X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Fmesh%2Fgnunet-service-mesh_connection.c;h=6947e47267824101a9e4efdcdeee3d370b363140;hb=6ba4f04d739c78bd5ff0ef7195fb0c897b716632;hp=fdb9e4a8db0b10bdf2fe71f07b07c58b6bd9634a;hpb=dcb337585d87937e7656a009d4e4f2abe6d91aa4;p=oweals%2Fgnunet.git diff --git a/src/mesh/gnunet-service-mesh_connection.c b/src/mesh/gnunet-service-mesh_connection.c index fdb9e4a8d..6947e4726 100644 --- a/src/mesh/gnunet-service-mesh_connection.c +++ b/src/mesh/gnunet-service-mesh_connection.c @@ -171,7 +171,7 @@ struct MeshConnection /** * ID of the connection. */ - struct GNUNET_HashCode id; + struct GNUNET_MeshHash id; /** * State of the connection. @@ -201,6 +201,17 @@ struct MeshConnection */ 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. */ @@ -320,6 +331,34 @@ connection_debug (struct MeshConnection *c) } #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. * @@ -374,9 +413,9 @@ fc_init (struct MeshFlowControl *fc) * @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)); } @@ -396,6 +435,8 @@ connection_change_state (struct MeshConnection* c, "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; } @@ -446,6 +487,8 @@ send_ack (struct MeshConnection *c, unsigned int buffer, int fwd, int force) /* 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; } @@ -453,9 +496,8 @@ send_ack (struct MeshConnection *c, unsigned int buffer, int fwd, int force) 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", - GM_f2s (fwd), 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; @@ -570,6 +612,14 @@ message_sent (void *cls, /* 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); @@ -587,6 +637,7 @@ message_sent (void *cls, fc->last_pid_sent); } GMC_send_ack (c, fwd, GNUNET_NO); + connection_reset_timeout (c, fwd); break; case GNUNET_MESSAGE_TYPE_MESH_POLL: @@ -639,11 +690,16 @@ get_prev_hop (const struct MeshConnection *c) { GNUNET_PEER_Id id; + 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); } @@ -660,11 +716,16 @@ get_next_hop (const struct MeshConnection *c) { 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); } @@ -729,8 +790,8 @@ send_connection_ack (struct MeshConnection *connection, int fwd) struct MeshTunnel3 *t; t = connection->t; - LOG (GNUNET_ERROR_TYPE_DEBUG, "Send connection %s ACK\n", - !GM_f2s (fwd)); + 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), @@ -768,6 +829,42 @@ send_broken (struct MeshConnection *c, } +/** + * 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. * @@ -775,23 +872,22 @@ send_broken (struct MeshConnection *c, * @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)); } @@ -823,6 +919,9 @@ connection_recreate (struct MeshConnection *c, int fwd) static void connection_maintain (struct MeshConnection *c, int fwd) { + if (GNUNET_NO != c->destroy) + return; + if (MESH_TUNNEL3_SEARCHING == GMT_get_cstate (c->t)) { /* TODO DHT GET with RO_BART */ @@ -837,7 +936,7 @@ connection_maintain (struct MeshConnection *c, int fwd) connection_recreate (c, fwd); break; case MESH_CONNECTION_READY: - connection_keepalive (c, fwd); + send_connection_keepalive (c, fwd); break; default: break; @@ -845,41 +944,125 @@ connection_maintain (struct MeshConnection *c, int fwd) } + +/** + * 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_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_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)); } @@ -1045,13 +1228,14 @@ connection_fwd_timeout (void *cls, 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); } @@ -1074,12 +1258,14 @@ connection_bck_timeout (void *cls, 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); } @@ -1102,27 +1288,24 @@ connection_bck_timeout (void *cls, 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; + f = fwd ? &connection_fwd_timeout : &connection_bck_timeout; *ti = GNUNET_SCHEDULER_add_delayed (delay, f, c); } } @@ -1145,17 +1328,28 @@ register_neighbors (struct MeshConnection *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, "# 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", + 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", + LOG (GNUNET_ERROR_TYPE_DEBUG, " next: %s, neighbor?: %d\n", GMP_2s (next_peer), GMP_is_neighbor (next_peer)); return GNUNET_SYSERR; } @@ -1180,15 +1374,19 @@ unregister_neighbors (struct MeshConnection *c) peer = get_next_hop (c); if (GNUNET_OK != GMP_remove_connection (peer, c)) { - GNUNET_break (MESH_CONNECTION_NEW == c->state); - LOG (GNUNET_ERROR_TYPE_ERROR, " cstate: %u\n", c->state); + 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); if (GNUNET_OK != GMP_remove_connection (peer, c)) { - GNUNET_break (MESH_CONNECTION_NEW == c->state); - LOG (GNUNET_ERROR_TYPE_ERROR, " cstate: %u\n", c->state); + 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); } } @@ -1210,6 +1408,85 @@ add_to_peer (struct MeshConnection *c, struct MeshPeer *peer) 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 ***********************************/ /******************************************************************************/ @@ -1230,17 +1507,13 @@ GMC_handle_create (void *cls, const struct GNUNET_PeerIdentity *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; 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); @@ -1268,43 +1541,42 @@ GMC_handle_create (void *cls, const struct GNUNET_PeerIdentity *peer, /* 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"); 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 @@ -1331,14 +1603,6 @@ GMC_handle_create (void *cls, const struct GNUNET_PeerIdentity *peer, 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*/ - if (GNUNET_SCHEDULER_NO_TASK == c->bck_maintenance_task) - { - c->bck_maintenance_task = - GNUNET_SCHEDULER_add_delayed (create_connection_time, - &connection_bck_keepalive, c); - } } else { @@ -1346,7 +1610,8 @@ GMC_handle_create (void *cls, const struct GNUNET_PeerIdentity *peer, 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_duplicate (path), GNUNET_NO); - GMC_send_prebuilt_message (message, c, GNUNET_YES, GNUNET_YES, NULL, NULL); + GMC_send_prebuilt_message (message, c, GNUNET_YES, GNUNET_YES, + NULL, NULL); } path_destroy (path); return GNUNET_OK; @@ -1374,11 +1639,8 @@ GMC_handle_confirm (void *cls, const struct GNUNET_PeerIdentity *peer, 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) { @@ -1388,6 +1650,12 @@ GMC_handle_confirm (void *cls, const struct GNUNET_PeerIdentity *peer, 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); @@ -1494,9 +1762,8 @@ GMC_handle_broken (void* cls, 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", @@ -1511,6 +1778,7 @@ GMC_handle_broken (void* cls, fwd = is_fwd (c, id); if (GMC_is_terminal (c, fwd)) { + path_invalidate (c->path); if (0 < c->pending_messages) c->destroy = GNUNET_YES; else @@ -1547,12 +1815,7 @@ GMC_handle_destroy (void *cls, const struct GNUNET_PeerIdentity *peer, 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) { @@ -1568,7 +1831,7 @@ GMC_handle_destroy (void *cls, const struct GNUNET_PeerIdentity *peer, 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)) @@ -1583,7 +1846,7 @@ GMC_handle_destroy (void *cls, const struct GNUNET_PeerIdentity *peer, c->state = MESH_CONNECTION_DESTROYED; if (NULL != c->t) { - GMT_remove_connection (c->t); + GMT_remove_connection (c->t, c); c->t = NULL; } @@ -1609,10 +1872,11 @@ handle_mesh_encrypted (const struct GNUNET_PeerIdentity *peer, 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 < @@ -1622,22 +1886,19 @@ handle_mesh_encrypted (const struct GNUNET_PeerIdentity *peer, 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", - GM_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 %s unknown\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; } + 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); @@ -1687,13 +1948,12 @@ handle_mesh_encrypted (const struct GNUNET_PeerIdentity *peer, /* 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; @@ -1737,29 +1997,27 @@ handle_mesh_kx (const struct GNUNET_PeerIdentity *peer, 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", - GM_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)); @@ -1788,13 +2046,15 @@ handle_mesh_kx (const struct GNUNET_PeerIdentity *peer, /* 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_cstate (c->t)) - GMT_change_cstate (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)) @@ -1878,13 +2138,9 @@ GMC_handle_ack (void *cls, const struct GNUNET_PeerIdentity *peer, 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, @@ -1955,20 +2211,16 @@ GMC_handle_poll (void *cls, const struct GNUNET_PeerIdentity *peer, 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; } @@ -2004,73 +2256,6 @@ GMC_handle_poll (void *cls, const struct GNUNET_PeerIdentity *peer, } -/** - * 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 (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; - } - - /* 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. @@ -2207,7 +2392,7 @@ GMC_shutdown (void) 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) @@ -2218,7 +2403,7 @@ GMC_new (const struct GNUNET_HashCode *cid, 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); @@ -2234,7 +2419,7 @@ GMC_new (const struct GNUNET_HashCode *cid, { if (0 == own_pos) { - GMT_remove_path (c->t, p); + path_invalidate (c->path); c->t = NULL; c->path = NULL; } @@ -2242,13 +2427,6 @@ GMC_new (const struct GNUNET_HashCode *cid, return NULL; } - if (0 == own_pos) - { - c->fwd_maintenance_task = - GNUNET_SCHEDULER_add_delayed (create_connection_time, - &connection_fwd_keepalive, c); - } - return c; } @@ -2317,7 +2495,8 @@ GMC_destroy (struct MeshConnection *c) } 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); @@ -2330,13 +2509,27 @@ GMC_destroy (struct MeshConnection *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. * @@ -2451,6 +2644,8 @@ GMC_get_qn (struct MeshConnection *c, int fwd) 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); } @@ -2546,6 +2741,11 @@ GMC_is_sendable (struct MeshConnection *c, int fwd) { struct MeshFlowControl *fc; + if (NULL == c) + { + GNUNET_break (0); + return GNUNET_YES; + } fc = fwd ? &c->fwd_fc : &c->bck_fc; if (GM_is_pid_bigger (fc->last_ack_recv, fc->last_pid_sent)) return GNUNET_YES; @@ -2584,8 +2784,8 @@ GMC_send_prebuilt_message (const struct GNUNET_MessageHeader *message, 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", - GM_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_NO == force; @@ -2651,18 +2851,18 @@ GMC_send_prebuilt_message (const struct GNUNET_MessageHeader *message, 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: @@ -2697,7 +2897,7 @@ GMC_send_prebuilt_message (const struct GNUNET_MessageHeader *message, &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; @@ -2742,14 +2942,17 @@ GMC_send_create (struct MeshConnection *connection) size = sizeof (struct GNUNET_MESH_ConnectionCreate); size += connection->path->length * sizeof (struct GNUNET_PeerIdentity); - LOG (GNUNET_ERROR_TYPE_DEBUG, "Send connection create\n"); + 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++; - GMP_queue_add (get_next_hop (connection), NULL, - GNUNET_MESSAGE_TYPE_MESH_CONNECTION_CREATE, - size, connection, GNUNET_YES, &message_sent, NULL); + 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) @@ -2852,7 +3055,7 @@ GMC_stop_poll (struct MeshConnection *c, int fwd) * @param c Connection. */ const char * -GMC_2s (struct MeshConnection *c) +GMC_2s (const struct MeshConnection *c) { if (NULL == c) return "NULL"; @@ -2861,8 +3064,8 @@ GMC_2s (struct MeshConnection *c) { 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)); }