/**
* ID of the connection.
*/
- struct GNUNET_HashCode id;
+ struct GNUNET_MeshHash id;
/**
* State of the connection.
enum MeshConnectionState state;
/**
- * Path being used for the tunnel.
+ * Path being used for the tunnel. At the origin of the connection
+ * it's a pointer to the destination's path pool, otherwise just a copy.
*/
struct MeshPeerPath *path;
*/
GNUNET_SCHEDULER_TaskIdentifier bck_maintenance_task;
+ /**
+ * Queue handle for maintainance traffic. One handle for FWD and BCK since
+ * one peer never needs to maintain both directions (no loopback connections).
+ */
+ struct MeshPeerQueue *maintenance_q;
+
+ /**
+ * Counter to do exponential backoff when creating a connection (max 64).
+ */
+ unsigned short create_retry;
+
/**
* Pending message count.
*/
*/
struct MeshPeerQueue *q;
+ /**
+ * Was this a forced message? (Do not account for it)
+ */
+ int forced;
+
/**
* Continuation to call once sent.
*/
}
#endif
+
+/**
+ * Schedule next keepalive task, taking in consideration
+ * the connection state and number of retries.
+ *
+ * @param c Connection for which to schedule the next keepalive.
+ * @param fwd Direction for the next keepalive.
+ */
+static void
+schedule_next_keepalive (struct MeshConnection *c, int fwd);
+
+
+/**
+ * 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.
*
return "MESH_CONNECTION_ACK";
case MESH_CONNECTION_READY:
return "MESH_CONNECTION_READY";
+ case MESH_CONNECTION_DESTROYED:
+ return "MESH_CONNECTION_DESTROYED";
default:
return "MESH_CONNECTION_STATE_ERROR";
}
* @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));
}
LOG (GNUNET_ERROR_TYPE_DEBUG,
"Connection %s state was %s\n",
GMC_2s (c), GMC_state2s (c->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;
}
/* If origin, there is no connection to send ACKs. Wrong function! */
if (GMC_is_origin (c, fwd))
{
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "connection %s is origin in %s\n",
+ GMC_2s (c), GM_f2s (fwd));
GNUNET_break (0);
return;
}
next_fc = fwd ? &c->fwd_fc : &c->bck_fc;
prev_fc = fwd ? &c->bck_fc : &c->fwd_fc;
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "connection send %s ack on %s\n",
- fwd ? "FWD" : "BCK", GMC_2s (c));
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "connection send %s ack on %s\n",
+ GM_f2s (fwd), GMC_2s (c));
/* Check if we need to transmit the ACK. */
delta = prev_fc->last_ack_sent - prev_fc->last_pid_recv;
/* Check if message is already in queue */
if (NULL != prev_fc->ack_msg)
{
- if (GMC_is_pid_bigger (ack, prev_fc->last_ack_sent))
+ if (GM_is_pid_bigger (ack, prev_fc->last_ack_sent))
{
LOG (GNUNET_ERROR_TYPE_DEBUG, " canceling old ACK\n");
GMC_cancel (prev_fc->ack_msg);
msg.ack = htonl (ack);
msg.cid = c->id;
- prev_fc->ack_msg = GMC_send_prebuilt_message (&msg.header, c, !fwd,
+ prev_fc->ack_msg = GMC_send_prebuilt_message (&msg.header, c,
+ !fwd, GNUNET_YES,
&ack_sent, prev_fc);
}
* @param size Size of the message.
* @param wait Time spent waiting for core (only the time for THIS message)
*/
-static void
+static void
message_sent (void *cls,
struct MeshConnection *c, uint16_t type,
int fwd, size_t size,
struct MeshFlowControl *fc;
struct MeshConnectionQueue *q = cls;
double usecsperbyte;
+ int forced;
fc = fwd ? &c->fwd_fc : &c->bck_fc;
LOG (GNUNET_ERROR_TYPE_DEBUG,
"! sent %s %s\n",
- fwd ? "FWD" : "BCK",
- GNUNET_MESH_DEBUG_M2S (type));
+ GM_f2s (fwd),
+ GM_m2s (type));
LOG (GNUNET_ERROR_TYPE_DEBUG, "! C_P- %p %u\n", c, c->pending_messages);
if (NULL != q)
{
+ forced = q->forced;
if (NULL != q->cont)
{
LOG (GNUNET_ERROR_TYPE_DEBUG, "! calling cont\n");
}
GNUNET_free (q);
}
+ else if (type == GNUNET_MESSAGE_TYPE_MESH_ENCRYPTED)
+ {
+ /* If NULL == q and ENCRYPTED == type, message must have been ch_mngmnt */
+ forced = GNUNET_YES;
+ }
+ else
+ {
+ forced = GNUNET_NO;
+ }
c->pending_messages--;
if (GNUNET_YES == c->destroy && 0 == c->pending_messages)
{
/* Send ACK if needed, after accounting for sent ID in fc->queue_n */
switch (type)
{
+ case GNUNET_MESSAGE_TYPE_MESH_CONNECTION_CREATE:
+ case GNUNET_MESSAGE_TYPE_MESH_CONNECTION_ACK:
+ c->maintenance_q = NULL;
+ /* Don't trigger a keepalive for sent ACKs, only SYN and SYNACKs */
+ if (GNUNET_MESSAGE_TYPE_MESH_CONNECTION_CREATE == type || !fwd)
+ schedule_next_keepalive (c, fwd);
+ break;
+
case GNUNET_MESSAGE_TYPE_MESH_ENCRYPTED:
fc->last_pid_sent++;
LOG (GNUNET_ERROR_TYPE_DEBUG, "! Q_N- %p %u\n", fc, fc->queue_n);
- fc->queue_n--;
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "! accounting pid %u\n",
- fc->last_pid_sent);
+ if (GNUNET_NO == forced)
+ {
+ fc->queue_n--;
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "! accounting pid %u\n",
+ fc->last_pid_sent);
+ }
+ else
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "! forced, Q_N not accounting pid %u\n",
+ fc->last_pid_sent);
+ }
GMC_send_ack (c, fwd, GNUNET_NO);
+ connection_reset_timeout (c, fwd);
break;
case GNUNET_MESSAGE_TYPE_MESH_POLL:
{
GNUNET_PEER_Id id;
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Get prev hop, own pos %u\n", c->own_pos);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " get prev hop %s [%u/%u]\n",
+ GMC_2s (c), c->own_pos, c->path->length);
if (0 == c->own_pos || c->path->length < 2)
id = c->path->peers[0];
else
id = c->path->peers[c->own_pos - 1];
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " ID: %s (%u)\n",
+ GNUNET_i2s (GNUNET_PEER_resolve2 (id)), id);
+
return GMP_get_short (id);
}
{
GNUNET_PEER_Id id;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " get next hop %s [%u/%u]\n",
+ GMC_2s (c), c->own_pos, c->path->length);
if ((c->path->length - 1) == c->own_pos || c->path->length < 2)
id = c->path->peers[c->path->length - 1];
else
id = c->path->peers[c->own_pos + 1];
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " ID: %s (%u)\n",
+ GNUNET_i2s (GNUNET_PEER_resolve2 (id)), id);
+
return GMP_get_short (id);
}
* #GNUNET_NO for BCK.
* #GNUNET_SYSERR for errors.
*/
-static int
+static int
is_fwd (const struct MeshConnection *c,
const struct GNUNET_PeerIdentity *sender)
{
struct MeshTunnel3 *t;
t = connection->t;
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Send connection %s ACK\n",
- !fwd ? "FWD" : "BCK");
+ 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,
sizeof (struct GNUNET_MESH_ConnectionACK),
connection, fwd, &message_sent, NULL);
connection->pending_messages++;
- if (MESH_TUNNEL3_NEW == GMT_get_state (t))
- GMT_change_state (t, MESH_TUNNEL3_WAITING);
+ if (MESH_TUNNEL3_NEW == GMT_get_cstate (t))
+ GMT_change_cstate (t, MESH_TUNNEL3_WAITING);
if (MESH_CONNECTION_READY != connection->state)
connection_change_state (connection, MESH_CONNECTION_SENT);
}
msg.cid = c->id;
msg.peer1 = *id1;
msg.peer2 = *id2;
- GMC_send_prebuilt_message (&msg.header, c, fwd, NULL, NULL);
+ GMC_send_prebuilt_message (&msg.header, c, fwd, GNUNET_YES, NULL, NULL);
}
+/**
+ * Send a notification that a connection is broken, when a connection
+ * isn't even created.
+ *
+ * @param connection_id Connection ID.
+ * @param id1 Peer that has disconnected.
+ * @param id2 Peer that has disconnected.
+ * @param peer Peer to notify (neighbor who sent the connection).
+ */
+static void
+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, "=> 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->header.type = htons (GNUNET_MESSAGE_TYPE_MESH_CONNECTION_BROKEN);
+ msg->cid = *connection_id;
+ msg->peer1 = *id1;
+ msg->peer2 = *id2;
+ neighbor = GMP_get_short (peer_id);
+ GMP_queue_add (neighbor, msg,
+ GNUNET_MESSAGE_TYPE_MESH_ENCRYPTED,
+ sizeof (struct GNUNET_MESH_ConnectionBroken),
+ NULL, GNUNET_SYSERR, /* connection, fwd */
+ NULL, NULL); /* continuation */
+}
+
/**
* Send keepalive packets for a connection.
* @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];
- uint16_t type;
+ struct GNUNET_MessageHeader msg;
- type = fwd ? GNUNET_MESSAGE_TYPE_MESH_FWD_KEEPALIVE :
- GNUNET_MESSAGE_TYPE_MESH_BCK_KEEPALIVE;
+ 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);
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "sending %s keepalive for connection %s]\n",
- fwd ? "FWD" : "BCK", GMC_2s (c));
+ GNUNET_assert (NULL != c->t);
+ msg.size = htons (sizeof (msg));
+ msg.type = htons (GNUNET_MESSAGE_TYPE_MESH_KEEPALIVE);
- msg = (struct GNUNET_MESH_ConnectionKeepAlive *) cbuf;
- msg->header.size = htons (size);
- msg->header.type = htons (type);
- msg->cid = c->id;
-
- GMC_send_prebuilt_message (&msg->header, c, fwd, NULL, NULL);
+ GNUNET_assert (NULL ==
+ GMT_send_prebuilt_message (&msg, c->t, c,
+ GNUNET_NO, NULL, NULL));
}
static void
connection_maintain (struct MeshConnection *c, int fwd)
{
- if (MESH_TUNNEL3_SEARCHING == GMT_get_state (c->t))
+ if (GNUNET_NO != c->destroy)
+ return;
+
+ if (MESH_TUNNEL3_SEARCHING == GMT_get_cstate (c->t))
{
/* TODO DHT GET with RO_BART */
return;
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.
+ *
+ * @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;
- struct GNUNET_TIME_Relative delay;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "%s keepalive for %s\n",
+ GM_f2s (fwd), 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);
- delay = c->state == MESH_CONNECTION_READY ?
- refresh_connection_time : create_connection_time;
- c->fwd_maintenance_task = GNUNET_SCHEDULER_add_delayed (delay,
- &connection_fwd_keepalive,
- c);
+ connection_maintain (c, fwd);
+
+ /* Next execution will be scheduled by message_sent */
}
+/**
+ * Keep the connection alive in the FWD direction.
+ *
+ * @param cls Closure (connection to keepalive).
+ * @param tc TaskContext.
+ */
static void
-connection_bck_keepalive (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+connection_fwd_keepalive (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ connection_keepalive ((struct MeshConnection *) cls,
+ GNUNET_YES,
+ tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN);
+}
+
+
+/**
+ * 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 next keepalive task, taking in consideration
+ * the connection state and number of retries.
+ *
+ * If the peer is not the origin, do nothing.
+ *
+ * @param c Connection for which to schedule the next keepalive.
+ * @param fwd Direction for the next keepalive.
+ */
+static void
+schedule_next_keepalive (struct MeshConnection *c, int fwd)
{
- struct MeshConnection *c = cls;
struct GNUNET_TIME_Relative delay;
+ GNUNET_SCHEDULER_TaskIdentifier *task_id;
+ GNUNET_SCHEDULER_Task keepalive_task;
- c->bck_maintenance_task = GNUNET_SCHEDULER_NO_TASK;
- if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+ if (GNUNET_NO == GMC_is_origin (c, fwd))
return;
- connection_maintain (c, GNUNET_NO);
- delay = c->state == MESH_CONNECTION_READY ?
- refresh_connection_time : create_connection_time;
- c->bck_maintenance_task = GNUNET_SCHEDULER_add_delayed (delay,
- &connection_bck_keepalive,
- c);
+ /* Calculate delay to use, depending on the state of the connection */
+ if (MESH_CONNECTION_READY == c->state)
+ {
+ delay = refresh_connection_time;
+ }
+ else
+ {
+ if (1 > c->create_retry)
+ c->create_retry = 1;
+ delay = GNUNET_TIME_relative_multiply (create_connection_time,
+ c->create_retry);
+ if (c->create_retry < 64)
+ c->create_retry *= 2;
+ }
+
+ /* Select direction-dependent parameters */
+ if (GNUNET_YES == fwd)
+ {
+ task_id = &c->fwd_maintenance_task;
+ keepalive_task = &connection_fwd_keepalive;
+ }
+ else
+ {
+ task_id = &c->bck_maintenance_task;
+ keepalive_task = &connection_bck_keepalive;
+ }
+
+ /* Check that no one scheduled it before us */
+ if (GNUNET_SCHEDULER_NO_TASK != *task_id)
+ {
+ /* No need for a _break. It can happen for instance when sending a SYNACK
+ * for a duplicate SYN: the first SYNACK scheduled the task. */
+ GNUNET_SCHEDULER_cancel (*task_id);
+ }
+
+ /* 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));
}
LOG (GNUNET_ERROR_TYPE_DEBUG,
"connection_unlock_queue %s on %s\n",
- fwd ? "FWD" : "BCK", GMC_2s (c));
+ GM_f2s (fwd), GMC_2s (c));
if (GMC_is_terminal (c, fwd))
{
/**
* Cancel all transmissions that belong to a certain connection.
- *
+ *
* If the connection is scheduled for destruction and no more messages are left,
* the connection will be destroyed by the continuation call.
*
struct MeshFlowControl *fc;
struct MeshPeer *peer;
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ " *** Cancel %s queues for connection %s\n",
+ GM_f2s (fwd), GMC_2s (c));
if (NULL == c)
{
GNUNET_break (0);
{
GNUNET_SCHEDULER_cancel (fc->poll_task);
fc->poll_task = GNUNET_SCHEDULER_NO_TASK;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " *** Cancel POLL in ccq for fc %p\n", fc);
}
peer = get_hop (c, fwd);
GMP_queue_cancel (peer, c);
{
struct MeshFlowControl *fc = cls;
- LOG (GNUNET_ERROR_TYPE_DEBUG, " *** POLL sent, scheduling new one!\n");
+ if (2 == c->destroy)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " *** POLL canceled on shutdown\n");
+ return;
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ " *** POLL sent for , scheduling new one!\n");
fc->poll_msg = NULL;
fc->poll_time = GNUNET_TIME_STD_BACKOFF (fc->poll_time);
fc->poll_task = GNUNET_SCHEDULER_add_delayed (fc->poll_time,
&connection_poll, fc);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " task %u\n", fc->poll_task);
+
}
/**
msg.header.size = htons (sizeof (msg));
msg.pid = htonl (fc->last_pid_sent);
LOG (GNUNET_ERROR_TYPE_DEBUG, " *** last pid sent: %u!\n", fc->last_pid_sent);
- fc->poll_msg = GMC_send_prebuilt_message (&msg.header, c, fc == &c->fwd_fc,
+ fc->poll_msg = GMC_send_prebuilt_message (&msg.header, c,
+ fc == &c->fwd_fc, GNUNET_YES,
&poll_sent, fc);
}
c->fwd_maintenance_task = GNUNET_SCHEDULER_NO_TASK;
if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
return;
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Connection %s[%X] FWD timed out. Destroying.\n",
- GMT_2s (c->t),
- c->id);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection %s FWD timed out. Destroying.\n",
+ GMC_2s (c));
if (GMC_is_origin (c, GNUNET_YES)) /* If local, leave. */
+ {
+ GNUNET_break (0);
return;
+ }
GMC_destroy (c);
}
if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
return;
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Connection %s[%X] FWD timed out. Destroying.\n",
- GMT_2s (c->t), c->id);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection %s BCK timed out. Destroying.\n",
+ GMC_2s (c));
if (GMC_is_origin (c, GNUNET_NO)) /* If local, leave. */
+ {
+ GNUNET_break (0);
return;
+ }
GMC_destroy (c);
}
* 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 tiemout if no timeout was running (connection just created).
+ * 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)
{
- 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);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection %s reset timeout\n", GM_f2s (fwd));
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;
+ f = fwd ? &connection_fwd_timeout : &connection_bck_timeout;
*ti = GNUNET_SCHEDULER_add_delayed (delay, f, c);
}
}
next_peer = get_next_hop (c);
prev_peer = get_prev_hop (c);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "register neighbors for connection %s\n",
+ GMC_2s (c));
+ path_debug (c->path);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "own pos %u\n", c->own_pos);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "putting connection %s to next peer %p\n",
+ GMC_2s (c), next_peer);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "next peer %p %s\n", next_peer, GMP_2s (next_peer));
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "putting connection %s to prev peer %p\n",
+ GMC_2s (c), prev_peer);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "prev peer %p %s\n", prev_peer, GMP_2s (prev_peer));
+
if (GNUNET_NO == GMP_is_neighbor (next_peer)
|| GNUNET_NO == GMP_is_neighbor (prev_peer))
+ {
+ if (GMC_is_origin (c, GNUNET_YES))
+ GNUNET_STATISTICS_update (stats, "# local bad paths", 1, GNUNET_NO);
+ GNUNET_STATISTICS_update (stats, "# bad paths", 1, GNUNET_NO);
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " register neighbors failed\n");
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " prev: %s, neighbor?: %d\n",
+ GMP_2s (prev_peer), GMP_is_neighbor (prev_peer));
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " next: %s, neighbor?: %d\n",
+ GMP_2s (next_peer), GMP_is_neighbor (next_peer));
return GNUNET_SYSERR;
+ }
GMP_add_connection (next_peer, c);
GMP_add_connection (prev_peer, c);
struct MeshPeer *peer;
peer = get_next_hop (c);
- GMP_remove_connection (peer, c);
+ if (GNUNET_OK != GMP_remove_connection (peer, c))
+ {
+ GNUNET_assert (MESH_CONNECTION_NEW == c->state
+ || MESH_CONNECTION_DESTROYED == c->state);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " cstate: %u\n", c->state);
+ if (NULL != c->t) GMT_debug (c->t);
+ }
peer = get_prev_hop (c);
- GMP_remove_connection (peer, c);
-
+ if (GNUNET_OK != GMP_remove_connection (peer, c))
+ {
+ GNUNET_assert (MESH_CONNECTION_NEW == c->state
+ || MESH_CONNECTION_DESTROYED == c->state);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " cstate: %u\n", c->state);
+ if (NULL != c->t) GMT_debug (c->t);
+ }
}
GMT_add_connection (c->t, c);
}
+
+/**
+ * Builds a path from a PeerIdentity array.
+ *
+ * @param peers PeerIdentity array.
+ * @param size Size of the @c peers array.
+ * @param own_pos Output parameter: own position in the path.
+ *
+ * @return Fixed and shortened path.
+ */
+static struct MeshPeerPath *
+build_path_from_peer_ids (struct GNUNET_PeerIdentity *peers,
+ unsigned int size,
+ unsigned int *own_pos)
+{
+ struct MeshPeerPath *path;
+ GNUNET_PEER_Id shortid;
+ unsigned int i;
+ unsigned int j;
+ unsigned int offset;
+
+ /* Create path */
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " Creating path...\n");
+ path = path_new (size);
+ *own_pos = 0;
+ offset = 0;
+ for (i = 0; i < size; i++)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " - %u: taking %s\n",
+ i, GNUNET_i2s (&peers[i]));
+ shortid = GNUNET_PEER_intern (&peers[i]);
+
+ /* Check for loops / duplicates */
+ for (j = 0; j < i - offset; j++)
+ {
+ 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);
+ 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;
+ }
+ path->length -= offset;
+
+ if (path->peers[*own_pos] != myid)
+ {
+ /* create path: self not found in path through self */
+ GNUNET_break_op (0);
+ path_destroy (path);
+ return NULL;
+ }
+
+ return path;
+}
+
+
+/**
+ * Log receipt of message on stderr (INFO level).
+ *
+ * @param message Message received.
+ * @param peer Peer who sent the message.
+ * @param hash Connection ID.
+ */
+static void
+log_message (const struct GNUNET_MessageHeader *message,
+ const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MeshHash *hash)
+{
+ LOG (GNUNET_ERROR_TYPE_INFO, "<- %s on connection %s from %s\n",
+ GM_m2s (ntohs (message->type)), GNUNET_h2s (GM_h2hc (hash)),
+ GNUNET_i2s (peer));
+}
+
/******************************************************************************/
/******************************** API ***********************************/
/******************************************************************************/
{
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;
struct MeshConnection *c;
unsigned int own_pos;
uint16_t size;
- uint16_t i;
-
- LOG (GNUNET_ERROR_TYPE_DEBUG, "\n\n");
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Received a connection create msg\n");
/* Check size */
size = ntohs (message->size);
/* Get parameters */
msg = (struct GNUNET_MESH_ConnectionCreate *) message;
cid = &msg->cid;
+ log_message (message, peer, cid);
id = (struct GNUNET_PeerIdentity *) &msg[1];
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- " connection %s (%s).\n",
- GNUNET_h2s (cid), GNUNET_i2s (id));
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " origin: %s\n", GNUNET_i2s (id));
/* Create connection */
c = connection_get (cid);
if (NULL == c)
{
- /* Create path */
- LOG (GNUNET_ERROR_TYPE_DEBUG, " Creating path...\n");
- path = path_new (size);
- own_pos = 0;
- for (i = 0; i < size; i++)
- {
- LOG (GNUNET_ERROR_TYPE_DEBUG, " ... adding %s\n",
- GNUNET_i2s (&id[i]));
- path->peers[i] = GNUNET_PEER_intern (&id[i]);
- if (path->peers[i] == myid)
- own_pos = i;
- }
- if (own_pos == 0 && path->peers[own_pos] != myid)
+ path = build_path_from_peer_ids ((struct GNUNET_PeerIdentity *) &msg[1],
+ size, &own_pos);
+ if (NULL == path)
+ return GNUNET_OK;
+ if (0 == own_pos)
{
- /* create path: self not found in path through self */
GNUNET_break_op (0);
path_destroy (path);
return GNUNET_OK;
}
LOG (GNUNET_ERROR_TYPE_DEBUG, " Own position: %u\n", own_pos);
- GMP_add_path_to_all (path, GNUNET_NO);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " Creating connection\n");
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " Creating connection\n");
c = GMC_new (cid, NULL, path_duplicate (path), own_pos);
if (NULL == c)
{
+ if (path->length - 1 == own_pos)
+ {
+ /* If we are destination, why did the creation fail? */
+ GNUNET_break (0);
+ return GNUNET_OK;
+ }
+ send_broken2 (cid, &my_full_id,
+ GNUNET_PEER_resolve2 (path->peers[own_pos + 1]),
+ path->peers[own_pos - 1]);
path_destroy (path);
return GNUNET_OK;
}
+ GMP_add_path_to_all (path, GNUNET_NO);
connection_reset_timeout (c, GNUNET_YES);
}
else
{
- path = c->path;
+ path = path_duplicate (c->path);
}
if (MESH_CONNECTION_NEW == c->state)
connection_change_state (c, MESH_CONNECTION_SENT);
if (c->own_pos == size - 1)
{
LOG (GNUNET_ERROR_TYPE_DEBUG, " It's for us!\n");
- GMP_add_path_to_origin (orig_peer, path, GNUNET_YES);
+ GMP_add_path_to_origin (orig_peer, path_duplicate (path), GNUNET_YES);
add_to_peer (c, orig_peer);
- if (MESH_TUNNEL3_NEW == GMT_get_state (c->t))
- GMT_change_state (c->t, MESH_TUNNEL3_WAITING);
+ if (MESH_TUNNEL3_NEW == GMT_get_cstate (c->t))
+ GMT_change_cstate (c->t, MESH_TUNNEL3_WAITING);
send_connection_ack (c, GNUNET_NO);
if (MESH_CONNECTION_SENT == c->state)
connection_change_state (c, MESH_CONNECTION_ACK);
-
- /* Keep tunnel alive in direction dest->owner*/
- c->bck_maintenance_task =
- GNUNET_SCHEDULER_add_delayed (create_connection_time,
- &connection_bck_keepalive, c);
}
else
{
/* It's for somebody else! Retransmit. */
LOG (GNUNET_ERROR_TYPE_DEBUG, " Retransmitting.\n");
GMP_add_path (dest_peer, path_duplicate (path), GNUNET_NO);
- GMP_add_path_to_origin (orig_peer, path, GNUNET_NO);
- GMC_send_prebuilt_message (message, c, GNUNET_YES, NULL, NULL);
+ GMP_add_path_to_origin (orig_peer, path_duplicate (path), GNUNET_NO);
+ GMC_send_prebuilt_message (message, c, GNUNET_YES, GNUNET_YES,
+ NULL, NULL);
}
+ path_destroy (path);
return GNUNET_OK;
}
enum MeshConnectionState oldstate;
int fwd;
- LOG (GNUNET_ERROR_TYPE_DEBUG, "\n\n");
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Received a connection ACK msg\n");
msg = (struct GNUNET_MESH_ConnectionACK *) message;
- LOG (GNUNET_ERROR_TYPE_DEBUG, " on connection %s\n",
- GNUNET_h2s (&msg->cid));
+ log_message (message, peer, &msg->cid);
c = connection_get (&msg->cid);
if (NULL == c)
{
return GNUNET_OK;
}
+ if (GNUNET_NO != c->destroy)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " connection being destroyed\n");
+ return GNUNET_OK;
+ }
+
oldstate = c->state;
LOG (GNUNET_ERROR_TYPE_DEBUG, " via peer %s\n", GNUNET_i2s (peer));
pi = GMP_get (peer);
if (MESH_CONNECTION_SENT == oldstate)
connection_reset_timeout (c, GNUNET_YES);
- /* Change connection and tunnel state */
+ /* Change connection state */
connection_change_state (c, MESH_CONNECTION_READY);
- if (MESH_TUNNEL3_WAITING == GMT_get_state (c->t))
- GMT_change_state (c->t, MESH_TUNNEL3_READY);
-
- /* Send ACK (~TCP ACK)*/
send_connection_ack (c, GNUNET_YES);
+
+ /* Change tunnel state, trigger KX */
+ if (MESH_TUNNEL3_WAITING == GMT_get_cstate (c->t))
+ GMT_change_cstate (c->t, MESH_TUNNEL3_READY);
+
+ return GNUNET_OK;
}
/* Message for us as destination? */
connection_reset_timeout (c, GNUNET_NO);
/* Change tunnel state */
- if (MESH_TUNNEL3_WAITING == GMT_get_state (c->t))
- GMT_change_state (c->t, MESH_TUNNEL3_READY);
+ if (MESH_TUNNEL3_WAITING == GMT_get_cstate (c->t))
+ GMT_change_cstate (c->t, MESH_TUNNEL3_READY);
return GNUNET_OK;
}
LOG (GNUNET_ERROR_TYPE_DEBUG, " not for us, retransmitting...\n");
- GMC_send_prebuilt_message (message, c, fwd, NULL, NULL);
+ GMC_send_prebuilt_message (message, c, fwd, GNUNET_YES, NULL, NULL);
return GNUNET_OK;
}
struct MeshConnection *c;
int fwd;
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Received a CONNECTION BROKEN msg from %s\n", GNUNET_i2s (id));
msg = (struct GNUNET_MESH_ConnectionBroken *) message;
+ log_message (message, id, &msg->cid);
LOG (GNUNET_ERROR_TYPE_DEBUG, " regarding %s\n",
GNUNET_i2s (&msg->peer1));
LOG (GNUNET_ERROR_TYPE_DEBUG, " regarding %s\n",
}
fwd = is_fwd (c, id);
- connection_cancel_queues (c, !fwd);
if (GMC_is_terminal (c, fwd))
{
+ path_invalidate (c->path);
if (0 < c->pending_messages)
c->destroy = GNUNET_YES;
else
}
else
{
- GMC_send_prebuilt_message (message, c, fwd, NULL, NULL);
+ GMC_send_prebuilt_message (message, c, fwd, GNUNET_YES, NULL, NULL);
c->destroy = GNUNET_YES;
+ connection_cancel_queues (c, !fwd);
}
return GNUNET_OK;
int fwd;
msg = (struct GNUNET_MESH_ConnectionDestroy *) message;
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Got a CONNECTION DESTROY message from %s\n",
- GNUNET_i2s (peer));
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- " for connection %s\n",
- GNUNET_h2s (&msg->cid));
+ log_message (message, peer, &msg->cid);
c = connection_get (&msg->cid);
if (NULL == c)
{
* destroyed the tunnel and retransmitted to children.
* Safe to ignore.
*/
- GNUNET_STATISTICS_update (stats, "# control on unknown tunnel",
+ GNUNET_STATISTICS_update (stats, "# control on unknown connection",
1, GNUNET_NO);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " connection unknown: already destroyed?\n");
return GNUNET_OK;
}
fwd = is_fwd (c, peer);
if (GNUNET_SYSERR == fwd)
{
- GNUNET_break_op (0);
+ GNUNET_break_op (0); /* FIXME */
+ return GNUNET_OK;
+ }
+ if (GNUNET_NO == GMC_is_terminal (c, fwd))
+ GMC_send_prebuilt_message (message, c, fwd, GNUNET_YES, NULL, NULL);
+ else if (0 == c->pending_messages)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "! directly destroying connection!\n");
+ GMC_destroy (c);
return GNUNET_OK;
}
- GMC_send_prebuilt_message (message, c, fwd, NULL, NULL);
c->destroy = GNUNET_YES;
+ c->state = MESH_CONNECTION_DESTROYED;
+ if (NULL != c->t)
+ {
+ GMT_remove_connection (c->t, c);
+ c->t = NULL;
+ }
return GNUNET_OK;
}
GNUNET_PEER_Id peer_id;
uint32_t pid;
uint32_t ttl;
- uint16_t type;
size_t size;
int fwd;
+ log_message (&msg->header, peer, &msg->cid);
+
/* Check size */
size = ntohs (msg->header.size);
if (size <
GNUNET_break_op (0);
return GNUNET_OK;
}
- type = ntohs (msg->header.type);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "\n\n");
- LOG (GNUNET_ERROR_TYPE_DEBUG, "got a %s message (#%u) from %s\n",
- GNUNET_MESH_DEBUG_M2S (type), ntohl (msg->pid), GNUNET_i2s (peer));
/* Check connection */
c = connection_get (&msg->cid);
if (NULL == c)
{
GNUNET_STATISTICS_update (stats, "# unknown connection", 1, GNUNET_NO);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "WARNING connection unknown\n");
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "enc on unknown connection %s\n",
+ GNUNET_h2s (GM_h2hc (&msg->cid)));
return GNUNET_OK;
}
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " connection %s\n", GMC_2s (c));
+
/* Check if origin is as expected */
neighbor = get_prev_hop (c);
peer_id = GNUNET_PEER_search (peer);
/* Check PID */
fc = fwd ? &c->bck_fc : &c->fwd_fc;
pid = ntohl (msg->pid);
- if (GMC_is_pid_bigger (pid, fc->last_ack_sent))
+ if (GM_is_pid_bigger (pid, fc->last_ack_sent))
{
GNUNET_STATISTICS_update (stats, "# unsolicited message", 1, GNUNET_NO);
LOG (GNUNET_ERROR_TYPE_DEBUG,
pid, fc->last_pid_recv, fc->last_ack_sent);
return GNUNET_OK;
}
- if (GNUNET_NO == GMC_is_pid_bigger (pid, fc->last_pid_recv))
+ if (GNUNET_NO == GM_is_pid_bigger (pid, fc->last_pid_recv))
{
GNUNET_STATISTICS_update (stats, "# duplicate PID", 1, GNUNET_NO);
LOG (GNUNET_ERROR_TYPE_DEBUG,
/* Is this message for us? */
if (GMC_is_terminal (c, fwd))
{
- /* TODO signature verification */
LOG (GNUNET_ERROR_TYPE_DEBUG, " message for us!\n");
GNUNET_STATISTICS_update (stats, "# messages received", 1, GNUNET_NO);
if (NULL == c->t)
{
- GNUNET_break (0);
+ GNUNET_break (GNUNET_NO != c->destroy);
return GNUNET_OK;
}
fc->last_pid_recv = pid;
}
GNUNET_STATISTICS_update (stats, "# messages forwarded", 1, GNUNET_NO);
- GMC_send_prebuilt_message (&msg->header, c, fwd, NULL, NULL);
+ GMC_send_prebuilt_message (&msg->header, c, fwd, GNUNET_NO, NULL, NULL);
return GNUNET_OK;
}
struct MeshPeer *neighbor;
GNUNET_PEER_Id peer_id;
size_t size;
- uint16_t type;
int fwd;
+ log_message (&msg->header, peer, &msg->cid);
+
/* 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);
return GNUNET_OK;
}
- type = ntohs (msg->header.type);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "\n\n");
- LOG (GNUNET_ERROR_TYPE_DEBUG, "got a %s message from %s\n",
- GNUNET_MESH_DEBUG_M2S (type), GNUNET_i2s (peer));
/* Check connection */
c = connection_get (&msg->cid);
if (NULL == c)
{
GNUNET_STATISTICS_update (stats, "# unknown connection", 1, GNUNET_NO);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "WARNING connection unknown\n");
+ 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));
/* Check if origin is as expected */
neighbor = get_prev_hop (c);
/* Count as connection confirmation. */
if (MESH_CONNECTION_SENT == c->state || MESH_CONNECTION_ACK == c->state)
- connection_change_state (c, MESH_CONNECTION_READY);
- connection_reset_timeout (c, fwd);
- if (NULL != c->t)
{
- if (MESH_TUNNEL3_WAITING == GMT_get_state (c->t))
- GMT_change_state (c->t, MESH_TUNNEL3_READY);
+ connection_change_state (c, MESH_CONNECTION_READY);
+ if (NULL != c->t)
+ {
+ if (MESH_TUNNEL3_WAITING == GMT_get_cstate (c->t))
+ GMT_change_cstate (c->t, MESH_TUNNEL3_READY);
+ }
}
+ connection_reset_timeout (c, fwd);
/* Is this message for us? */
if (GMC_is_terminal (c, fwd))
/* Message not for us: forward to next hop */
LOG (GNUNET_ERROR_TYPE_DEBUG, " not for us, retransmitting...\n");
GNUNET_STATISTICS_update (stats, "# messages forwarded", 1, GNUNET_NO);
- GMC_send_prebuilt_message (&msg->header, c, fwd, NULL, NULL);
+ GMC_send_prebuilt_message (&msg->header, c, fwd, GNUNET_NO, NULL, NULL);
return GNUNET_OK;
}
uint32_t ack;
int fwd;
- LOG (GNUNET_ERROR_TYPE_DEBUG, "\n\n");
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Got an ACK packet from %s!\n",
- GNUNET_i2s (peer));
msg = (struct GNUNET_MESH_ACK *) message;
-
+ log_message (message, peer, &msg->cid);
c = connection_get (&msg->cid);
-
if (NULL == c)
{
GNUNET_STATISTICS_update (stats, "# ack on unknown connection", 1,
ack = ntohl (msg->ack);
LOG (GNUNET_ERROR_TYPE_DEBUG, " ACK %u (was %u)\n",
ack, fc->last_ack_recv);
- if (GMC_is_pid_bigger (ack, fc->last_ack_recv))
+ if (GM_is_pid_bigger (ack, fc->last_ack_recv))
fc->last_ack_recv = ack;
/* Cancel polling if the ACK is big enough. */
if (GNUNET_SCHEDULER_NO_TASK != fc->poll_task &&
- GMC_is_pid_bigger (fc->last_ack_recv, fc->last_pid_sent))
+ GM_is_pid_bigger (fc->last_ack_recv, fc->last_pid_sent))
{
LOG (GNUNET_ERROR_TYPE_DEBUG, " Cancel poll\n");
GNUNET_SCHEDULER_cancel (fc->poll_task);
uint32_t pid;
int fwd;
- LOG (GNUNET_ERROR_TYPE_DEBUG, "\n\n");
- LOG (GNUNET_ERROR_TYPE_DEBUG,
- "Got a POLL packet from %s!\n",
- GNUNET_i2s (peer));
-
msg = (struct GNUNET_MESH_Poll *) message;
-
+ log_message (message, peer, &msg->cid);
c = connection_get (&msg->cid);
-
if (NULL == c)
{
GNUNET_STATISTICS_update (stats, "# poll on unknown connection", 1,
GNUNET_NO);
- GNUNET_break_op (0);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "WARNING POLL message on unknown connection %s!\n",
+ 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;
- int fwd;
-
- msg = (struct GNUNET_MESH_ConnectionKeepAlive *) message;
- LOG (GNUNET_ERROR_TYPE_DEBUG, "got a keepalive packet from %s\n",
- GNUNET_i2s (peer));
-
- c = connection_get (&msg->cid);
- if (NULL == c)
- {
- GNUNET_STATISTICS_update (stats, "# keepalive on unknown connection", 1,
- GNUNET_NO);
- return GNUNET_OK;
- }
-
- fwd = GNUNET_MESSAGE_TYPE_MESH_FWD_KEEPALIVE == ntohs (message->type) ?
- GNUNET_YES : GNUNET_NO;
-
- /* Check if origin is as expected */
- neighbor = get_hop (c, fwd);
- if (GNUNET_PEER_search (peer) != GMP_get_short_id (neighbor))
- {
- 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, NULL, NULL);
-
- return GNUNET_OK;
-}
-
-
/**
* Send an ACK on the appropriate connection/channel, depending on
* the direction and the position of the peer.
LOG (GNUNET_ERROR_TYPE_DEBUG,
"GMC send %s ACK on %s\n",
- fwd ? "FWD" : "BCK", GMC_2s (c));
+ GM_f2s (fwd), GMC_2s (c));
if (NULL == c)
{
return;
}
+ if (GNUNET_NO != c->destroy)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " being destroyed, why bother...\n");
+ return;
+ }
+
/* Get available buffer space */
if (GMC_is_terminal (c, fwd))
{
connections = GNUNET_CONTAINER_multihashmap_create (1024, GNUNET_YES);
}
+
+/**
+ * Destroy each connection on shutdown.
+ *
+ * @param cls Closure (unused).
+ * @param key Current key code (CID, unused).
+ * @param value Value in the hash map (connection)
+ *
+ * @return #GNUNET_YES, because we should continue to iterate,
+ */
+static int
+shutdown_iterator (void *cls,
+ const struct GNUNET_HashCode *key,
+ void *value)
+{
+ struct MeshConnection *c = value;
+
+ GMC_destroy (c);
+ return GNUNET_YES;
+}
+
+
/**
* Shut down the connections subsystem.
*/
void
GMC_shutdown (void)
{
+ GNUNET_CONTAINER_multihashmap_iterate (connections, &shutdown_iterator, NULL);
GNUNET_CONTAINER_multihashmap_destroy (connections);
+ connections = NULL;
}
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 = GNUNET_new (struct MeshConnection);
c->id = *cid;
- GNUNET_CONTAINER_multihashmap_put (connections, &c->id, c,
- GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CONTAINER_multihashmap_put (connections,
+ GMC_get_h (c), c,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
fc_init (&c->fwd_fc);
fc_init (&c->bck_fc);
c->fwd_fc.c = c;
c->bck_fc.c = c;
c->t = t;
- if (own_pos > p->length - 1)
- {
- GNUNET_break (0);
- GMC_destroy (c);
- path_destroy (p);
- return NULL;
- }
+ GNUNET_assert (own_pos <= p->length - 1);
c->own_pos = own_pos;
c->path = p;
- if (0 == own_pos)
- {
- c->fwd_maintenance_task =
- GNUNET_SCHEDULER_add_delayed (create_connection_time,
- &connection_fwd_keepalive, c);
- }
if (GNUNET_OK != register_neighbors (c))
{
+ if (0 == own_pos)
+ {
+ path_invalidate (c->path);
+ c->t = NULL;
+ c->path = NULL;
+ }
GMC_destroy (c);
return NULL;
}
GMC_destroy (struct MeshConnection *c)
{
if (NULL == c)
+ {
+ GNUNET_break (0);
return;
+ }
if (2 == c->destroy) /* cancel queues -> GMP_queue_cancel -> q_destroy -> */
return; /* -> message_sent -> GMC_destroy. Don't loop. */
c->destroy = 2;
LOG (GNUNET_ERROR_TYPE_DEBUG, "destroying connection %s\n", GMC_2s (c));
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " fc's f: %p, b: %p\n",
+ &c->fwd_fc, &c->bck_fc);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " fc tasks f: %u, b: %u\n",
+ c->fwd_fc.poll_task, c->bck_fc.poll_task);
/* Cancel all traffic */
- connection_cancel_queues (c, GNUNET_YES);
- connection_cancel_queues (c, GNUNET_NO);
+ if (NULL != c->path)
+ {
+ connection_cancel_queues (c, GNUNET_YES);
+ connection_cancel_queues (c, GNUNET_NO);
+ unregister_neighbors (c);
+ }
- /* Cancel maintainance task (keepalive/timeout) */
- if (GNUNET_SCHEDULER_NO_TASK != c->fwd_maintenance_task)
- GNUNET_SCHEDULER_cancel (c->fwd_maintenance_task);
- if (GNUNET_SCHEDULER_NO_TASK != c->bck_maintenance_task)
- GNUNET_SCHEDULER_cancel (c->bck_maintenance_task);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " fc tasks f: %u, b: %u\n",
+ c->fwd_fc.poll_task, c->bck_fc.poll_task);
- /* Unregister from neighbors */
- unregister_neighbors (c);
+ /* Cancel maintainance task (keepalive/timeout) */
+ if (NULL != c->fwd_fc.poll_msg)
+ {
+ GMC_cancel (c->fwd_fc.poll_msg);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " *** POLL msg FWD canceled\n");
+ }
+ if (NULL != c->bck_fc.poll_msg)
+ {
+ GMC_cancel (c->bck_fc.poll_msg);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " *** POLL msg BCK canceled\n");
+ }
- /* Delete */
- GNUNET_STATISTICS_update (stats, "# connections", -1, GNUNET_NO);
+ /* Delete from tunnel */
if (NULL != c->t)
GMT_remove_connection (c->t, c);
- if (GNUNET_NO == GMC_is_origin (c, GNUNET_YES))
+ if (GNUNET_NO == GMC_is_origin (c, GNUNET_YES) && NULL != c->path)
path_destroy (c->path);
+ if (GNUNET_SCHEDULER_NO_TASK != c->fwd_maintenance_task)
+ GNUNET_SCHEDULER_cancel (c->fwd_maintenance_task);
+ if (GNUNET_SCHEDULER_NO_TASK != c->bck_maintenance_task)
+ GNUNET_SCHEDULER_cancel (c->bck_maintenance_task);
+ if (GNUNET_SCHEDULER_NO_TASK != c->fwd_fc.poll_task)
+ {
+ GNUNET_SCHEDULER_cancel (c->fwd_fc.poll_task);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " *** POLL FWD canceled\n");
+ }
+ if (GNUNET_SCHEDULER_NO_TASK != c->bck_fc.poll_task)
+ {
+ GNUNET_SCHEDULER_cancel (c->bck_fc.poll_task);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " *** POLL BCK canceled\n");
+ }
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.
*
const struct MeshPeerPath *
GMC_get_path (const struct MeshConnection *c)
{
- return c->path;
+ if (GNUNET_NO == c->destroy)
+ return c->path;
+ return NULL;
}
struct MeshFlowControl *fc;
fc = fwd ? &c->fwd_fc : &c->bck_fc;
- if (GMC_is_pid_bigger(fc->last_pid_recv, fc->last_ack_sent))
+ if (GM_is_pid_bigger(fc->last_pid_recv, fc->last_ack_sent))
{
return 0;
}
void
GMC_allow (struct MeshConnection *c, unsigned int buffer, int fwd)
{
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " allowing %s %u messages %s\n",
+ GMC_2s (c), buffer, GM_f2s (fwd));
send_ack (c, buffer, fwd, GNUNET_NO);
}
* (the one we just scheduled), so no point in checking whether to
* destroy immediately. */
c->destroy = GNUNET_YES;
+ c->state = MESH_CONNECTION_DESTROYED;
/**
* Cancel all queues, if no message is left, connection will be destroyed.
{
struct MeshFlowControl *fc;
+ if (NULL == c)
+ {
+ GNUNET_break (0);
+ return GNUNET_YES;
+ }
fc = fwd ? &c->fwd_fc : &c->bck_fc;
- if (GMC_is_pid_bigger (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;
}
* If message is not hop-by-hop, decrements TTL of copy.
* @param c Connection on which this message is transmitted.
* @param fwd Is this a fwd message?
+ * @param force Force the connection to accept the message (buffer overfill).
* @param cont Continuation called once message is sent. Can be NULL.
* @param cont_cls Closure for @c cont.
*
*/
struct MeshConnectionQueue *
GMC_send_prebuilt_message (const struct GNUNET_MessageHeader *message,
- struct MeshConnection *c, int fwd,
+ struct MeshConnection *c, int fwd, int force,
GMC_sent cont, void *cont_cls)
{
struct MeshFlowControl *fc;
data = GNUNET_malloc (size);
memcpy (data, message, size);
type = ntohs (message->type);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Send %s (%u bytes) on connection %s\n",
- GNUNET_MESH_DEBUG_M2S (type), size, GMC_2s (c));
+ LOG (GNUNET_ERROR_TYPE_INFO, "-> %s on connection %s (%u bytes)\n",
+ GM_m2s (type), GMC_2s (c), size);
fc = fwd ? &c->fwd_fc : &c->bck_fc;
- droppable = GNUNET_YES;
+ droppable = GNUNET_NO == force;
switch (type)
{
struct GNUNET_MESH_Encrypted *emsg;
emsg->ttl = htonl (ttl - 1);
emsg->pid = htonl (fc->next_pid++);
LOG (GNUNET_ERROR_TYPE_DEBUG, " Q_N+ %p %u\n", fc, fc->queue_n);
- fc->queue_n++;
- LOG (GNUNET_ERROR_TYPE_DEBUG, "pid %u\n", ntohl (emsg->pid));
- LOG (GNUNET_ERROR_TYPE_DEBUG, "last pid sent %u\n", fc->last_pid_sent);
- LOG (GNUNET_ERROR_TYPE_DEBUG, " ack recv %u\n", fc->last_ack_recv);
- if (GMC_is_pid_bigger (fc->last_pid_sent + 1, fc->last_ack_recv))
+ if (GNUNET_YES == droppable)
+ {
+ fc->queue_n++;
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "pid %u\n", ntohl (emsg->pid));
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "last pid sent %u\n", fc->last_pid_sent);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " ack recv %u\n", fc->last_ack_recv);
+ }
+ else
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " not droppable, Q_N stays the same\n");
+ }
+ if (GM_is_pid_bigger (fc->last_pid_sent + 1, fc->last_ack_recv))
{
GMC_start_poll (c, fwd);
}
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:
break;
default:
GNUNET_break (0);
+ GNUNET_free (data);
+ return NULL;
}
if (fc->queue_n > fc->queue_max && droppable)
LOG (GNUNET_ERROR_TYPE_DEBUG, " C_P+ %p %u\n", c, c->pending_messages);
c->pending_messages++;
- if (NULL == cont)
- {
- (void) GMP_queue_add (get_hop (c, fwd), data, type, size, c, fwd,
- &message_sent, NULL);
- return NULL;
- }
-
q = GNUNET_new (struct MeshConnectionQueue);
+ q->forced = !droppable;
q->q = GMP_queue_add (get_hop (c, fwd), data, type, size, c, fwd,
&message_sent, q);
if (NULL == q->q)
{
- GNUNET_break (0);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "WARNING dropping msg on %s\n", GMC_2s (c));
GNUNET_free (data);
GNUNET_free (q);
return NULL;
void
GMC_send_create (struct MeshConnection *connection)
{
- enum MeshTunnel3State state;
+ enum MeshTunnel3CState state;
size_t size;
size = sizeof (struct GNUNET_MESH_ConnectionCreate);
size += connection->path->length * sizeof (struct GNUNET_PeerIdentity);
- LOG (GNUNET_ERROR_TYPE_DEBUG, "Send connection create\n");
- GMP_queue_add (get_next_hop (connection), NULL,
- GNUNET_MESSAGE_TYPE_MESH_CONNECTION_CREATE,
- size, connection, GNUNET_YES, &message_sent, NULL);
+
+ LOG (GNUNET_ERROR_TYPE_INFO, "=> %s on connection %s (%u bytes)\n",
+ GM_m2s (GNUNET_MESSAGE_TYPE_MESH_CONNECTION_CREATE),
+ GMC_2s (connection), size);
LOG (GNUNET_ERROR_TYPE_DEBUG, " C_P+ %p %u (create)\n",
connection, connection->pending_messages);
connection->pending_messages++;
- state = GMT_get_state (connection->t);
+
+ connection->maintenance_q =
+ GMP_queue_add (get_next_hop (connection), NULL,
+ GNUNET_MESSAGE_TYPE_MESH_CONNECTION_CREATE,
+ size, connection, GNUNET_YES, &message_sent, NULL);
+
+ state = GMT_get_cstate (connection->t);
if (MESH_TUNNEL3_SEARCHING == state || MESH_TUNNEL3_NEW == state)
- GMT_change_state (connection->t, MESH_TUNNEL3_WAITING);
+ GMT_change_cstate (connection->t, MESH_TUNNEL3_WAITING);
if (MESH_CONNECTION_NEW == connection->state)
connection_change_state (connection, MESH_CONNECTION_SENT);
}
GMC_2s (c));
if (GNUNET_NO == GMC_is_terminal (c, GNUNET_YES))
- GMC_send_prebuilt_message (&msg.header, c, GNUNET_YES, NULL, NULL);
+ GMC_send_prebuilt_message (&msg.header, c,
+ GNUNET_YES, GNUNET_YES, NULL, NULL);
if (GNUNET_NO == GMC_is_terminal (c, GNUNET_NO))
- GMC_send_prebuilt_message (&msg.header, c, GNUNET_NO, NULL, NULL);
+ GMC_send_prebuilt_message (&msg.header, c,
+ GNUNET_NO, GNUNET_YES, NULL, NULL);
c->destroy = GNUNET_YES;
+ c->state = MESH_CONNECTION_DESTROYED;
}
struct MeshFlowControl *fc;
fc = fwd ? &c->fwd_fc : &c->bck_fc;
- if (GNUNET_SCHEDULER_NO_TASK != fc->poll_task && NULL != fc->poll_msg)
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " *** POLL %s requested\n",
+ GM_f2s (fwd));
+ if (GNUNET_SCHEDULER_NO_TASK != fc->poll_task || NULL != fc->poll_msg)
{
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " *** not needed (%u, %p)\n",
+ fc->poll_task, fc->poll_msg);
return;
}
+ LOG (GNUNET_ERROR_TYPE_DEBUG, " *** POLL started on request\n");
fc->poll_task = GNUNET_SCHEDULER_add_delayed (fc->poll_time,
&connection_poll,
fc);
* @param c Connection.
*/
const char *
-GMC_2s (struct MeshConnection *c)
+GMC_2s (const struct MeshConnection *c)
{
+ if (NULL == c)
+ return "NULL";
+
if (NULL != c->t)
{
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);
-}
\ No newline at end of file
+ return GNUNET_h2s (GM_h2hc (&c->id));
+}