{
logger(mesh, MESHLINK_ERROR, "Avahi failed to set new host name: %s\n", avahi_strerror(result));
avahi_simple_poll_quit(mesh->avahi_poll);
- return;
}
}
break;
logger(mesh, MESHLINK_ERROR, "(Browser) %s\n", avahi_strerror(avahi_server_errno(mesh->avahi_server)));
avahi_simple_poll_quit(mesh->avahi_poll);
}
- return;
+ break;
case AVAHI_BROWSER_NEW:
{
crypto_exit();
}
-int weight_from_dclass(dclass_t dclass)
+int cweight_from_dclass(dclass_t dclass)
{
switch(dclass)
{
return 9;
}
+
+int max_ccount_from_dclass(dclass_t dclass)
+{
+ switch(dclass)
+ {
+ case BACKBONE:
+ return 10000;
+
+ case STATIONARY:
+ return 100;
+
+ case PORTABLE:
+ return 3;
+ }
+
+ return 3;
+}
+
+bool dclass_ccounts_satisfied(dclass_t dclass, splay_tree_t* counts, int total_count)
+{
+ // lookup keys
+ dclass_ccount_t key_portable;
+ key_portable.dclass = PORTABLE;
+
+ dclass_ccount_t key_stationary;
+ key_stationary.dclass = STATIONARY;
+
+ dclass_ccount_t key_backbone;
+ key_backbone.dclass = BACKBONE;
+
+ // check num of portable devices
+ dclass_ccount_t* portable = splay_search(counts, &key_portable);
+
+ if(portable)
+ {
+ if(portable->ccount > 9)
+ return true;
+ }
+
+ // check num of stationary devices
+ dclass_ccount_t* stationary = splay_search(counts, &key_stationary);
+
+ if(stationary)
+ {
+ if(stationary->ccount > 6)
+ return true;
+ }
+
+ // check num of backbone devices
+ dclass_ccount_t* backbone = splay_search(counts, &key_backbone);
+
+ if(backbone)
+ {
+ if(backbone->ccount > 3)
+ return true;
+ }
+
+ // fallback
+ if(total_count >= max_ccount_from_dclass(dclass))
+ return true;
+
+ return false;
+}
+
+int dclass_ccount_compare(const void *a, const void *b)
+{
+ const dclass_ccount_t* da = a;
+ const dclass_ccount_t* db = b;
+
+ return da->dclass - db->dclass;
+}
+
+dclass_ccount_t* dclass_ccount_alloc()
+{
+ return xzalloc(sizeof(dclass_ccount_t));
+}
+
+void dclass_ccount_delete(void *c)
+{
+ free(c);
+}
extern meshlink_log_level_t global_log_level;
extern meshlink_log_cb_t global_log_cb;
-extern int weight_from_dclass(dclass_t dclass);
+extern int cweight_from_dclass(dclass_t dclass);
+extern int max_ccount_from_dclass(dclass_t dclass);
+extern bool dclass_ccounts_satisfied(dclass_t dclass, splay_tree_t* counts, int total_count);
+
+typedef struct {
+ dclass_t dclass;
+ int ccount;
+} dclass_ccount_t;
+
+extern int dclass_ccount_compare(const void *a, const void *b);
+extern dclass_ccount_t* dclass_ccount_alloc();
+extern void dclass_ccount_delete(void *c);
#endif // MESHLINK_INTERNAL_H
int timeout = 5;
- /* If AutoConnect is set, check if we need to make or break connections. */
+ /* Check if we need to make or break connections. */
- if(autoconnect && mesh->nodes->count > 1) {
- /* Count number of active connections */
- int nc = 0;
+ if(mesh->nodes->count > 1) {
+
+ splay_tree_t* ccounts = splay_alloc_tree(dclass_ccount_compare, NULL);
+
+ /* Count number of active connections per device class */
+ int num_total = 0;
for list_each(connection_t, c, mesh->connections) {
if(c->status.active)
- nc++;
+ {
+ dclass_ccount_t key;
+ key.dclass = c->node->dclass;
+
+ dclass_ccount_t* ccount = splay_search(ccounts, &key);
+
+ if(!ccount)
+ {
+ ccount = dclass_ccount_alloc();
+ ccount->dclass = c->node->dclass;
+ splay_insert(ccounts, ccount);
+ }
+
+ ccount->ccount++;
+ num_total++;
+ }
}
/* Count number of unreachable nodes */
num_unreachable++;
}
- if(nc < autoconnect) {
+ bool satisfied = dclass_ccounts_satisfied(mesh->self->dclass, ccounts, num_total);
+
+ if(!satisfied) {
/* Not enough active connections, try to add one.
Choose a random node, if we don't have a connection to it,
and we are not already trying to make one, create an
outgoing connection to this node.
*/
cond_add_connection(mesh, mesh->nodes->count, &found_random_node);
- } else if(num_unreachable > 0) {
+ }
+
+ if(satisfied && num_unreachable > 0) {
/* Min number of connections established. Now try
to connect to some unreachable nodes to attempt
to heal possible partitions.
cond_add_connection(mesh, num_unreachable, &found_random_unreachable_node);
}
- if(nc > autoconnect) {
+ if(max_ccount_from_dclass(mesh->self->dclass) > num_total) {
/* Too many active connections, try to remove one.
Choose a random outgoing connection to a node
that has at least one other connection.
*/
- int r = rand() % nc;
+ int r = rand() % num_total;
int i = 0;
for list_each(connection_t, c, mesh->connections) {
}
}
- if(nc >= autoconnect) {
+ if(satisfied) {
/* If we have enough active connections,
remove any pending outgoing connections.
Do not remove pending connections to unreachable
}
}
- if (nc + mesh->outgoings->count < min(autoconnect, mesh->nodes->count - 1))
+ if (!satisfied && (num_total + mesh->outgoings->count) < mesh->nodes->count)
timeout = 0;
+
+ splay_free_tree(ccounts);
}
timeout_set(&mesh->loop, data, &(struct timeval){timeout, rand() % 100000});
extern int keylifetime;
extern int max_connection_burst;
extern bool do_prune;
-extern int autoconnect;
/* Yes, very strange placement indeed, but otherwise the typedefs get all tangled up */
#include "connection.h"
#include "utils.h"
#include "xalloc.h"
-int autoconnect = 3;
-
bool node_read_ecdsa_public_key(meshlink_handle_t *mesh, node_t *n) {
if(ecdsa_active(n->ecdsa))
return true;
mesh->localdiscovery = true;
keylifetime = 3600; // TODO: check if this can be removed as well
mesh->maxtimeout = 900;
- autoconnect = 3;
mesh->self->options |= OPTION_PMTU_DISCOVERY;
read_invitation_key(mesh);
graph(mesh);
- if(autoconnect)
- load_all_nodes(mesh);
+ load_all_nodes(mesh);
/* Open sockets */
sockaddr2str(&c->address, &hisaddress, NULL);
c->edge->address = str2sockaddr(hisaddress, hisport);
free(hisaddress);
- c->edge->weight = weight_from_dclass(dclass);
+ c->edge->weight = cweight_from_dclass(dclass);
c->edge->connection = c;
c->edge->options = c->options;