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!
- * - Already wrong with dv.
*/
#include "platform.h"
#include "gnunet_client_lib.h"
#define DEBUG_PING_PONG GNUNET_NO
+#define SIGN_USELESS GNUNET_NO
+
+#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
+#define MAX_PENDING (128 * 1024)
/**
* Size of the per-transport blacklist hash maps.
* 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.
- */
- size_t addrlen;
-
/**
* The address.
*/
*/
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
/**
- * 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;
};
/**
* 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;
};
};
+/**
+ * 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 Session *session;
/**
- * Length of addr.
+ * Challenge number we used.
*/
- size_t addrlen;
+ uint32_t challenge;
/**
- * Challenge number we used.
+ * Length of addr.
*/
- uint32_t challenge;
+ uint16_t addrlen;
};
*/
int hello_known;
+ /**
+ * Number of validation entries currently referring to this
+ * CHVC.
+ */
+ unsigned int ve_count;
};
*/
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 TransportPlugin *plugins;
-/**
- * Our server.
- */
-static struct GNUNET_SERVER_Handle *server;
-
/**
* Handle to peerinfo service.
*/
*/
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
if (GNUNET_CONTAINER_multihashmap_contains(plugin->blacklist, &peer->hashPubKey) == GNUNET_YES)
{
#if DEBUG_BLACKLIST
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
_("Peer `%s:%s' is blacklisted!\n"),
plugin->short_name, GNUNET_i2s (peer));
#endif
"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))
}
if (frstat.st_size == 0)
{
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+#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))
{
}
entries_found = 0;
pos = 0;
- while ((pos < frstat.st_size) && isspace (data[pos]))
+ 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 (data[colon_pos]))
+ while ((colon_pos < frstat.st_size) && (data[colon_pos] != ':') && !isspace ( (unsigned char) data[colon_pos]))
colon_pos++;
if (colon_pos >= frstat.st_size)
return;
}
- if (isspace(data[colon_pos]))
+ 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 (data[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))
+ 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"),
return;
}
- transport_name = GNUNET_malloc(tsize);
+ 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 (enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1]))
+ 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 (data[pos])))
+ while ((pos < frstat.st_size) && (!isspace ( (unsigned char) data[pos])))
pos++;
GNUNET_free_non_null(transport_name);
continue;
{
entries_found++;
add_peer_to_blacklist (&pid,
- transport_name);
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- _("Found blacklisted peer `%s:%s' in configuration\n"),
- transport_name, GNUNET_i2s (&pid));
+ transport_name);
}
else
{
}
pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded);
GNUNET_free_non_null(transport_name);
- while ((pos < frstat.st_size) && isspace (data[pos]))
+ while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
pos++;
}
GNUNET_free (data);
}
+/**
+ * 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'
{
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;
}
{
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);
{
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,
if (addresses->addr != NULL)
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),
+ a2s (head->plugin->short_name,
+ addresses->addr,
+ addresses->addrlen),
GNUNET_i2s (&neighbour->id),
addresses->connected,
addresses->in_transmit,
{
#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Best address found has latency of %llu ms.\n",
+ "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.value);
#endif
}
mq->message_buf_size,
GNUNET_i2s (&neighbour->id),
(mq->specific_address->addr != NULL)
- ? GNUNET_a2s (mq->specific_address->addr,
- mq->specific_address->addrlen)
+ ? a2s (mq->plugin->short_name,
+ mq->specific_address->addr,
+ mq->specific_address->addrlen)
: "<inbound>",
rl->plugin->short_name);
#endif
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;
}
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 (peerinfo, our_hello);
npos = neighbours;
while (npos != NULL)
plugin_env_notify_address (void *cls,
const char *name,
const void *addr,
- size_t addrlen,
+ uint16_t addrlen,
struct GNUNET_TIME_Relative expires)
{
struct TransportPlugin *p = cls;
}
al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
- al->addr = &al[1];
al->next = p->addresses;
p->addresses = al;
al->expires = abex;
const char *tname,
struct Session *session,
const char *addr,
- size_t addrlen)
+ uint16_t addrlen)
{
struct ReadyList *head;
struct ForeignAddressList *pos;
const char *tname,
struct Session *session,
const char *addr,
- size_t addrlen)
+ uint16_t addrlen)
{
struct ReadyList *head;
struct ForeignAddressList *ret;
struct Session *session;
/**
- * Length of addr.
+ * Set to GNUNET_YES if the address exists.
*/
- size_t addrlen;
+ int exists;
/**
- * Set to GNUNET_YES if the address exists.
+ * Length of addr.
*/
- int exists;
+ uint16_t addrlen;
+
};
}
+
+/**
+ * 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 (sched, 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;
+}
+
+
/**
* HELLO validation cleanup task (validation failed).
*
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);
try = GNUNET_NO;
{
#if DEBUG_TRANSPORT
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);
* @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;
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"),
if (do_hello)
{
n->piter = GNUNET_PEERINFO_iterate (peerinfo, peer,
- 0, GNUNET_TIME_UNIT_FOREVER_REL,
+ GNUNET_TIME_UNIT_FOREVER_REL,
&add_hello_for_peer, n);
transmit_to_peer (NULL, NULL, 0,
HELLO_ADDRESS_EXPIRATION,
/**
- * 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
struct CheckAddressExistsClosure caec;
char * message_buf;
uint16_t hello_size;
+ size_t slen;
size_t tsize;
peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Some validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
(peer_address->addr != NULL)
- ? GNUNET_a2s (peer_address->addr,
- peer_address->addrlen)
+ ? a2s (tp->short_name,
+ peer_address->addr,
+ peer_address->addrlen)
: "<inbound>",
tp->short_name,
GNUNET_i2s (&neighbour->id));
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);
+ UINT_MAX);
va->send_time = GNUNET_TIME_absolute_get();
va->session = peer_address->session;
if (peer_address->addr != NULL)
GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
hello_size = GNUNET_HELLO_size(our_hello);
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->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",
+ "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s'\n",
(peer_address->addr != NULL)
- ? GNUNET_a2s (peer_address->addr,
- peer_address->addrlen)
+ ? 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
GNUNET_STATISTICS_update (stats,
gettext_noop ("# PING messages sent for re-validation"),
}
#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Received message of type %u from `%4s', sending to all clients.\n",
+ "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,
im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
im->latency = GNUNET_TIME_relative_hton (n->latency);
im->peer = n->id;
+ im->distance = ntohl(n->distance);
memcpy (&im[1], message, msize);
cpos = clients;
while (cpos != NULL)
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;
- if (GNUNET_OK !=
- GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PING,
- &pong->purpose,
- &pong->signature,
- &ve->publicKey))
+ ps = ntohs (pong->header.size);
+ if (ps < sizeof (struct TransportPongMessage))
{
GNUNET_break_op (0);
- return GNUNET_YES;
+ return GNUNET_NO;
}
-
+ addr = (const char*) &pong[1];
+ slen = strlen (ve->transport_name) + 1;
+ if ( (ps - sizeof (struct TransportPongMessage) != ve->addrlen + 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) + ve->addrlen + slen) )
+ 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),
- (ve->addr != NULL)
- ? GNUNET_a2s ((const struct sockaddr *) ve->addr,
- ve->addrlen)
- : "<inbound>",
- 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 (ve->addrlen != 0)
+ return GNUNET_YES; /* different entry, keep trying */
+ if ( (0 != memcmp (&pong->pid,
+ &my_identity,
+ sizeof (struct GNUNET_PeerIdentity))) ||
+ (ve->addrlen != 0) )
+ {
+ GNUNET_break_op (0);
+ return GNUNET_NO;
+ }
+ 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_INFO,
+ _("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)).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,
n->latency = fal->latency;
else
n->latency.value = (fal->latency.value + n->latency.value) / 2;
+
n->distance = fal->distance;
if (GNUNET_NO == n->received_pong)
{
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);
-#endif
}
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_free (va->transport_name);
- GNUNET_free (va);
+ GNUNET_break (GNUNET_OK ==
+ GNUNET_CONTAINER_multihashmap_remove (validation_map,
+ &id.hashPubKey,
+ va));
+ abort_validation (NULL, NULL, va);
return;
}
neighbour->publicKey = va->publicKey;
"Failed to add peer `%4s' for plugin `%s'\n",
GNUNET_i2s (&neighbour->id),
va->transport_name);
- GNUNET_free (va->transport_name);
- GNUNET_free (va);
+ 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);
- tsize = sizeof(struct TransportPingMessage) + hello_size;
+ 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));
+ 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",
- GNUNET_a2s ((const void*) &va[1], va->addrlen),
+ (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));
+ "PING", sizeof (struct TransportPingMessage) + va->addrlen + slen);
#endif
+
GNUNET_STATISTICS_update (stats,
gettext_noop ("# PING messages sent for initial validation"),
1,
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 OwnAddressList *oal;
GNUNET_assert (addr != NULL);
+
GNUNET_STATISTICS_update (stats,
gettext_noop ("# peer addresses scheduled for validation"),
1,
while (NULL != oal)
{
if ( (oal->addrlen == addrlen) &&
- (0 == memcmp (oal->addr,
+ (0 == memcmp (&oal[1],
addr,
addrlen)) )
{
{
#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- _("Attempted to validate blacklisted peer `%s' using `%s'!\n"), GNUNET_i2s(&id), tname);
+ "Attempted to validate blacklisted peer `%s' using `%s'!\n",
+ GNUNET_i2s(&id),
+ tname);
#endif
return GNUNET_OK;
}
#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
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);
+ UINT_MAX);
va->send_time = GNUNET_TIME_absolute_get();
va->addr = (const void*) &va[1];
memcpy (&va[1], addr, addrlen);
* @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)
{
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
GNUNET_free (plain_hello);
#if DEBUG_TRANSPORT
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
1,
GNUNET_NO);
}
- GNUNET_free (chvc);
+ chvc->ve_count--;
+ if (chvc->ve_count == 0)
+ {
+ GNUNET_CONTAINER_DLL_remove (chvc_head,
+ chvc_tail,
+ chvc);
+ GNUNET_free (chvc);
+ }
return;
}
if (h == NULL)
return;
#if DEBUG_TRANSPORT
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
const struct GNUNET_HELLO_Message *hello;
struct CheckHelloValidatedContext *chvc;
struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
-
+#if DEBUG_TRANSPORT_HELLO
+ char *my_id;
+#endif
hsize = ntohs (message->size);
if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
(hsize < sizeof (struct GNUNET_MessageHeader)))
gettext_noop ("# HELLOs received for validation"),
1,
GNUNET_NO);
+
/* first, check if load is too high */
if (GNUNET_SCHEDULER_get_load (sched,
GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
gettext_noop ("# HELLOs ignored due to high load"),
1,
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 (0 == memcmp (&my_identity,
&target,
sizeof (struct GNUNET_PeerIdentity)))
GNUNET_NO);
return GNUNET_OK;
}
-#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));
+ chvc = chvc_head;
+ while (NULL != chvc)
+ {
+ if (GNUNET_HELLO_equals (hello,
+ chvc->hello,
+ GNUNET_TIME_absolute_get ()).value > 0)
+ {
+#if DEBUG_TRANSPORT_HELLO
+ 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 DEBUG_TRANSPORT_HELLO
+ 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);
+ }
#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,
(continuation will then schedule actual validation) */
chvc->piter = GNUNET_PEERINFO_iterate (peerinfo,
&target,
- 0,
HELLO_VERIFICATION_TIMEOUT,
&check_hello_validated, chvc);
return GNUNET_OK;
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;
"Processing `%s' from `%s'\n",
"PING",
(sender_address != NULL)
- ? GNUNET_a2s ((const struct sockaddr *)sender_address,
- sender_address_len)
+ ? 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_PING);
- pong->challenge = ping->challenge;
- pong->addrlen = htons(sender_address_len);
- memcpy(&pong->signer,
- &my_public_key,
- sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
- if (sender_address != NULL)
- 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).value < PONG_SIGNATURE_LIFETIME.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).value < PONG_SIGNATURE_LIFETIME.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);
GNUNET_assert (n != NULL);
/* first try reliable response transmission */
static struct GNUNET_TIME_Relative
plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
const struct GNUNET_MessageHeader *message,
- unsigned int distance,
+ uint32_t distance,
struct Session *session,
const char *sender_address,
- size_t sender_address_len)
+ uint16_t sender_address_len)
{
struct TransportPlugin *plugin = cls;
struct ReadyList *service_context;
}
#if DEBUG_PING_PONG
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Received message of type %u from `%4s', sending to all clients.\n",
- ntohs (message->type), GNUNET_i2s (peer));
+ "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))
{
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);
GNUNET_NO);
obm = (const struct OutboundMessage *) message;
obmm = (const struct GNUNET_MessageHeader *) &obm[1];
- msize = ntohs (obmm->size);
+ msize = size - sizeof (struct OutboundMessage);
#if DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Received `%s' request from client with target `%4s' and message of type %u and size %u\n",
ntohs (obmm->type),
msize);
#endif
- if (size != msize + sizeof (struct OutboundMessage))
- {
- GNUNET_break (0);
- GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
- return;
- }
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,
/**
- * 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*')
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)
&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},
- {&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}
-};
-
/**
* Setup the environment for this plugin.
}
-/**
- * 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.
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);
+ 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);
*
* @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, 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},
+ {&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;
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... */
int
main (int argc, char *const *argv)
{
+ a2s (NULL, NULL, 0); /* make compiler happy */
return (GNUNET_OK ==
GNUNET_SERVICE_run (argc,
argv,