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
#define DEBUG_PING_PONG GNUNET_NO
-#define SIGN_USELESS GNUNET_NO
-
-#define DEBUG_TRANSPORT_HELLO GNUNET_YES
+#define DEBUG_TRANSPORT_HELLO GNUNET_NO
/**
* Should we do some additional checks (to validate behavior
}
+/**
+ * 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
session);
nl = find_neighbour (peer);
if (nl == NULL)
- return;
+ return; /* was never marked as connected */
rl = nl->plugins;
while (rl != NULL)
{
rl = rl->next;
}
if (rl == NULL)
- return;
+ return; /* was never marked as connected */
prev = NULL;
pos = rl->addresses;
while ( (pos != NULL) &&
pos = pos->next;
}
if (pos == NULL)
- return;
+ return; /* was never marked as connected */
pos->session = NULL;
if (pos->addrlen != 0)
- return;
+ {
+ 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
}
GNUNET_free (pos);
if (nl->received_pong == GNUNET_NO)
- return; /* nothing to do */
+ return; /* nothing to do, never connected... */
/* check if we have any validated addresses left */
pos = rl->addresses;
while (pos != NULL)
{
if (pos->validated)
- return;
+ {
+ try_fast_reconnect (p, nl);
+ return;
+ }
pos = pos->next;
}
/* no valid addresses left, signal disconnect! */
- disconnect_neighbour (nl, GNUNET_NO);
+
+ 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);
}
* @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;
}
&neighbour_timeout_task, n);
if (do_hello)
{
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# peerinfo 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,
- 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,
struct NeighbourList * orig = cls;
if (n == NULL)
- disconnect_neighbour (orig, GNUNET_NO);
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&orig->id),
+ "confirm_or_drop_neighboUr");
+ disconnect_neighbour (orig, GNUNET_NO);
+ }
}
slen = strlen (tp->short_name) + 1;
tsize += slen + peer_address->addrlen;
}
+ else
+ {
+ slen = 0; /* make gcc happy */
+ }
message_buf = GNUNET_malloc(tsize);
ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
ping.challenge = htonl(va->challenge);
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,
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Received message of type %u and size %u from `%4s', sending to all clients.\n",
ntohs (message->type),
ntohs (message->size),
addr = (const char*) &pong[1];
slen = strlen (ve->transport_name) + 1;
if ( (ps - sizeof (struct TransportPongMessage) != ve->addrlen + slen) ||
- (ve->challenge != challenge) ||
+ (ve->challenge != challenge) ||
(addr[slen-1] != '\0') ||
(0 != strcmp (addr, ve->transport_name)) ||
(ntohl (pong->purpose.size)
sizeof (uint32_t) +
sizeof (struct GNUNET_TIME_AbsoluteNBO) +
sizeof (struct GNUNET_PeerIdentity) + ve->addrlen + slen) )
- return GNUNET_YES;
+ {
+ return GNUNET_YES;
+ }
+
alen = ps - sizeof (struct TransportPongMessage) - slen;
switch (ntohl (pong->purpose.purpose))
{
(0 != memcmp (&addr[slen],
ve->addr,
ve->addrlen)) )
- return GNUNET_YES; /* different entry, keep trying! */
+ {
+ 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 DEBUG_TRANSPORT
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
break;
case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING:
if (ve->addrlen != 0)
- return GNUNET_YES; /* different entry, keep trying */
+ {
+ return GNUNET_YES; /* different entry, keep trying */
+ }
if ( (0 != memcmp (&pong->pid,
&my_identity,
sizeof (struct GNUNET_PeerIdentity))) ||
}
if (oal == NULL)
{
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ 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],
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",
* @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;
if (GNUNET_NO == chvc->hello_known)
{
chvc);
/* finally, check if HELLO was previously validated
(continuation will then schedule actual validation) */
+ GNUNET_STATISTICS_update (stats,
+ gettext_noop ("# peerinfo 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;
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 */
uint16_t msize;
struct NeighbourList *n;
struct GNUNET_TIME_Relative ret;
-
if (is_blacklisted (peer, plugin))
return GNUNET_TIME_UNIT_FOREVER_REL;
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",
ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
if (ret.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__,
struct GNUNET_SERVER_Client *client,
const struct GNUNET_MessageHeader *message)
{
+ const struct StartMessage *start;
struct TransportClient *c;
struct ConnectInfoMessage cim;
struct NeighbourList *n;
+ 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;
GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
qsm->quota);
if (0 == ntohl (qsm->quota.value__))
- disconnect_neighbour (n, GNUNET_NO);
+ {
+ 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);
}
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;
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");
{
chvc_head = chvc->next;
if (chvc->piter != NULL)
- GNUNET_PEERINFO_iterate_cancel (chvc->piter);
+ {
+ 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);
{
static const struct GNUNET_SERVER_MessageHandler handlers[] = {
{&handle_start, NULL,
- GNUNET_MESSAGE_TYPE_TRANSPORT_START, 0},
+ GNUNET_MESSAGE_TYPE_TRANSPORT_START, sizeof (struct StartMessage)},
{&handle_hello, NULL,
GNUNET_MESSAGE_TYPE_HELLO, 0},
{&handle_send, NULL,