+static int node_udp_compare(const node_t *a, const node_t *b) {
+ return sockaddrcmp(&a->address, &b->address);
+}
+
+void init_nodes(void) {
+ node_tree = avl_alloc_tree((avl_compare_t) node_compare, (avl_action_t) free_node);
+ node_udp_tree = avl_alloc_tree((avl_compare_t) node_udp_compare, NULL);
+}
+
+void exit_nodes(void) {
+ avl_delete_tree(node_udp_tree);
+ avl_delete_tree(node_tree);
+}
+
+node_t *new_node(void) {
+ node_t *n = xmalloc_and_zero(sizeof(*n));
+
+ if(replaywin) n->late = xmalloc_and_zero(replaywin);
+ n->subnet_tree = new_subnet_tree();
+ n->edge_tree = new_edge_tree();
+ EVP_CIPHER_CTX_init(&n->inctx);
+ EVP_CIPHER_CTX_init(&n->outctx);
+ n->mtu = MTU;
+ n->maxmtu = MTU;
+
+ return n;
+}
+
+void free_node(node_t *n) {
+ if(n->inkey)
+ free(n->inkey);
+
+ if(n->outkey)
+ free(n->outkey);
+
+ if(n->subnet_tree)
+ free_subnet_tree(n->subnet_tree);
+
+ if(n->edge_tree)
+ free_edge_tree(n->edge_tree);
+
+ sockaddrfree(&n->address);
+
+ EVP_CIPHER_CTX_cleanup(&n->inctx);
+ EVP_CIPHER_CTX_cleanup(&n->outctx);
+
+ if(n->mtuevent)
+ event_del(n->mtuevent);
+
+ if(n->hostname)
+ free(n->hostname);
+
+ if(n->name)
+ free(n->name);
+
+ if(n->late)
+ free(n->late);
+
+ free(n);