}
/**
- * find the first peer whom to send a packet to go down this path
+ * Find the first peer whom to send a packet to go down this path
* @param path The path to use
* @return short id of the next peer, myid in case of local delivery,
* or 0 in case of error
return 0;
}
+
+/**
+ * Get the cost of the path.
+ * @param path The path to analyze
+ * @return Number of hops to reach destination, UINT_MAX in case the peer is not
+ * in the path
+ */
+static unsigned int
+get_path_cost(struct MeshPath *path)
+{
+ unsigned int i;
+
+ if (NULL == path) return UINT_MAX;
+ for (i = 0; i < path->length; i++) {
+ if (path->peers[i] == myid) {
+ return path->length - i;
+ }
+ }
+ return UINT_MAX;
+}
+
+
+/**
+ * Add the path to the peer and update the path used to reach it in case this
+ * is the shortest.
+ * @param peer_info Destination peer to add the path to.
+ * @param path New path to add. Last peer must be the peer in arg 1.
+ */
static void
add_path_to_peer(struct MeshPeerInfo *peer_info, struct MeshPath *path)
{
-
+ unsigned int i;
+ unsigned int new_cost;
+ unsigned int best_cost;
+ struct MeshPath *aux;
+ struct MeshPath *best;
+
+ if (NULL == peer_info || NULL == path) return;
+
+ new_cost = get_path_cost(path);
+ best_cost = UINT_MAX;
+ best = NULL;
+ for (aux = peer_info->path; aux != NULL; aux = aux->next) {
+ if ((i = get_path_cost(aux)) < best_cost) {
+ best = aux;
+ best_cost = i;
+ }
+ }
+ if (best_cost < new_cost) {
+ path->in_use = 0;
+ GNUNET_CONTAINER_DLL_insert_tail(peer_info->path,
+ peer_info->path_tail,
+ path);
+ } else {
+ if (NULL != best) best->in_use = 0;
+ path->in_use = 1;
+ GNUNET_CONTAINER_DLL_insert(peer_info->path,
+ peer_info->path_tail,
+ path);
+ }
return;
}
}
-#if LATER
+
/**
* Search for a tunnel by global ID using full PeerIdentities
* @param oid owner of the tunnel
* @return GNUNET_OK on success
*/
static int
-destroy_path(struct MeshTunnel *t, struct MeshPath *p)
+destroy_path(struct MeshPath *p)
{
GNUNET_PEER_decrement_rcs(p->peers, p->length);
GNUNET_free(p->peers);
return GNUNET_OK;
}
-
+#if LATER
/**
* Destroy the peer_info and free any allocated resources linked to it
* @param t tunnel the path belongs to
* @return GNUNET_OK on success
*/
static int
-destroy_tunnel(struct MeshClient *c, struct MeshTunnel *t)
+destroy_tunnel(struct MeshTunnel *t)
{
// struct MeshPath *path;
- GNUNET_HashCode hash;
- int r;
+ struct MeshClient *c;
+ GNUNET_HashCode hash;
+ int r;
if (NULL == t) return GNUNET_OK;
+ c = t->client;
+
GNUNET_CRYPTO_hash(&t->id, sizeof(struct MESH_TunnelID), &hash);
if(GNUNET_YES != GNUNET_CONTAINER_multihashmap_remove(tunnels, &hash, t)) {
r = GNUNET_SYSERR;
const struct GNUNET_TRANSPORT_ATS_Information
*atsi)
{
- /* Extract path */
- /* Find origin & self */
- /* Search for origin in local tunnels */
- /* Create tunnel / add path */
- /* Retransmit to next link in chain, if any (core_notify + callback) */
+ unsigned int own_pos;
+ uint16_t size;
+ uint16_t i;
+ MESH_TunnelNumber tid;
+ struct GNUNET_MESH_ManipulatePath *msg;
+ struct GNUNET_PeerIdentity *pi;
+ GNUNET_HashCode hash;
+ struct MeshPath *path;
+ struct MeshPeerInfo *peer_info;
+ struct MeshTunnel *t;
+
+
+ size = ntohs(message->size);
+ if (size < sizeof(struct GNUNET_MESH_ManipulatePath)) {
+ GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
+ "received create path message too short\n");
+ return GNUNET_OK;
+ }
+
+ size -= sizeof(struct GNUNET_MESH_ManipulatePath);
+ if (size < 2 * sizeof(struct GNUNET_PeerIdentity)) {
+ GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
+ "create path message lacks enough peers\n");
+ return GNUNET_OK;
+ }
+ if (size % sizeof(struct GNUNET_PeerIdentity)) {
+ GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
+ "create path message of wrong size\n");
+ return GNUNET_OK;
+ }
+ msg = (struct GNUNET_MESH_ManipulatePath *) message;
+ size /= sizeof(struct GNUNET_PeerIdentity);
+
+ tid = ntohl(msg->tid);
+ pi = (struct GNUNET_PeerIdentity *) &msg[1];
+ t = retrieve_tunnel(pi, tid);
+
+ if (NULL == t) {
+ t = GNUNET_malloc(sizeof(struct MeshTunnel));
+ t->id.oid = GNUNET_PEER_intern(pi);
+ t->id.tid = tid;
+ t->local_tid = 0;
+ t->client = NULL;
+ t->peers = GNUNET_CONTAINER_multihashmap_create(32);
+
+ GNUNET_CRYPTO_hash(&t->id, sizeof(struct MESH_TunnelID), &hash);
+ if (GNUNET_OK !=
+ GNUNET_CONTAINER_multihashmap_put(tunnels,
+ &hash,
+ t,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
+ {
+ GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
+ "create path: could not store tunnel in hashmap\n");
+ return GNUNET_OK;
+ }
+
+ }
+ peer_info = GNUNET_CONTAINER_multihashmap_get(peers,
+ &pi[size - 1].hashPubKey);
+ if (NULL == peer_info) {
+ peer_info = GNUNET_malloc(sizeof(struct MeshPeerInfo));
+ peer_info->id = GNUNET_PEER_intern(&pi[size - 1]);
+ peer_info->state = MESH_PEER_WAITING;
+ GNUNET_CONTAINER_multihashmap_put(peers,
+ &pi[size - 1].hashPubKey,
+ peer_info,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
+ }
+
+ path = GNUNET_malloc(sizeof(struct MeshPath));
+ path->length = size;
+ path->peers = GNUNET_malloc(size * sizeof(GNUNET_PEER_Id));
+ own_pos = 0;
+ for (i = 0; i < size; i++) {
+ path->peers[i] = GNUNET_PEER_intern(&pi[i]);
+ if (path->peers[i] == myid) own_pos = i;
+ }
+ if (own_pos == 0) { /* cannot be self, must be 'not found' */
+ GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
+ "create path: self not found in path through self\n");
+ destroy_path(path);
+ /* FIXME destroy tunnel? leave for timeout? */
+ return 0;
+ }
+ if (own_pos == size - 1) { /* it is for us! */
+ destroy_path(path); /* not needed anymore */
+ /* TODO: send ack? new meesage type? */
+ } else {
+ add_path_to_peer(peer_info, path);
+ /* TODO: Retransmit to next link in chain, if any (core_notify + callback) */
+ }
return GNUNET_OK;
}
static int
delete_tunnel_entry (void *cls, const GNUNET_HashCode * key, void *value) {
int r;
- r = destroy_tunnel((struct MeshClient *) cls, (struct MeshTunnel *) value);
+ r = destroy_tunnel((struct MeshTunnel *) value);
return r;
}