/* 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); }