-RETSIGTYPE
-try_outgoing_connections(int a)
-{
- static config_t *cfg = NULL;
- static int retry = 0;
- char *name;
-cp
- if(!cfg)
- cfg = lookup_config(config_tree, "ConnectTo");
-
- if(!cfg)
- return;
-
- while(cfg)
- {
- get_config_string(cfg, &name);
-
- if(check_id(name))
- {
- syslog(LOG_ERR, _("Invalid name for outgoing connection in %s line %d"), cfg->file, cfg->line);
- continue;
- }
-
- if(setup_outgoing_connection(name)) /* function returns 0 when there are no problems */
- retry = 1;
-
- cfg = lookup_config_next(config_tree, cfg); /* Next time skip to next ConnectTo line */
- }
-
- get_config_int(lookup_config(config_tree, "MaxTimeout"), &maxtimeout);
-
- if(retry)
- {
- seconds_till_retry += 5;
- if(seconds_till_retry > maxtimeout) /* Don't wait more than MAXTIMEOUT seconds. */
- seconds_till_retry = maxtimeout;
-
- syslog(LOG_ERR, _("Failed to setup any outgoing connection, will retry in %d seconds"),
- seconds_till_retry);
-
- /* Randomize timeout to avoid global synchronisation effects */
- randomized_alarm(seconds_till_retry);
- }
- else
- {
- seconds_till_retry = 5;
- }
-cp
+ for splay_each(node_t, n, mesh->nodes)
+ {
+ if(n != mesh->self && n->devclass == devclass && !n->connection && (n->last_connect_try == 0 || (time(NULL) - n->last_connect_try) > retry_timeout))
+ { splay_insert(nodes, n); }
+ }
+
+ if(nodes->head)
+ {
+ logger(mesh, MESHLINK_DEBUG, "* found better node");
+ connect_to = (node_t*)nodes->head->data;
+
+ splay_free_tree(nodes);
+ break;
+ }
+
+ splay_free_tree(nodes);
+ }
+ else
+ { break; }
+ }
+
+ if(!connect_to)
+ { logger(mesh, MESHLINK_DEBUG, "* could not find better nodes"); }
+ }
+
+
+ // heal partitions
+
+ if(!connect_to && min_connects <= cur_connects && cur_connects < max_connects)
+ {
+ splay_tree_t *nodes = splay_alloc_tree(node_compare_devclass_asc_lsc_desc, NULL);
+
+ for splay_each(node_t, n, mesh->nodes)
+ {
+ if(n != mesh->self && n->devclass <= mesh->devclass && !n->status.reachable && (n->last_connect_try == 0 || (time(NULL) - n->last_connect_try) > retry_timeout))
+ { splay_insert(nodes, n); }
+ }
+
+ if(nodes->head)
+ {
+ logger(mesh, MESHLINK_DEBUG, "* try to heal partition");
+ connect_to = (node_t*)nodes->head->data;
+ }
+ else
+ { logger(mesh, MESHLINK_DEBUG, "* could not find nodes for partition healing"); }
+
+ splay_free_tree(nodes);
+ }
+
+
+ // perform connect
+
+ if(connect_to && !connect_to->connection)
+ {
+ connect_to->last_connect_try = time(NULL);
+
+ /* check if there is already a connection attempt to this node */
+ bool found = false;
+ for list_each(outgoing_t, outgoing, mesh->outgoings)
+ {
+ if(!strcmp(outgoing->name, connect_to->name))
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if(!found)
+ {
+ logger(mesh, MESHLINK_DEBUG, "Autoconnecting to %s", connect_to->name);
+ outgoing_t *outgoing = xzalloc(sizeof(outgoing_t));
+ outgoing->mesh = mesh;
+ outgoing->name = xstrdup(connect_to->name);
+ list_insert_tail(mesh->outgoings, outgoing);
+ setup_outgoing_connection(mesh, outgoing);
+ }
+ else
+ { logger(mesh, MESHLINK_DEBUG, "* skip autoconnect since it is an outgoing connection already"); }
+ }
+
+
+ // disconnect suboptimal outgoing connections
+
+ if(min_connects < cur_connects /*&& cur_connects <= max_connects*/)
+ {
+ unsigned int connects = 0;
+
+ for(int devclass = 0; devclass <= mesh->devclass; ++devclass)
+ {
+ for list_each(connection_t, c, mesh->connections)
+ {
+ if(c->status.active && c->node && c->node->devclass == devclass)
+ { connects += 1; }
+ }
+
+ if( min_connects < connects )
+ {
+ splay_tree_t *nodes = splay_alloc_tree(node_compare_devclass_desc, NULL);
+
+ for list_each(connection_t, c, mesh->connections)
+ {
+ if(c->outgoing && c->node && c->node->devclass >= devclass)
+ { splay_insert(nodes, c->node); }
+ }
+
+ if(nodes->head)
+ {
+ logger(mesh, MESHLINK_DEBUG, "* disconnect suboptimal outgoing connection");
+ disconnect_from = (node_t*)nodes->head->data;
+ }
+
+ splay_free_tree(nodes);
+ break;
+ }
+ }
+
+ if(!disconnect_from)
+ { logger(mesh, MESHLINK_DEBUG, "* no suboptimal outgoing connections"); }
+ }
+
+
+ // disconnect connections (too many connections)
+
+ if(!disconnect_from && max_connects < cur_connects)
+ {
+ splay_tree_t *nodes = splay_alloc_tree(node_compare_devclass_desc, NULL);
+
+ for list_each(connection_t, c, mesh->connections)
+ {
+ if(c->status.active && c->node)
+ { splay_insert(nodes, c->node); }
+ }
+
+ if(nodes->head)
+ {
+ logger(mesh, MESHLINK_DEBUG, "* disconnect connection (too many connections)");
+
+ //timeout = 0;
+ disconnect_from = (node_t*)nodes->head->data;
+ }
+ else
+ { logger(mesh, MESHLINK_DEBUG, "* no node we want to disconnect, even though we have too many connections"); }
+
+ splay_free_tree(nodes);
+ }
+
+
+ // perform disconnect
+
+ if(disconnect_from && disconnect_from->connection)
+ {
+ logger(mesh, MESHLINK_DEBUG, "Autodisconnecting from %s", disconnect_from->connection->name);
+ list_delete(mesh->outgoings, disconnect_from->connection->outgoing);
+ disconnect_from->connection->outgoing = NULL;
+ terminate_connection(mesh, disconnect_from->connection, disconnect_from->connection->status.active);
+ }
+
+
+ // done!
+
+ logger(mesh, MESHLINK_DEBUG, "--- autoconnect end ---");
+ }
+
+ timeout_set(&mesh->loop, data, &(struct timeval){timeout, rand() % 100000});