/**
* ID of the connection.
*/
- struct GNUNET_HashCode id;
+ struct GNUNET_MeshHash id;
/**
* State of the connection.
/**
- * Get string description for tunnel state.
+ * Resets the connection timeout task, some other message has done the
+ * task's job.
+ * - For the first peer on the direction this means to send
+ * a keepalive or a path confirmation message (either create or ACK).
+ * - For all other peers, this means to destroy the connection,
+ * due to lack of activity.
+ * Starts the timeout if no timeout was running (connection just created).
+ *
+ * @param c Connection whose timeout to reset.
+ * @param fwd Is this forward?
+ */
+static void
+connection_reset_timeout (struct MeshConnection *c, int fwd);
+
+
+/**
+ * Get string description for tunnel state. Reentrant.
*
* @param s Tunnel state.
*
* @param cid Connection ID.
*/
static struct MeshConnection *
-connection_get (const struct GNUNET_HashCode *cid)
+connection_get (const struct GNUNET_MeshHash *cid)
{
- return GNUNET_CONTAINER_multihashmap_get (connections, cid);
+ return GNUNET_CONTAINER_multihashmap_get (connections, GM_h2hc (cid));
}
enum MeshConnectionState state)
{
LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Connection %s state was %s\n",
- GMC_2s (c), GMC_state2s (c->state));
+ "Connection %s state %s -> %s\n",
+ GMC_2s (c), GMC_state2s (c->state), GMC_state2s (state));
if (MESH_CONNECTION_DESTROYED == c->state)
{
LOG (GNUNET_ERROR_TYPE_DEBUG, "state not changing anymore\n");
return;
}
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Connection %s state is now %s\n",
- GMC_2s (c), GMC_state2s (state));
c->state = state;
if (MESH_CONNECTION_READY == state)
c->create_retry = 1;
fc->last_pid_sent);
}
GMC_send_ack (c, fwd, GNUNET_NO);
+ connection_reset_timeout (c, fwd);
break;
case GNUNET_MESSAGE_TYPE_MESH_POLL:
struct MeshTunnel3 *t;
t = connection->t;
- LOG (GNUNET_ERROR_TYPE_INFO, "Send %s ACK on connection %s\n",
+ LOG (GNUNET_ERROR_TYPE_INFO, "=> {%18s ACK} on connection %s\n",
GM_f2s (!fwd), GMC_2s (connection));
GMP_queue_add (get_hop (connection, fwd), NULL,
GNUNET_MESSAGE_TYPE_MESH_CONNECTION_ACK,
* @param peer Peer to notify (neighbor who sent the connection).
*/
static void
-send_broken2 (struct GNUNET_HashCode *connection_id,
+send_broken2 (struct GNUNET_MeshHash *connection_id,
const struct GNUNET_PeerIdentity *id1,
const struct GNUNET_PeerIdentity *id2,
GNUNET_PEER_Id peer_id)
struct GNUNET_MESH_ConnectionBroken *msg;
struct MeshPeer *neighbor;
- LOG (GNUNET_ERROR_TYPE_INFO,
- "Send BROKEN on unknown connection %s\n", GNUNET_h2s (connection_id));
+ LOG (GNUNET_ERROR_TYPE_INFO, "=> BROKEN on unknown connection %s\n",
+ GNUNET_h2s (GM_h2hc (connection_id)));
msg = GNUNET_new (struct GNUNET_MESH_ConnectionBroken);
msg->header.size = htons (sizeof (struct GNUNET_MESH_ConnectionBroken));
msg->peer2 = *id2;
neighbor = GMP_get_short (peer_id);
GMP_queue_add (neighbor, msg,
- GNUNET_MESSAGE_TYPE_MESH_ENCRYPTED,
+ GNUNET_MESSAGE_TYPE_MESH_CONNECTION_BROKEN,
sizeof (struct GNUNET_MESH_ConnectionBroken),
NULL, GNUNET_SYSERR, /* connection, fwd */
NULL, NULL); /* continuation */
* @param fwd Is this a FWD keepalive? (owner -> dest).
*/
static void
-connection_keepalive (struct MeshConnection *c, int fwd)
+send_connection_keepalive (struct MeshConnection *c, int fwd)
{
- struct GNUNET_MESH_ConnectionKeepAlive *msg;
- size_t size = sizeof (struct GNUNET_MESH_ConnectionKeepAlive);
- char cbuf[size];
+ struct GNUNET_MessageHeader msg;
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "sending %s keepalive for connection %s]\n",
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ "keepalive %s for connection %s\n",
GM_f2s (fwd), GMC_2s (c));
+ GNUNET_STATISTICS_update (stats, "# keepalives sent", 1, GNUNET_NO);
- msg = (struct GNUNET_MESH_ConnectionKeepAlive *) cbuf;
- msg->header.size = htons (size);
- msg->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_KEEPALIVE);
- msg->cid = c->id;
- msg->reserved = htonl (0);
+ GNUNET_assert (NULL != c->t);
+ msg.size = htons (sizeof (msg));
+ msg.type = htons (GNUNET_MESSAGE_TYPE_MESH_KEEPALIVE);
- GMC_send_prebuilt_message (&msg->header, c, fwd, GNUNET_YES, NULL, NULL);
+ GNUNET_assert (NULL ==
+ GMT_send_prebuilt_message (&msg, c->t, c,
+ GNUNET_NO, NULL, NULL));
}
connection_recreate (c, fwd);
break;
case MESH_CONNECTION_READY:
- connection_keepalive (c, fwd);
+ send_connection_keepalive (c, fwd);
break;
default:
break;
}
+
/**
- * Keep the connection alive in the FWD direction.
+ * Keep the connection alive.
*
- * @param cls Closure (connection to keepalive).
- * @param tc TaskContext.
+ * @param c Connection to keep alive.
+ * @param fwd Direction.
+ * @param shutdown Are we shutting down? (Don't send traffic)
+ * Non-zero value for true, not necessarily GNUNET_YES.
*/
static void
-connection_fwd_keepalive (void *cls,
- const struct GNUNET_SCHEDULER_TaskContext *tc)
+connection_keepalive (struct MeshConnection *c, int fwd, int shutdown)
{
- struct MeshConnection *c = cls;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "%s keepalive for %s\n",
+ GM_f2s (fwd), GMC_2s (c));
- LOG (GNUNET_ERROR_TYPE_DEBUG, "FWD keepalive for %s\n", GMC_2s (c));
- c->fwd_maintenance_task = GNUNET_SCHEDULER_NO_TASK;
- if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+ if (fwd)
+ c->fwd_maintenance_task = GNUNET_SCHEDULER_NO_TASK;
+ else
+ c->bck_maintenance_task = GNUNET_SCHEDULER_NO_TASK;
+
+ if (GNUNET_NO != shutdown)
return;
- connection_maintain (c, GNUNET_YES);
+ connection_maintain (c, fwd);
/* Next execution will be scheduled by message_sent */
}
/**
- * Keep the connection alive in the BCK direction.
- *
- * TODO refactor and merge with connection_fwd_keepalive.
+ * Keep the connection alive in the FWD direction.
*
* @param cls Closure (connection to keepalive).
* @param tc TaskContext.
*/
static void
-connection_bck_keepalive (void *cls,
+connection_fwd_keepalive (void *cls,
const struct GNUNET_SCHEDULER_TaskContext *tc)
{
- struct MeshConnection *c = cls;
-
- c->bck_maintenance_task = GNUNET_SCHEDULER_NO_TASK;
- if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
- return;
+ connection_keepalive ((struct MeshConnection *) cls,
+ GNUNET_YES,
+ tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN);
+}
- connection_maintain (c, GNUNET_NO);
- /* Next execution will be scheduled by message_sent */
+/**
+ * Keep the connection alive in the BCK direction.
+ *
+ * @param cls Closure (connection to keepalive).
+ * @param tc TaskContext.
+ */
+static void
+connection_bck_keepalive (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ connection_keepalive ((struct MeshConnection *) cls,
+ GNUNET_NO,
+ tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN);
}
/* Schedule the task */
*task_id = GNUNET_SCHEDULER_add_delayed (delay, keepalive_task, c);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "next keepalive in %s\n",
+ GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
}
static void
connection_reset_timeout (struct MeshConnection *c, int fwd)
{
- GNUNET_SCHEDULER_TaskIdentifier *ti;
- GNUNET_SCHEDULER_Task f;
-
- ti = fwd ? &c->fwd_maintenance_task : &c->bck_maintenance_task;
-
LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection %s reset timeout\n", GM_f2s (fwd));
- if (GNUNET_SCHEDULER_NO_TASK != *ti)
- GNUNET_SCHEDULER_cancel (*ti);
-
if (GMC_is_origin (c, fwd)) /* Startpoint */
{
- f = fwd ? &connection_fwd_keepalive : &connection_bck_keepalive;
- *ti = GNUNET_SCHEDULER_add_delayed (refresh_connection_time, f, c);
+ schedule_next_keepalive (c, fwd);
}
else /* Relay, endpoint. */
{
struct GNUNET_TIME_Relative delay;
+ GNUNET_SCHEDULER_TaskIdentifier *ti;
+ GNUNET_SCHEDULER_Task f;
+
+ ti = fwd ? &c->fwd_maintenance_task : &c->bck_maintenance_task;
+ if (GNUNET_SCHEDULER_NO_TASK != *ti)
+ GNUNET_SCHEDULER_cancel (*ti);
delay = GNUNET_TIME_relative_multiply (refresh_connection_time, 4);
f = fwd ? &connection_fwd_timeout : &connection_bck_timeout;
*ti = GNUNET_SCHEDULER_add_delayed (delay, f, c);
if (path->peers[j] == shortid)
{
LOG (GNUNET_ERROR_TYPE_DEBUG, " already exists at pos %u\n", j);
- offset += i - j;
- LOG (GNUNET_ERROR_TYPE_DEBUG, " offset now\n", offset);
+ offset = i - j;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " offset now %u\n", offset);
GNUNET_PEER_change_rc (shortid, -1);
}
}
LOG (GNUNET_ERROR_TYPE_DEBUG, " storing at %u\n", i - offset);
path->peers[i - offset] = shortid;
- if (path->peers[i] == myid)
- *own_pos = i;
+ if (path->peers[i - offset] == myid)
+ *own_pos = i - offset;
}
path->length -= offset;
static void
log_message (const struct GNUNET_MessageHeader *message,
const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_HashCode *hash)
+ const struct GNUNET_MeshHash *hash)
{
LOG (GNUNET_ERROR_TYPE_INFO, "<- %s on connection %s from %s\n",
- GM_m2s (ntohs (message->type)), GNUNET_h2s (hash), GNUNET_i2s (peer));
+ GM_m2s (ntohs (message->type)), GNUNET_h2s (GM_h2hc (hash)),
+ GNUNET_i2s (peer));
}
/******************************************************************************/
{
struct GNUNET_MESH_ConnectionCreate *msg;
struct GNUNET_PeerIdentity *id;
- struct GNUNET_HashCode *cid;
+ struct GNUNET_MeshHash *cid;
struct MeshPeerPath *path;
struct MeshPeer *dest_peer;
struct MeshPeer *orig_peer;
orig_peer = GMP_get (&id[0]);
/* Is it a connection to us? */
- if (c->own_pos == size - 1)
+ if (c->own_pos == path->length - 1)
{
LOG (GNUNET_ERROR_TYPE_DEBUG, " It's for us!\n");
GMP_add_path_to_origin (orig_peer, path_duplicate (path), GNUNET_YES);
/**
- * Core handler for notifications of broken paths
+ * Core handler for notifications of broken connections.
*
* @param cls Closure (unused).
* @param id Peer identity of sending neighbor.
c = connection_get (&msg->cid);
if (NULL == c)
{
- GNUNET_break_op (0);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " duplicate CONNECTION_BROKEN\n");
return GNUNET_OK;
}
fwd = is_fwd (c, id);
if (GMC_is_terminal (c, fwd))
{
+ struct GNUNET_MessageHeader *out_msg;
+ struct MeshPeer *neighbor;
+ struct MeshPeer *endpoint;
+
+ neighbor = get_hop (c, !fwd);
+ endpoint = GMP_get_short (c->path->peers[c->path->length - 1]);
path_invalidate (c->path);
- if (0 < c->pending_messages)
- c->destroy = GNUNET_YES;
- else
- GMC_destroy (c);
+ GMP_notify_broken_link (endpoint, &msg->peer1, &msg->peer2);
+ c->state = MESH_CONNECTION_DESTROYED;
+ while (NULL != (out_msg = GMP_connection_pop (neighbor, c)))
+ {
+ GNUNET_assert (NULL ==
+ GMT_send_prebuilt_message (out_msg, c->t, NULL, GNUNET_YES,
+ NULL, NULL));
+ }
+
+ GMC_destroy (c);
}
else
{
if (NULL == c)
{
GNUNET_STATISTICS_update (stats, "# unknown connection", 1, GNUNET_NO);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "WARNING enc on unknown connection %s\n",
- GNUNET_h2s (&msg->cid));
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "enc on unknown connection %s\n",
+ GNUNET_h2s (GM_h2hc (&msg->cid)));
return GNUNET_OK;
}
/* Check size */
size = ntohs (msg->header.size);
if (size <
- sizeof (struct GNUNET_MESH_Encrypted) +
+ sizeof (struct GNUNET_MESH_KX) +
sizeof (struct GNUNET_MessageHeader))
{
GNUNET_break_op (0);
if (NULL == c)
{
GNUNET_STATISTICS_update (stats, "# unknown connection", 1, GNUNET_NO);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "WARNING kx on unknown connection %s\n",
- GNUNET_h2s (&msg->cid));
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "kx on unknown connection %s\n",
+ GNUNET_h2s (GM_h2hc (&msg->cid)));
return GNUNET_OK;
}
LOG (GNUNET_ERROR_TYPE_DEBUG, " on connection %s\n", GMC_2s (c));
GNUNET_NO);
LOG (GNUNET_ERROR_TYPE_DEBUG,
"WARNING POLL message on unknown connection %s!\n",
- GNUNET_h2s (&msg->cid));
+ GNUNET_h2s (GM_h2hc (&msg->cid)));
return GNUNET_OK;
}
}
-/**
- * Core handler for mesh keepalives.
- *
- * @param cls closure
- * @param message message
- * @param peer peer identity this notification is about
- * @return GNUNET_OK to keep the connection open,
- * GNUNET_SYSERR to close it (signal serious error)
- *
- * TODO: Check who we got this from, to validate route.
- */
-int
-GMC_handle_keepalive (void *cls, const struct GNUNET_PeerIdentity *peer,
- const struct GNUNET_MessageHeader *message)
-{
- struct GNUNET_MESH_ConnectionKeepAlive *msg;
- struct MeshConnection *c;
- struct MeshPeer *neighbor;
- GNUNET_PEER_Id peer_id;
- int fwd;
-
- msg = (struct GNUNET_MESH_ConnectionKeepAlive *) message;
- log_message (message, peer, &msg->cid);
- c = connection_get (&msg->cid);
- if (NULL == c)
- {
- GNUNET_STATISTICS_update (stats, "# keepalive on unknown connection", 1,
- GNUNET_NO);
- return GNUNET_OK;
- }
-
- /* Check if origin is as expected TODO refactor and reuse */
- peer_id = GNUNET_PEER_search (peer);
- neighbor = get_prev_hop (c);
- if (peer_id == GMP_get_short_id (neighbor))
- {
- fwd = GNUNET_YES;
- }
- else
- {
- neighbor = get_next_hop (c);
- if (peer_id == GMP_get_short_id (neighbor))
- {
- fwd = GNUNET_NO;
- }
- else
- {
- GNUNET_break_op (0);
- return GNUNET_OK;
- }
- }
-
- connection_change_state (c, MESH_CONNECTION_READY);
- connection_reset_timeout (c, fwd);
-
- if (GMC_is_terminal (c, fwd))
- return GNUNET_OK;
-
- GNUNET_STATISTICS_update (stats, "# keepalives forwarded", 1, GNUNET_NO);
- GMC_send_prebuilt_message (message, c, fwd, GNUNET_YES, NULL, NULL);
-
- return GNUNET_OK;
-}
-
-
/**
* Send an ACK on the appropriate connection/channel, depending on
* the direction and the position of the peer.
return;
}
create_connection_time = GNUNET_TIME_UNIT_SECONDS;
- connections = GNUNET_CONTAINER_multihashmap_create (1024, GNUNET_YES);
+ connections = GNUNET_CONTAINER_multihashmap_create (1024, GNUNET_NO);
}
struct MeshConnection *
-GMC_new (const struct GNUNET_HashCode *cid,
+GMC_new (const struct GNUNET_MeshHash *cid,
struct MeshTunnel3 *t,
struct MeshPeerPath *p,
unsigned int own_pos)
c->id = *cid;
GNUNET_assert (GNUNET_OK ==
GNUNET_CONTAINER_multihashmap_put (connections,
- &c->id, c,
+ GMC_get_h (c), c,
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
fc_init (&c->fwd_fc);
fc_init (&c->bck_fc);
}
GNUNET_break (GNUNET_YES ==
- GNUNET_CONTAINER_multihashmap_remove (connections, &c->id, c));
+ GNUNET_CONTAINER_multihashmap_remove (connections,
+ GMC_get_h (c), c));
GNUNET_STATISTICS_update (stats, "# connections", -1, GNUNET_NO);
GNUNET_free (c);
*
* @return ID of the connection.
*/
-const struct GNUNET_HashCode *
+const struct GNUNET_MeshHash *
GMC_get_id (const struct MeshConnection *c)
{
return &c->id;
}
+/**
+ * Get the connection ID.
+ *
+ * @param c Connection to get the ID from.
+ *
+ * @return ID of the connection.
+ */
+const struct GNUNET_HashCode *
+GMC_get_h (const struct MeshConnection *c)
+{
+ return GM_h2hc (&c->id);
+}
+
+
/**
* Get the connection path.
*
{
struct MeshFlowControl *fc;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " checking sendability of %s traffic on %s\n",
+ GM_f2s (fwd), GMC_2s (c));
if (NULL == c)
{
GNUNET_break (0);
return GNUNET_YES;
}
fc = fwd ? &c->fwd_fc : &c->bck_fc;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " last ack recv: %u, last pid sent: %u\n",
+ fc->last_ack_recv, fc->last_pid_sent);
if (GM_is_pid_bigger (fc->last_ack_recv, fc->last_pid_sent))
return GNUNET_YES;
return GNUNET_NO;
case GNUNET_MESSAGE_TYPE_MESH_CONNECTION_DESTROY:
dmsg = (struct GNUNET_MESH_ConnectionDestroy *) data;
dmsg->cid = c->id;
- dmsg->reserved = 0;
break;
case GNUNET_MESSAGE_TYPE_MESH_CONNECTION_BROKEN:
bmsg = (struct GNUNET_MESH_ConnectionBroken *) data;
bmsg->cid = c->id;
- bmsg->reserved = 0;
break;
+ case GNUNET_MESSAGE_TYPE_MESH_KEEPALIVE:
+ GNUNET_break (0);
+ /* falltrough */
case GNUNET_MESSAGE_TYPE_MESH_CONNECTION_CREATE:
case GNUNET_MESSAGE_TYPE_MESH_CONNECTION_ACK:
- case GNUNET_MESSAGE_TYPE_MESH_KEEPALIVE:
break;
default:
size = sizeof (struct GNUNET_MESH_ConnectionCreate);
size += connection->path->length * sizeof (struct GNUNET_PeerIdentity);
- LOG (GNUNET_ERROR_TYPE_INFO, "Send %s (%u bytes) on connection %s\n",
+ LOG (GNUNET_ERROR_TYPE_INFO, "=> %s on connection %s (%u bytes)\n",
GM_m2s (GNUNET_MESSAGE_TYPE_MESH_CONNECTION_CREATE),
- size, GMC_2s (connection));
+ GMC_2s (connection), size);
LOG (GNUNET_ERROR_TYPE_DEBUG, " C_P+ %p %u (create)\n",
connection, connection->pending_messages);
connection->pending_messages++;
{
static char buf[128];
- sprintf (buf, "%s (->%s)", GNUNET_h2s (&c->id), GMT_2s (c->t));
+ sprintf (buf, "%s (->%s)", GNUNET_h2s (GM_h2hc (GMC_get_id(c))), GMT_2s (c->t));
return buf;
}
- return GNUNET_h2s (&c->id);
+ return GNUNET_h2s (GM_h2hc (&c->id));
}