/* BTP library - Banana Tree Protocol
* Copyright (C) 1999-2001 The Regents of the University of Michigan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "btp_node.h"
#include "btp_debug.h"
static void node_delete (BtpNode* node);
/* **************************************** */
BtpTree*
btp_tree_new (BPeer* peer, GURL* url)
{
BtpTree* tree;
tree = g_new0 (BtpTree, 1);
tree->group.peer = peer;
tree->group.url = url;
return tree;
}
/*
Delete the BTP tree. Nodes may still be around at the end of this
call, but we the only callbacks we should get are write callbacks.
Last checked: ???
*/
void
btp_tree_delete (BtpTree* tree)
{
GSList* i;
g_return_if_fail (tree);
g_return_if_fail (!tree->is_deleting);
BTPP (1, "btp_tree_delete %p\n", tree);
tree->is_deleting = TRUE;
/* Delete the children and siblings lists */
g_slist_free (tree->children);
g_slist_free (tree->siblings);
tree->children = NULL;
tree->siblings = NULL;
tree->shortcuts = NULL;
/* Delete all nodes. Note that the nodes may not be deleted until
their out queues are empty. Send packet needs 'me' to determine
the port, so we delete it last. */
for (i = tree->nodes; i != NULL; )
{
BtpNode* node = (BtpNode*) i->data;
i = i->next; /* node might be deleted */
g_return_if_fail(node);
if (node != tree->me)
node_delete (node);
}
node_delete (tree->me);
g_slist_free(tree->nodes);
tree->nodes = NULL;
if (tree->switch_timeout)
g_source_remove(tree->switch_timeout);
if (tree->request_neighbors_timeout)
g_source_remove(tree->request_neighbors_timeout);
if (tree->find_new_parent_timeout)
g_source_remove(tree->find_new_parent_timeout);
if (tree->find_new_shortcut_timeout)
g_source_remove(tree->find_new_shortcut_timeout);
if (tree->send_node_info_timeout)
g_source_remove(tree->send_node_info_timeout);
/* Zero myself out to be safe */
memset(tree, 0, sizeof(*tree));
g_free(tree);
}
static void
node_delete (BtpNode* node)
{
gboolean delete_done;
/* If the delete is delayed (so that the connection can be closed,
then remove all references to the tree/group. */
delete_done = btp_node_delete(node);
if (!delete_done)
{
node->tree = NULL;
if (node->conn)
node->conn->group = NULL;
}
}
/* **************************************** */
void
btp_tree_print (FILE* file, BtpTree* tree)
{
gchar* url_str;
GSList* i;
g_return_if_fail (tree);
fprintf (file, "\nBtpTree\n");
url_str = gnet_url_get_nice_string(tree->group.url);
fprintf (file, "url: %s\n", url_str);
g_free (url_str);
fprintf (file, "passive: %d\n", tree->passive);
fprintf (file, "sw-to: %d\n", tree->switch_timeout != 0);
fprintf (file, "rn-to: %d\n", tree->request_neighbors_timeout != 0);
fprintf (file, "fnp-to: %d\n", tree->find_new_parent_timeout != 0);
fprintf (file, "fns-to: %d\n", tree->find_new_shortcut_timeout != 0);
fprintf (file, "sni-to: %d\n", tree->send_node_info_timeout != 0);
fprintf (file, "\n");
fprintf (file, "ME:\n");
btp_node_print (file, tree->me);
fprintf (file, "\nROOT:\n");
btp_node_print (file, tree->root);
fprintf (file, "\nPARENT:\n");
btp_node_print (file, tree->parent);
fprintf (file, "\nGPARENT:\n");
btp_node_print (file, tree->gparent);
fprintf (file, "\nNEW_PARENT:\n");
btp_node_print (file, tree->new_parent);
fprintf (file, "\n");
fprintf (file, "CHILDREN: \n");
for (i = tree->children; i != NULL; i = i->next)
{
btp_node_print (file, (BtpNode*) i->data);
fprintf (file, "\n");
}
fprintf (file, "\n");
fprintf (file, "SIBLINGS: \n");
for (i = tree->siblings; i != NULL; i = i->next)
{
btp_node_print (file, (BtpNode*) i->data);
fprintf (file, "\n");
}
fprintf (file, "\n");
fprintf (file, "SHORTCUTS: \n");
for (i = tree->shortcuts; i != NULL; i = i->next)
{
btp_node_print (file, (BtpNode*) i->data);
fprintf (file, "\n");
}
fprintf (file, "\n");
fprintf (file, "NODES: \n");
for (i = tree->nodes; i != NULL; i = i->next)
{
btp_node_print (file, (BtpNode*) i->data);
fprintf (file, "\n");
}
fprintf (file, "\n");
}
/* **************************************** */
gboolean
btp_tree_is_me (BtpNode* node)
{
g_return_val_if_fail (node, FALSE);
g_return_val_if_fail (node->tree, FALSE);
return (node->tree->me == node);
}
gboolean
btp_tree_is_root (BtpNode* node)
{
g_return_val_if_fail (node, FALSE);
g_return_val_if_fail (node->tree, FALSE);
return (node->tree->root == node);
}
gboolean
btp_tree_is_parent (BtpNode* node)
{
g_return_val_if_fail (node, FALSE);
g_return_val_if_fail (node->tree, FALSE);
return (node->tree->parent == node);
}
gboolean
btp_tree_is_gparent (BtpNode* node)
{
g_return_val_if_fail (node, FALSE);
g_return_val_if_fail (node->tree, FALSE);
return (node->tree->gparent == node);
}
gboolean
btp_tree_is_sibling (BtpNode* node)
{
g_return_val_if_fail (node, FALSE);
g_return_val_if_fail (node->tree, FALSE);
return (g_slist_find(node->tree->siblings, node) != NULL);
}
gboolean
btp_tree_is_child (BtpNode* node)
{
g_return_val_if_fail (node, FALSE);
g_return_val_if_fail (node->tree, FALSE);
return (g_slist_find(node->tree->children, node) != NULL);
}
gboolean
btp_tree_is_shortcut (BtpNode* node)
{
g_return_val_if_fail (node, FALSE);
g_return_val_if_fail (node->tree, FALSE);
return (g_slist_find(node->tree->shortcuts, node) != NULL);
}
gboolean
btp_tree_is_new_parent (BtpNode* node)
{
g_return_val_if_fail (node, FALSE);
g_return_val_if_fail (node->tree, FALSE);
return (node->tree->new_parent == node);
}
gboolean
btp_tree_is_one_hop (BtpNode* node)
{
g_return_val_if_fail (node, FALSE);
g_return_val_if_fail (node->tree, FALSE);
return (node == node->tree->parent ||
g_slist_find(node->tree->children, node) != NULL);
}
gboolean
btp_tree_is_two_hop (BtpNode* node)
{
g_return_val_if_fail (node, FALSE);
g_return_val_if_fail (node->tree, FALSE);
return (node == node->tree->gparent ||
g_slist_find(node->tree->siblings, node) != NULL);
}
gboolean
btp_tree_is_tree_neighbor (BtpNode* node)
{
if ( btp_tree_is_child (node) ||
btp_tree_is_parent (node) )
return TRUE;
return FALSE;
}
gboolean
btp_tree_is_mesh_neighbor (BtpNode* node)
{
if ( btp_tree_is_tree_neighbor(node) ||
btp_tree_is_shortcut(node) )
return TRUE;
return FALSE;
}
gchar*
btp_tree_relation_to_string (BtpNode* node)
{
static gchar* relation_to_string[] =
{
"me",
"root",
"parent",
"gparent",
"child",
"sibling",
"none"
};
if (btp_tree_is_me(node))
return relation_to_string[0];
else if (btp_tree_is_root(node))
return relation_to_string[1];
else if (btp_tree_is_parent(node))
return relation_to_string[2];
else if (btp_tree_is_gparent(node))
return relation_to_string[3];
else if (btp_tree_is_child(node))
return relation_to_string[4];
else if (btp_tree_is_sibling(node))
return relation_to_string[5];
return relation_to_string[6];
}
/* ********** */
void
btp_tree_add_sibling (BtpNode* node)
{
g_return_if_fail (node);
g_return_if_fail (node->tree);
g_return_if_fail (node != node->tree->me);
if (!g_slist_find(node->tree->siblings, node))
node->tree->siblings = g_slist_prepend (node->tree->siblings, node);
}
void
btp_tree_remove_sibling (BtpNode* node)
{
g_return_if_fail (node);
g_return_if_fail (node->tree);
node->tree->siblings = g_slist_remove (node->tree->siblings, node);
}
void
btp_tree_add_child (BtpNode* node)
{
g_return_if_fail (node);
g_return_if_fail (node->tree);
g_return_if_fail (node != node->tree->me);
if (!g_slist_find(node->tree->children, node))
node->tree->children = g_slist_prepend (node->tree->children, node);
}
void
btp_tree_remove_child (BtpNode* node)
{
g_return_if_fail (node);
g_return_if_fail (node->tree);
node->tree->children = g_slist_remove (node->tree->children, node);
}
void
btp_tree_add_shortcut (BtpNode* node)
{
g_return_if_fail (node);
g_return_if_fail (node->tree);
g_return_if_fail (node != node->tree->me);
if (!g_slist_find(node->tree->shortcuts, node))
node->tree->shortcuts = g_slist_prepend (node->tree->shortcuts, node);
}
void
btp_tree_remove_shortcut (BtpNode* node)
{
g_return_if_fail (node);
g_return_if_fail (node->tree);
node->tree->shortcuts = g_slist_remove (node->tree->shortcuts, node);
}
guint
btp_tree_degree (BtpTree* tree)
{
guint degree = 0;
g_return_val_if_fail (tree, 0);
if (tree->parent)
degree++;
degree += g_slist_length (tree->children);
degree += g_slist_length (tree->shortcuts);
return degree;
}
guint
btp_tree_parent_degree (BtpTree* tree)
{
g_return_val_if_fail (tree, 0);
if (!tree->parent)
return 0;
return (tree->root != tree->parent)?1:0 /* parent's parent */ +
1 /* me */ +
g_slist_length (tree->siblings);
}
gboolean
btp_tree_is_node (BtpNode* node)
{
g_return_val_if_fail (node, FALSE);
g_return_val_if_fail (node->tree, FALSE);
return (g_slist_find(node->tree->nodes, node) != NULL);
}
void
btp_tree_add_node (BtpNode* node)
{
g_return_if_fail (node);
g_return_if_fail (node->tree);
if (!g_slist_find(node->tree->nodes, node))
node->tree->nodes = g_slist_prepend (node->tree->nodes, node);
}
void
btp_tree_remove_node (BtpNode* node)
{
g_return_if_fail (node);
g_return_if_fail (node->tree);
node->tree->nodes = g_slist_remove (node->tree->nodes, node);
}
BtpNode*
btp_tree_find_node (BtpTree* tree, gchar* hostname, gint port)
{
GSList* i;
g_return_val_if_fail (tree, NULL);
g_return_val_if_fail (hostname, NULL);
for (i = tree->nodes; i != NULL; i = i->next)
{
BtpNode* node = (BtpNode*) i->data;
g_return_val_if_fail (node, NULL);
g_return_val_if_fail (node->hostname, NULL);
if (port == node->port &&
strcmp(hostname, node->hostname) == 0)
return node;
}
return NULL;
}
/* ******************** */
void
btp_tree_send_mcast (BtpTree* tree, const void* buffer, guint16 length)
{
BPacket* pkt;
g_return_if_fail (tree);
g_return_if_fail (buffer);
pkt = b_packet_new_mcast (NULL, buffer, length);
pkt->seq = g_htons(tree->group.seq_num++);
pkt->source_id = g_htonl(tree->group.source_id);
btp_tree_forward_mcast (tree, NULL, pkt);
b_packet_delete (pkt);
}
void
btp_tree_forward_mcast (BtpTree* tree, BtpNode* not_node, BPacket* pkt)
{
GSList* i;
g_return_if_fail (tree);
g_return_if_fail (pkt);
/* Forward to other nodes */
# define SEND_PKT(N) do{ \
if ((N) != not_node) { \
BPacket* cpkt = b_packet_clone (pkt); \
g_assert ((N)->conn); \
cpkt->id = (N)->conn->out_conn_id; \
b_conn_send_packet ((N)->conn, cpkt); } } while(0)
/* Send to parent */
if (tree->parent)
SEND_PKT (tree->parent);
/* Send to children */
for (i = tree->children; i != NULL; i = i->next)
SEND_PKT ((BtpNode*) i->data);
/* Send to shortcuts */
for (i = tree->shortcuts; i != NULL; i = i->next)
SEND_PKT ((BtpNode*) i->data);
# undef SEND_PACKET
}
void
btp_tree_send_ucast (BtpTree* tree, BtpNode* node, const void* buffer, guint16 length)
{
BPacket* packet;
g_return_if_fail (tree);
g_return_if_fail (node);
g_return_if_fail (buffer);
packet = b_packet_new_ucast (node->conn, buffer, length);
b_conn_send_packet (node->conn, packet);
}
syntax highlighted by Code2HTML, v. 0.9.1