+int ack_h(connection_t *c)
+{
+ port_t port;
+ int weight;
+ node_t *n;
+ subnet_t *s;
+ edge_t *e;
+ connection_t *other;
+ avl_node_t *node, *node2;
+cp
+ if(sscanf(c->buffer, "%*d %hd %d", &port, &weight) != 2)
+ {
+ syslog(LOG_ERR, _("Got bad %s from %s (%s)"), "ACK", c->name, c->hostname);
+ return -1;
+ }
+
+ /* Check if we already have a node_t for him */
+
+ n = lookup_node(c->name);
+
+ if(!n)
+ {
+ n = new_node();
+ n->name = xstrdup(c->name);
+ n->address = c->address;
+ n->hostname = xstrdup(c->hostname);
+ n->port = port;
+
+ /* FIXME: Also check if no other tinc daemon uses the same IP and port for UDP traffic */
+
+ node_add(n);
+ }
+ else
+ {
+ if(n->connection)
+ {
+ /* Oh dear, we already have a connection to this node. */
+ syslog(LOG_DEBUG, _("Established a second connection with %s (%s), closing old connection"), n->name, n->hostname);
+ terminate_connection(n->connection, 0);
+ }
+
+ /* FIXME: check if information in existing node matches that of the other end of this connection */
+ }
+
+ n->connection = c;
+ c->node = n;
+
+ /* Check some options
+
+ if((cfg = get_config_val(c->config, config_indirectdata)))
+ {
+ if(cfg->data.val == stupid_true)
+ c->options |= OPTION_INDIRECT;
+ }
+
+ if((cfg = get_config_val(c->config, config_tcponly)))
+ {
+ if(cfg->data.val == stupid_true)
+ c->options |= OPTION_TCPONLY;
+ }
+
+ if((myself->options | c->options) & OPTION_INDIRECT)
+ c->via = myself;
+ else
+ c->via = c;
+
+ */
+
+ /* Create an edge_t for this connection */
+
+ c->edge = new_edge();
+
+ c->edge->from = myself;
+ c->edge->to = n;
+ c->edge->weight = (weight + c->estimated_weight) / 2;
+ c->edge->connection = c;
+
+ edge_add(c->edge);
+
+ /* Activate this connection */
+
+ c->allow_request = ALL;
+ c->status.active = 1;
+ c->node->cipher = EVP_bf_cbc();
+ c->node->keylength = c->node->cipher->key_len + c->node->cipher->iv_len;
+
+ if(debug_lvl >= DEBUG_CONNECTIONS)
+ syslog(LOG_NOTICE, _("Connection with %s (%s) activated"), c->name, c->hostname);
+
+cp
+ /* Send him our subnets */
+
+ for(node = myself->subnet_tree->head; node; node = node->next)
+ {
+ s = (subnet_t *)node->data;
+ send_add_subnet(c, s);
+ }
+
+ /* And send him all known nodes and their subnets */
+
+ for(node = node_tree->head; node; node = node->next)
+ {
+ n = (node_t *)node->data;
+
+ if(n == c->node || n == myself)
+ continue;
+
+ send_add_node(c, n);
+
+ for(node2 = c->node->subnet_tree->head; node2; node2 = node2->next)
+ {
+ s = (subnet_t *)node2->data;
+ send_add_subnet(c, s);
+ }
+ }
+
+ /* Send all known edges */
+
+ for(node = edge_tree->head; node; node = node->next)
+ {
+ e = (edge_t *)node->data;
+
+ if(e == c->edge)
+ continue;
+
+ send_add_edge(c, e);
+ }
+
+ /* Notify others of this connection */
+
+ for(node = connection_tree->head; node; node = node->next)
+ {
+ other = (connection_t *)node->data;
+
+ if(other == c)
+ continue;
+
+ send_add_node(other, c->node);
+ send_add_edge(other, c->edge);
+ }
+
+ /* Run MST and SSSP algorithms */
+
+ mst_kruskal();
+ sssp_bfs(0);
+cp
+ return 0;
+}
+
+
+
+/* Address and subnet information exchange */
+
+int send_add_subnet(connection_t *c, subnet_t *subnet)