예제 #1
0
static void
tree_node_debug (struct MeshTunnelTreeNode *n, uint16_t level)
{
  struct MeshTunnelTreeNode *c;
  struct GNUNET_PeerIdentity id;;
  uint16_t i;

  for (i = 0; i < level; i++)
    FPRINTF (stderr, "%s",  "  ");
  if (n->status == MESH_PEER_READY)
    FPRINTF (stderr, "%s",  "#");
  if (n->status == MESH_PEER_SEARCHING)
    FPRINTF (stderr, "%s",  "+");
  if (n->status == MESH_PEER_RELAY)
    FPRINTF (stderr, "%s",  "-");
  if (n->status == MESH_PEER_RECONNECTING)
    FPRINTF (stderr, "%s",  "*");

  GNUNET_PEER_resolve (n->peer, &id);
  FPRINTF (stderr, "%s, [%u, %p] ", GNUNET_i2s (&id), n->peer, n);
  if (NULL != n->parent)
  {
    GNUNET_PEER_resolve (n->parent->peer, &id);
    FPRINTF (stderr, "(-> %s [%u])\n", GNUNET_i2s (&id), n->parent->peer);
  }
  else
    FPRINTF (stderr, "%s",  "(root)\n");
  for (c = n->children_head; NULL != c; c = c->next)
    tree_node_debug (c, level + 1);
}
예제 #2
0
/**
 * Delete the current path to the peer, including all now unused relays.
 * The destination peer is NOT destroyed, it is returned in order to either set
 * a new path to it or destroy it explicitly, taking care of it's child nodes.
 *
 * @param t Tunnel tree where to delete the path from.
 * @param peer_id Short ID of the destination peer whose path we want to remove.
 * @param cb Callback to use to notify about disconnected peers.
 * @param cbcls Closure for cb.
 *
 * @return pointer to the pathless node.
 *         NULL when not found
 */
struct MeshTunnelTreeNode *
tree_del_path (struct MeshTunnelTree *t, GNUNET_PEER_Id peer_id,
               MeshTreeCallback cb, void *cbcls)
{
  struct MeshTunnelTreeNode *parent;
  struct MeshTunnelTreeNode *node;
  struct MeshTunnelTreeNode *n;

#if MESH_TREE_DEBUG
  struct GNUNET_PeerIdentity id;

  GNUNET_PEER_resolve (peer_id, &id);
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree:   Deleting path to %s.\n",
              GNUNET_i2s (&id));
#endif
  if (peer_id == t->root->peer)
    return NULL;

  for (n = t->disconnected_head; NULL != n; n = n->next)
  {
    if (n->peer == peer_id)
    {
      /* Was already pathless, waiting for reconnection */
      GNUNET_CONTAINER_DLL_remove (t->disconnected_head, t->disconnected_tail,
                                   n);
      return n;
    }
  }
  n = tree_find_peer (t, peer_id);
  if (NULL == n)
    return NULL;
  node = n;

  parent = n->parent;
  GNUNET_CONTAINER_DLL_remove (parent->children_head, parent->children_tail, n);
  n->parent = NULL;

  while (MESH_PEER_RELAY == parent->status && NULL == parent->children_head)
  {
#if MESH_TREE_DEBUG
    GNUNET_PEER_resolve (parent->peer, &id);
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree:   Deleting node %s.\n",
                GNUNET_i2s (&id));
#endif
    n = parent->parent;
    tree_node_destroy (parent);
    parent = n;
  }
#if MESH_TREE_DEBUG
  GNUNET_PEER_resolve (parent->peer, &id);
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree:   Not deleted peer %s.\n",
              GNUNET_i2s (&id));
#endif

  tree_mark_peers_disconnected (t, node, cb, cbcls);

  return node;
}
예제 #3
0
/**
 * Recusively update the info about what is the first hop to reach the node
 *
 * @param tree Tree this nodes belongs to.
 * @param parent ID from node form which to start updating.
 * @param hop If known, ID of the first hop.
 *            If not known, NULL to find out and pass on children.
 */
static void
tree_node_update_first_hops (struct MeshTunnelTree *tree,
                             struct MeshTunnelTreeNode *parent,
                             struct GNUNET_PeerIdentity *hop)
{
  struct GNUNET_PeerIdentity pi;
  struct GNUNET_PeerIdentity *copy;
  struct GNUNET_PeerIdentity id;
  struct MeshTunnelTreeNode *n;

#if MESH_TREE_DEBUG
  GNUNET_PEER_resolve (parent->peer, &id);
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree:   Finding first hop for %s.\n",
              GNUNET_i2s (&id));
#endif
  if (NULL == hop)
  {
    struct MeshTunnelTreeNode *aux;
    struct MeshTunnelTreeNode *old;

    aux = old = parent;
    while (aux != tree->me)
    {
#if MESH_TREE_DEBUG
      GNUNET_PEER_resolve (aux->peer, &id);
      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree:   ... checking %s.\n",
                  GNUNET_i2s (&id));
#endif
      old = aux;
      aux = aux->parent;
      GNUNET_assert (NULL != aux);
    }
#if MESH_TREE_DEBUG
    GNUNET_PEER_resolve (old->peer, &id);
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree:   It's %s!\n",
                GNUNET_i2s (&id));
#endif
    hop = &pi;
    GNUNET_PEER_resolve (old->peer, hop);
  }
  GNUNET_PEER_resolve (parent->peer, &id);
  copy = GNUNET_CONTAINER_multihashmap_get (tree->first_hops, &id.hashPubKey);
  if (NULL == copy)
    copy = GNUNET_malloc (sizeof (struct GNUNET_PeerIdentity));
  *copy = *hop;

  (void) GNUNET_CONTAINER_multihashmap_put (tree->first_hops, &id.hashPubKey,
                                            copy,
                                            GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);

  for (n = parent->children_head; NULL != n; n = n->next)
  {
    tree_node_update_first_hops (tree, n, hop);
  }
}
예제 #4
0
/**
 * Recusively mark peer and children as disconnected, notify client
 *
 * @param tree Tree this node belongs to
 * @param parent Node to be clean, potentially with children
 * @param cb Callback to use to notify about disconnected peers.
 * @param cbcls Closure for cb.
 */
static void
tree_mark_peers_disconnected (struct MeshTunnelTree *tree,
                              struct MeshTunnelTreeNode *parent,
                              MeshTreeCallback cb, void *cbcls)
{
  struct GNUNET_PeerIdentity *pi;
  struct GNUNET_PeerIdentity id;
  struct MeshTunnelTreeNode *n;

  for (n = parent->children_head; NULL != n; n = n->next)
  {
    tree_mark_peers_disconnected (tree, n, cb, cbcls);
  }
  if (MESH_PEER_READY == parent->status)
  {
    if (NULL != cb)
      cb (cbcls, parent->peer);
    parent->status = MESH_PEER_RECONNECTING;
  }

  /* Remove and free info about first hop */
  GNUNET_PEER_resolve (parent->peer, &id);
  pi = GNUNET_CONTAINER_multihashmap_get (tree->first_hops, &id.hashPubKey);
  GNUNET_CONTAINER_multihashmap_remove_all (tree->first_hops, &id.hashPubKey);
  if (NULL != pi)
    GNUNET_free (pi);
}
예제 #5
0
/**
 * Find the first peer whom to send a packet to go down this path
 *
 * @param t The tunnel tree to use
 * @param peer The peerinfo of the peer we are trying to reach
 *
 * @return peerinfo of the peer who is the first hop in the tunnel
 *         NULL on error
 * 
 * FIXME use PEER_Id
 */
struct GNUNET_PeerIdentity *
tree_get_first_hop (struct MeshTunnelTree *t, GNUNET_PEER_Id peer)
{
  struct GNUNET_PeerIdentity id;
  struct GNUNET_PeerIdentity *r;

  GNUNET_PEER_resolve (peer, &id);
  r = GNUNET_CONTAINER_multihashmap_get (t->first_hops, &id.hashPubKey);
  if (NULL == r)
  {
    struct MeshTunnelTreeNode *n;

    n = tree_find_peer (t, peer);
    if (NULL != t->me && NULL != n)
    {
      tree_node_update_first_hops (t, n, NULL);
      r = GNUNET_CONTAINER_multihashmap_get (t->first_hops, &id.hashPubKey);
      GNUNET_assert (NULL != r);
    }
    else
    {
      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                  "Tree structure inconsistent! me: %p, n: %p", t->me, n);
      GNUNET_break (0);
    }
  }

  return r;
}
예제 #6
0
/**
 * Destroys and frees the node and all children
 *
 * @param parent Parent node to be destroyed
 */
static void
tree_node_destroy (struct MeshTunnelTreeNode *parent)
{
  struct MeshTunnelTreeNode *n;
  struct MeshTunnelTreeNode *next;

#if MESH_TREE_DEBUG
  struct GNUNET_PeerIdentity id;

  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree: Destroying node %u\n",
              parent->peer);
  GNUNET_PEER_resolve (parent->peer, &id);
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree:   (%s)\n", GNUNET_i2s (&id));
#endif
  n = parent->children_head;
  while (NULL != n)
  {
    next = n->next;
    tree_node_destroy (n);
    n = next;
  }
  GNUNET_PEER_change_rc (parent->peer, -1);
  if (NULL != parent->parent)
    GNUNET_CONTAINER_DLL_remove (parent->parent->children_head,
                                 parent->parent->children_tail, parent);
  GNUNET_free (parent);
}
예제 #7
0
/**
 * Integrate a stand alone path into the tunnel tree.
 * If the peer toward which the new path is already in the tree, the peer
 * and its children will be maked as disconnected and the callback
 * will be called on each one of them. They will be maked as online only after
 * receiving a PATH ACK for the new path for each one of them, so the caller
 * should take care of sending a new CREATE PATH message for each disconnected
 * peer.
 *
 * @param t Tunnel where to add the new path.
 * @param p Path to be integrated.
 * @param cb Callback to use to notify about peers temporarily disconnecting.
 * @param cbcls Closure for cb.
 *
 * @return GNUNET_OK in case of success.
 *         GNUNET_SYSERR in case of error.
 *
 * TODO: optimize
 * - go backwards on path looking for each peer in the present tree
 * - do not disconnect peers until new path is created & connected
 */
int
tree_add_path (struct MeshTunnelTree *t, const struct MeshPeerPath *p,
               MeshTreeCallback cb, void *cbcls)
{
  struct MeshTunnelTreeNode *parent;
  struct MeshTunnelTreeNode *oldnode;
  struct MeshTunnelTreeNode *n;
  struct MeshTunnelTreeNode *c;
  struct GNUNET_PeerIdentity id;
  int me;
  unsigned int i;

#if MESH_TREE_DEBUG
  GNUNET_PEER_resolve (p->peers[p->length - 1], &id);
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "tree:   Adding path [%u] towards peer %s.\n", p->length,
              GNUNET_i2s (&id));
#endif

  GNUNET_assert (0 != p->length);
  parent = n = t->root;
  if (n->peer != p->peers[0])
  {
    GNUNET_break (0);
    return GNUNET_SYSERR;
  }
  if (1 == p->length)
    return GNUNET_OK;
  oldnode = tree_del_path (t, p->peers[p->length - 1], cb, cbcls);
  /* Look for the first node that is not already present in the tree
   *
   * Assuming that the tree is somewhat balanced, O(log n * log N).
   * - Length of the path is expected to be log N (size of whole network).
   * - Each level of the tree is expected to have log n children (size of tree).
   */
  me = t->root->peer == 1 ? 0 : -1;
  for (i = 1; i < p->length; i++)
  {
#if MESH_TREE_DEBUG
    GNUNET_PEER_resolve (p->peers[i], &id);
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree:   Looking for peer %s.\n",
                GNUNET_i2s (&id));
#endif
    parent = n;
    if (p->peers[i] == 1)
      me = i;
    for (c = n->children_head; NULL != c; c = c->next)
    {
      if (c->peer == p->peers[i])
      {
#if MESH_TREE_DEBUG
        GNUNET_PEER_resolve (parent->peer, &id);
        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                    "tree:   Found in children of %s.\n", GNUNET_i2s (&id));
#endif
        n = c;
        break;
      }
    }
    /*  If we couldn't find a child equal to path[i], we have reached the end
     * of the common path. */
    if (parent == n)
      break;
  }
#if MESH_TREE_DEBUG
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree:   All childen visited.\n");
#endif
  /* Add the rest of the path as a branch from parent. */
  while (i < p->length)
  {
#if MESH_TREE_DEBUG
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree:   Adding peer %u to %u.\n",
                p->peers[i], parent->peer);
    GNUNET_PEER_resolve (p->peers[i], &id);
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree:   Adding peer %s.\n",
                GNUNET_i2s (&id));
    GNUNET_PEER_resolve (parent->peer, &id);
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree:            to %s.\n",
                GNUNET_i2s (&id));
#endif

    if (i == p->length - 1 && NULL != oldnode)
    {
#if MESH_TREE_DEBUG
      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                  "tree:   Putting old node into place.\n");
#endif
      oldnode->parent = parent;
      GNUNET_CONTAINER_DLL_insert (parent->children_head, parent->children_tail,
                                   oldnode);
      tree_node_update_first_hops (t, oldnode, NULL);
      n = oldnode;
    }
    else
    {
#if MESH_TREE_DEBUG
      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree:   Creating new node.\n");
#endif
      n = tree_node_new (parent, p->peers[i]);
      n->status = MESH_PEER_RELAY;
    }
    if (n->peer == 1)
    {
      t->me = n;
      me = i;
    }
    i++;
    parent = n;
  }
  n->status = MESH_PEER_SEARCHING;

  GNUNET_break (-1 != me);

  /* Add info about first hop into hashmap. */
  if (-1 != me && me < p->length - 1)
  {
#if MESH_TREE_DEBUG
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                "MESH:   finding first hop (own pos %d/%u)\n", me,
                p->length - 1);
#endif
    GNUNET_PEER_resolve (p->peers[me + 1], &id);
    tree_update_first_hops (t, p->peers[me + 1], &id);
  }
#if MESH_TREE_DEBUG
  else
  {
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                "MESH:   was last in path, not updating first hops (%d/%u)\n",
                me, p->length - 1);
  }
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "tree:   New node added.\n");
#endif
  if (NULL == t->me)
    t->me = tree_find_peer (t, 1);
  return GNUNET_OK;
}
예제 #8
0
static int
check ()
{
  int i;
  GNUNET_PEER_Id pid;
  struct GNUNET_PeerIdentity res;
  struct GNUNET_PeerIdentity zero;
  GNUNET_PEER_Id ids[] = { 1, 2, 3 };

  GNUNET_assert (0 == GNUNET_PEER_intern (NULL));
  /* Insert Peers into PeerEntry table and hashmap */
  for (i = 0; i < NUMBER_OF_PEERS; i++)
  {
    pid = GNUNET_PEER_intern (&pidArr[i]);
    if (pid != (i + 1))
    {
      FPRINTF (stderr, "%s",  "Unexpected Peer ID returned by intern function\n");
      return 1;
    }
  }

  /* Referencing the first 3 peers once again */
  for (i = 0; i < 3; i++)
  {
    pid = GNUNET_PEER_intern (&pidArr[i]);
    if (pid != (i + 1))
    {
      FPRINTF (stderr, "%s",  "Unexpected Peer ID returned by intern function\n");
      return 1;
    }
  }

  /* Dereferencing the first 3 peers once [decrementing their reference count] */
  GNUNET_PEER_decrement_rcs (ids, 3);

  /* re-referencing the first 3 peers using the change_rc function */
  for (i = 1; i <= 3; i++)
    GNUNET_PEER_change_rc (i, 1);

  /* Removing the second Peer from the PeerEntry hash map */
  GNUNET_PEER_change_rc (2, -2);

  /* convert the pid of the first PeerEntry into that of the third */
  GNUNET_PEER_resolve (1, &res);
  GNUNET_assert (0 == memcmp (&res, &pidArr[0], sizeof (res)));

  /*
   * Attempt to convert pid = 0 (which is reserved)
   * into a peer identity object, the peer identity memory
   * is expected to be set to zero
   */
  memset (&zero, 0, sizeof (struct GNUNET_PeerIdentity));
  GNUNET_log_skip (1, GNUNET_YES);
  GNUNET_PEER_resolve (0, &res);
  GNUNET_assert (0 == memcmp (&res, &zero, sizeof (res)));

  /* Removing peer entries 1 and 3 from table using the list decrement function */
  /* If count = 0, nothing should be done whatsoever */
  GNUNET_PEER_decrement_rcs (ids, 0);

  ids[1] = 3;
  GNUNET_PEER_decrement_rcs (ids, 2);
  GNUNET_PEER_decrement_rcs (ids, 2);

  return 0;
}