From: Niklas Hofmann Date: Sat, 9 Aug 2014 16:26:35 +0000 (+0200) Subject: class based connect behaviour X-Git-Url: https://git.meshlink.io/?a=commitdiff_plain;h=3b13c8881100e12d5a4bf184611188bcb57e7144;p=meshlink class based connect behaviour --- diff --git a/src/discovery.c b/src/discovery.c index b50aea8d..d17f962b 100644 --- a/src/discovery.c +++ b/src/discovery.c @@ -163,7 +163,6 @@ static void discovery_server_callback(AvahiServer *server, AvahiServerState stat { 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; @@ -347,7 +346,7 @@ static void discovery_browse_callback(AvahiSServiceBrowser *browser, AvahiIfInde 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: { diff --git a/src/meshlink.c b/src/meshlink.c index 7f009d94..95ab41c7 100644 --- a/src/meshlink.c +++ b/src/meshlink.c @@ -1706,7 +1706,7 @@ static void __attribute__((destructor)) meshlink_exit(void) { crypto_exit(); } -int weight_from_dclass(dclass_t dclass) +int cweight_from_dclass(dclass_t dclass) { switch(dclass) { @@ -1722,3 +1722,84 @@ int weight_from_dclass(dclass_t 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); +} diff --git a/src/meshlink_internal.h b/src/meshlink_internal.h index 63a71dc0..f7f0ba78 100644 --- a/src/meshlink_internal.h +++ b/src/meshlink_internal.h @@ -158,6 +158,17 @@ extern void meshlink_send_from_queue(event_loop_t* el,meshlink_handle_t *mesh); 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 diff --git a/src/net.c b/src/net.c index 4045c136..e5e80ae9 100644 --- a/src/net.c +++ b/src/net.c @@ -223,14 +223,32 @@ static void periodic_handler(event_loop_t *loop, void *data) { 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 */ @@ -240,14 +258,18 @@ static void periodic_handler(event_loop_t *loop, void *data) { 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. @@ -255,12 +277,12 @@ static void periodic_handler(event_loop_t *loop, void *data) { 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) { @@ -281,7 +303,7 @@ static void periodic_handler(event_loop_t *loop, void *data) { } } - if(nc >= autoconnect) { + if(satisfied) { /* If we have enough active connections, remove any pending outgoing connections. Do not remove pending connections to unreachable @@ -312,8 +334,10 @@ static void periodic_handler(event_loop_t *loop, void *data) { } } - 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}); diff --git a/src/net.h b/src/net.h index 6014a3d6..d2a60bcf 100644 --- a/src/net.h +++ b/src/net.h @@ -76,7 +76,6 @@ extern unsigned replaywin; 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" diff --git a/src/net_setup.c b/src/net_setup.c index 68b8ed74..3a14729a 100644 --- a/src/net_setup.c +++ b/src/net_setup.c @@ -32,8 +32,6 @@ #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; @@ -230,7 +228,6 @@ bool setup_myself_reloadable(meshlink_handle_t *mesh) { 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); @@ -383,8 +380,7 @@ bool setup_myself(meshlink_handle_t *mesh) { graph(mesh); - if(autoconnect) - load_all_nodes(mesh); + load_all_nodes(mesh); /* Open sockets */ diff --git a/src/protocol_auth.c b/src/protocol_auth.c index 76188f6e..65736253 100644 --- a/src/protocol_auth.c +++ b/src/protocol_auth.c @@ -444,7 +444,7 @@ bool ack_h(meshlink_handle_t *mesh, connection_t *c, const char *request) { 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;