From: Niklas Hofmann Date: Tue, 12 Aug 2014 03:32:22 +0000 (+0200) Subject: converging auto connect algorithm X-Git-Url: https://git.meshlink.io/?a=commitdiff_plain;h=a021bf25db676353b8ea50740ce343962c3dddb9;p=meshlink converging auto connect algorithm --- diff --git a/examples/chat.c b/examples/chat.c index 3eaa5c7e..c6d67fb5 100644 --- a/examples/chat.c +++ b/examples/chat.c @@ -195,7 +195,7 @@ int main(int argc, char *argv[]) { meshlink_set_log_cb(NULL, MESHLINK_INFO, log_message); - meshlink_handle_t *mesh = meshlink_open(confbase, nick, "chat", STATIONARY); + meshlink_handle_t *mesh = meshlink_open(confbase, nick, "chat", DEV_CLASS_STATIONARY); if(!mesh) { fprintf(stderr, "Could not open MeshLink: %s\n", meshlink_strerror(meshlink_errno)); return 1; diff --git a/examples/chatpp.cc b/examples/chatpp.cc index e500ad27..331f6584 100644 --- a/examples/chatpp.cc +++ b/examples/chatpp.cc @@ -187,7 +187,7 @@ int main(int argc, char *argv[]) { if(argc > 2) nick = argv[2]; - ChatMesh* mesh = meshlink::open(confbase, nick, "chatpp", STATIONARY); + ChatMesh* mesh = meshlink::open(confbase, nick, "chatpp", DEV_CLASS_STATIONARY); if(!mesh) { fprintf(stderr, "Could not open MeshLink: %s\n", meshlink::strerror()); diff --git a/examples/manynodes.c b/examples/manynodes.c index 96aa5f0f..22ebad21 100644 --- a/examples/manynodes.c +++ b/examples/manynodes.c @@ -241,7 +241,7 @@ int main(int argc, char *argv[]) { snprintf(nodename, sizeof nodename, "%snode%d", namesprefix,i); snprintf(filename, sizeof filename, "%s/%s", basebase, nodename); bool itsnew = access(filename, R_OK); - mesh[i] = meshlink_open(filename, nodename, "manynodes", STATIONARY); + mesh[i] = meshlink_open(filename, nodename, "manynodes", DEV_CLASS_PORTABLE); meshlink_set_log_cb(mesh[i], MESHLINK_INFO, log_message); if(itsnew) meshlink_add_address(mesh[i], "localhost"); diff --git a/examples/meshlinkapp.c b/examples/meshlinkapp.c index 6c56165c..d9e5b7e0 100644 --- a/examples/meshlinkapp.c +++ b/examples/meshlinkapp.c @@ -14,7 +14,7 @@ int main(int argc , char **argv){ meshlink_handle_t* myhandle; - myhandle = meshlink_open(confbase, name, "meshlinkapp", STATIONARY); + myhandle = meshlink_open(confbase, name, "meshlinkapp", DEV_CLASS_STATIONARY); //Register callback function for incoming data meshlink_set_receive_cb(myhandle, (meshlink_receive_cb_t)handle_recv_data); diff --git a/src/meshlink++.h b/src/meshlink++.h index 8271ab2f..5f5539a2 100644 --- a/src/meshlink++.h +++ b/src/meshlink++.h @@ -387,8 +387,8 @@ namespace meshlink { * @return This function will return a pointer to a meshlink::mesh if MeshLink has succesfully set up its configuration files, NULL otherwise. */ template - static MESH* open(const char *confbase, const char *name, const char* appname, dclass_t dclass) { - void* mp = (void *)meshlink_open_with_size(confbase, name, appname, dclass, sizeof(MESH)); + static MESH* open(const char *confbase, const char *name, const char* appname, dev_class_t devclass) { + void* mp = (void *)meshlink_open_with_size(confbase, name, appname, devclass, sizeof(MESH)); return new (mp) MESH; } diff --git a/src/meshlink.c b/src/meshlink.c index 95ab41c7..3661f064 100644 --- a/src/meshlink.c +++ b/src/meshlink.c @@ -742,11 +742,11 @@ static bool meshlink_setup(meshlink_handle_t *mesh) { return true; } -meshlink_handle_t *meshlink_open(const char *confbase, const char *name, const char* appname, dclass_t dclass) { - return meshlink_open_with_size(confbase, name, appname, dclass, sizeof(meshlink_handle_t)); +meshlink_handle_t *meshlink_open(const char *confbase, const char *name, const char* appname, dev_class_t devclass) { + return meshlink_open_with_size(confbase, name, appname, devclass, sizeof(meshlink_handle_t)); } -meshlink_handle_t *meshlink_open_with_size(const char *confbase, const char *name, const char* appname, dclass_t dclass, size_t size) { +meshlink_handle_t *meshlink_open_with_size(const char *confbase, const char *name, const char* appname, dev_class_t devclass, size_t size) { // Validate arguments provided by the application bool usingname = false; @@ -776,10 +776,16 @@ meshlink_handle_t *meshlink_open_with_size(const char *confbase, const char *nam } else { usingname = true;} } + if(devclass < 0 || devclass > _DEV_CLASS_MAX) { + logger(NULL, MESHLINK_ERROR, "Invalid devclass given!\n"); + meshlink_errno = MESHLINK_EINVAL; + return NULL; + } + meshlink_handle_t *mesh = xzalloc(size); mesh->confbase = xstrdup(confbase); mesh->appname = xstrdup(appname); - mesh->dclass = dclass; + mesh->devclass = devclass; if (usingname) mesh->name = xstrdup(name); pthread_mutex_init ( &(mesh->nodes_mutex), NULL); mesh->threadstarted = false; @@ -1706,100 +1712,11 @@ static void __attribute__((destructor)) meshlink_exit(void) { crypto_exit(); } -int cweight_from_dclass(dclass_t dclass) -{ - switch(dclass) - { - case BACKBONE: - return 1; - - case STATIONARY: - return 3; - - case PORTABLE: - return 6; - } - - 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); -} +/// Device class +dev_class_traits_t dev_class_traits[_DEV_CLASS_MAX +1] = { + { .min_connects = 3, .max_connects = 10000, .edge_weight = 1 }, // DEV_CLASS_BACKBONE + { .min_connects = 3, .max_connects = 100, .edge_weight = 3 }, // DEV_CLASS_STATIONARY + { .min_connects = 3, .max_connects = 3, .edge_weight = 6 }, // DEV_CLASS_PORTABLE + { .min_connects = 1, .max_connects = 1, .edge_weight = 9 }, // DEV_CLASS_UNKNOWN +}; diff --git a/src/meshlink.h b/src/meshlink.h index 6858b5bc..9f6c63ce 100644 --- a/src/meshlink.h +++ b/src/meshlink.h @@ -65,12 +65,14 @@ typedef enum { MESHLINK_EPEER, ///< A peer caused an error } meshlink_errno_t; -// Device class +/// Device class typedef enum { - BACKBONE = 1, - STATIONARY = 2, - PORTABLE = 3 -} dclass_t; + DEV_CLASS_BACKBONE = 0, + DEV_CLASS_STATIONARY = 1, + DEV_CLASS_PORTABLE = 2, + DEV_CLASS_UNKNOWN = 3, + _DEV_CLASS_MAX = 3 +} dev_class_t; /// A variable holding the last encountered error from MeshLink. /** This is a thread local variable that contains the error code of the most recent error @@ -84,6 +86,8 @@ extern __thread meshlink_errno_t meshlink_errno; struct meshlink_handle { const char *name; + char *appname; + dev_class_t devclass; void *priv; }; @@ -130,15 +134,15 @@ extern const char *meshlink_strerror(meshlink_errno_t err); * After the function returns, the application is free to overwrite or free @a name @a. * @param appname The application name which will be used in the mesh. * After the function returns, the application is free to overwrite or free @a name @a. - * @param dclass The device class which will be used in the mesh. + * @param devclass The device class which will be used in the mesh. * * @return A pointer to a meshlink_handle_t which represents this instance of MeshLink, or NULL in case of an error. * The pointer is valid until meshlink_close() is called. */ -extern meshlink_handle_t *meshlink_open(const char *confbase, const char *name, const char* appname, dclass_t dclass); +extern meshlink_handle_t *meshlink_open(const char *confbase, const char *name, const char* appname, dev_class_t devclass); /// is used by the C++ wrapper to allocate more memory behind the handle -extern meshlink_handle_t *meshlink_open_with_size(const char *confbase, const char *name, const char* appname, dclass_t dclass, size_t size); +extern meshlink_handle_t *meshlink_open_with_size(const char *confbase, const char *name, const char* appname, dev_class_t devclass, size_t size); /// Start MeshLink. /** This function causes MeshLink to open network sockets, make outgoing connections, and diff --git a/src/meshlink_internal.h b/src/meshlink_internal.h index f7f0ba78..c1f3659d 100644 --- a/src/meshlink_internal.h +++ b/src/meshlink_internal.h @@ -64,7 +64,7 @@ typedef struct outpacketqueue { struct meshlink_handle { char *name; char *appname; - dclass_t dclass; + dev_class_t devclass; void *priv; char *confbase; @@ -158,17 +158,13 @@ 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 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); - +/// Device class typedef struct { - dclass_t dclass; - int ccount; -} dclass_ccount_t; + unsigned int min_connects; + unsigned int max_connects; + int edge_weight; +} dev_class_traits_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); +extern dev_class_traits_t dev_class_traits[]; #endif // MESHLINK_INTERNAL_H diff --git a/src/net.c b/src/net.c index ed129245..654a7813 100644 --- a/src/net.c +++ b/src/net.c @@ -31,6 +31,7 @@ #include "protocol.h" #include "xalloc.h" + static const int min(int a, int b) { return a < b ? a : b; } @@ -129,75 +130,61 @@ static void timeout_handler(event_loop_t *loop, void *data) { timeout_set(&mesh->loop, data, &(struct timeval){mesh->pingtimeout, rand() % 100000}); } -/// Utility function to establish connections based on condition check -/** The function iterates over all nodes, but skips those that do - * not pass the condition check. - * - * The condition check function is passed - * a pointer to a random number r between 0 and rand_modulo, a pointer to the - * current node index i, and the node pointer n. This function should return true - * if a connection attempt to the node should be made. - * - * @param mesh A pointer to the mesh structure - * @param rand_modulo Random index is selected between 0 and rand_modulo - * @cond_check A function pointer. This function should return true - * if a connection attempt to the node should be made - */ -static void cond_add_connection(meshlink_handle_t *mesh, int rand_modulo, bool (*cond_check)(int*, int*, node_t*)) { - int r = rand() % rand_modulo; - int i = 0; - - for splay_each(node_t, n, mesh->nodes) { - /* skip nodes that do not pass condition check */ - if(!(*cond_check)(&i, &r, n)) - continue; - - /* 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, n->name)) { - found = true; - break; - } - } +// devclass asc, last_connect_try desc +static int node_compare_devclass_asc_last_connect_try_desc(const void *a, const void *b) +{ + const node_t *na = a, *nb = b; - if(!found) { - //TODO: if the node is blacklisted the connection will not happen, but - //the user will read this debug message "Autoconnecting to %s" that is misleading - logger(mesh, MESHLINK_INFO, "Autoconnecting to %s", n->name); - outgoing_t *outgoing = xzalloc(sizeof *outgoing); - outgoing->mesh = mesh; - outgoing->name = xstrdup(n->name); - list_insert_tail(mesh->outgoings, outgoing); - setup_outgoing_connection(mesh, outgoing); - } - break; - } + if(na->devclass < nb->devclass) + { return -1; } + + if(na->devclass > nb->devclass) + { return 1; } + + if(na->last_connect_try == nb->last_connect_try) + return 0; + + if(nb->last_connect_try == 0 || na->last_connect_try < nb->last_connect_try) + return -1; + + if(na->last_connect_try == 0 || na->last_connect_try > nb->last_connect_try) + return 1; + + return 0; } -static bool found_random_node(int *i, int *r, node_t *n) { - if((*i)++ != *r) - return false; +// last_connect_try desc +static int node_compare_last_connect_try_desc(const void *a, const void *b) +{ + const node_t *na = a, *nb = b; + + if(na->last_connect_try == nb->last_connect_try) + return 0; - if(n->connection) - return false; - - return true; + if(nb->last_connect_try == 0 || na->last_connect_try < nb->last_connect_try) + return -1; + + if(na->last_connect_try == 0 || na->last_connect_try > nb->last_connect_try) + return 1; + + return 0; } -static bool found_random_unreachable_node(int *i, int *r, node_t *n) { - if(n->status.reachable) - return false; - - if((*i)++ != *r) - return false; +// devclass desc +static int node_compare_devclass_desc(const void *a, const void *b) +{ + const node_t *na = a, *nb = b; + + if(na->devclass < nb->devclass) + { return -1; } - if(n->connection) - return false; + if(na->devclass > nb->devclass) + { return 1; } - return true; + return 0; } + static void periodic_handler(event_loop_t *loop, void *data) { meshlink_handle_t *mesh = loop->data; @@ -229,127 +216,212 @@ static void periodic_handler(event_loop_t *loop, void *data) { logger(mesh, MESHLINK_INFO, "--- autoconnect begin ---"); - 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) + int retry_timeout = min(mesh->nodes->count * 5, 60); + + // connect disconnect nodes + + node_t* connect_to = NULL; + node_t* disconnect_from = NULL; + + + // get cur_connects + + int cur_connects = 0; + + for list_each(connection_t, c, mesh->connections) + { + if(!c->status.remove_unused) + { + cur_connects += 1; + } + } + + logger(mesh, MESHLINK_INFO, "* cur_connects = %d", cur_connects); + + + // get min_connects and max_connects + + int min_connects = dev_class_traits[mesh->devclass].min_connects; + int max_connects = dev_class_traits[mesh->devclass].max_connects; + + logger(mesh, MESHLINK_INFO, "* min_connects = %d", min_connects); + logger(mesh, MESHLINK_INFO, "* max_connects = %d", max_connects); + + + // find the best one for initial connect + + if(cur_connects < min_connects) + { + splay_tree_t *nodes = splay_alloc_tree(node_compare_devclass_asc_last_connect_try_desc, NULL); + + for splay_each(node_t, n, mesh->nodes) + { + if(n->devclass <= mesh->devclass && !n->connection && (n->last_connect_try == 0 || (time(NULL) - n->last_connect_try) > retry_timeout)) + { splay_insert(nodes, n); } + } + + if(nodes->head) { - dclass_ccount_t key; - key.dclass = c->node->dclass; + logger(mesh, MESHLINK_INFO, "* found best one for initial connect"); + + timeout = 0; + connect_to = (node_t*)nodes->head->data; + } + + splay_free_tree(nodes); + } + - dclass_ccount_t* ccount = splay_search(ccounts, &key); + // find better nodes to connect to + + if(!connect_to && min_connects <= cur_connects < max_connects) + { + unsigned int connects = 0; - if(!ccount) + for(int devclass = 0; devclass <= mesh->devclass; ++devclass) + { + for list_each(connection_t, c, mesh->connections) { - ccount = dclass_ccount_alloc(); - ccount->dclass = c->node->dclass; - splay_insert(ccounts, ccount); + if(!c->status.remove_unused && c->node && c->node->devclass == devclass) + { connects += 1; } } - ccount->ccount++; - num_total++; + if( connects < min_connects ) + { + splay_tree_t *nodes = splay_alloc_tree(node_compare_last_connect_try_desc, NULL); + + for splay_each(node_t, n, mesh->nodes) + { + if(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_INFO, "* found better node"); + connect_to = (node_t*)nodes->head->data; + + splay_free_tree(nodes); + break; + } + + splay_free_tree(nodes); + } + else + { break; } } } - /* Count number of unreachable nodes */ - int num_unreachable = 0; - for splay_each(node_t, n, mesh->nodes) { - if(!n->status.reachable) - num_unreachable++; - } - bool satisfied = dclass_ccounts_satisfied(mesh->self->dclass, ccounts, num_total); - int maxcc = max_ccount_from_dclass(mesh->self->dclass); + // heal partitions - logger(mesh, MESHLINK_INFO, "* num_total = %d, satisfied = %d, maxcc = %d", num_total, satisfied, maxcc); + if(!connect_to && min_connects <= cur_connects < max_connects) + { + splay_tree_t *nodes = splay_alloc_tree(node_compare_devclass_asc_last_connect_try_desc, NULL); - if(!satisfied) { - logger(mesh, MESHLINK_INFO, "* Not enough active connections, try to add one."); - /* 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); - } + for splay_each(node_t, n, mesh->nodes) + { + if(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_INFO, "* try to heal partition"); + connect_to = (node_t*)nodes->head->data; + } - if(satisfied && num_unreachable > 0) { - logger(mesh, MESHLINK_INFO, "* Min number of connections established. Now heal possible partitions."); - /* 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); + splay_free_tree(nodes); } - - if(num_total > maxcc) { - logger(mesh, MESHLINK_INFO, "* Too many active connections, try to remove one."); - /* 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() % num_total; - int i = 0; - - for list_each(connection_t, c, mesh->connections) { - if(!c->status.active) - continue; - if(i++ != r) - continue; - if(!c->outgoing || !c->node || c->node->edge_tree->count < 2) - break; + // perform connect - logger(mesh, MESHLINK_INFO, "Autodisconnecting from %s", c->name); - list_delete(mesh->outgoings, c->outgoing); - c->outgoing = NULL; - terminate_connection(mesh, c, c->status.active); - break; - } + if(connect_to && !connect_to->connection) + { + logger(mesh, MESHLINK_INFO, "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); } - if(satisfied) { - logger(mesh, MESHLINK_INFO, "* We have enough active connections, remove pending outgoing connections."); - /* If we have enough active connections, - remove any pending outgoing connections. - Do not remove pending connections to unreachable - nodes. - */ - node_t *o_node = NULL; - for list_each(outgoing_t, o, mesh->outgoings) { - o_node = lookup_node(mesh, o->name); - /* o_node is NULL if it is not part of the graph yet */ - if(!o_node || !o_node->status.reachable) - continue; - bool found = false; - for list_each(connection_t, c, mesh->connections) { - if(c->outgoing == o) { - found = true; - break; - } + // disconnect suboptimal outgoing connections + + if(min_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.remove_unused && c->node && c->node->devclass == devclass) + { connects += 1; } } - if(!found) { - logger(mesh, MESHLINK_INFO, "Cancelled outgoing connection to %s", o->name); - /* The node variable is leaked in from using the list_each macro. - The o variable could be used, but using node directly - is more efficient. - */ - list_delete_node(mesh->outgoings, node); + + 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->status.remove_unused && c->outgoing && c->node && c->node->devclass >= devclass) + { splay_insert(nodes, c->node); } + } + + if(nodes->head) + { + logger(mesh, MESHLINK_INFO, "* disconnect suboptimal outgoing connection"); + disconnect_from = (node_t*)nodes->head->data; + } + + splay_free_tree(nodes); + break; } } } - if (!satisfied && (num_total + mesh->outgoings->count) < mesh->nodes->count) + + // 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.remove_unused && c->node) + { splay_insert(nodes, c->node); } + } + + if(nodes->head) + { + logger(mesh, MESHLINK_INFO, "* disconnect connection (too many connections"); + + timeout = 0; + disconnect_from = (node_t*)nodes->head->data; + } + + splay_free_tree(nodes); + } + + + // perform disconnect + + if(disconnect_from && disconnect_from->connection) { - logger(mesh, MESHLINK_INFO, "* No timeout."); - timeout = 0; + logger(mesh, MESHLINK_INFO, "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); } - splay_free_tree(ccounts); + + // done! logger(mesh, MESHLINK_INFO, "--- autoconnect end ---"); } diff --git a/src/net_setup.c b/src/net_setup.c index 3a14729a..fd438674 100644 --- a/src/net_setup.c +++ b/src/net_setup.c @@ -122,8 +122,8 @@ static bool read_invitation_key(meshlink_handle_t *mesh) { return mesh->invitation_key; } -bool node_read_dclass(meshlink_handle_t *mesh, node_t *n) { - if(n->dclass != 0) +bool node_read_devclass(meshlink_handle_t *mesh, node_t *n) { + if(n->devclass != 0) return true; splay_tree_t *config_tree; @@ -133,19 +133,23 @@ bool node_read_dclass(meshlink_handle_t *mesh, node_t *n) { if(!read_host_config(mesh, config_tree, n->name)) goto exit; - if(get_config_string(lookup_config(config_tree, "DeviceClass"), &p)) { - n->dclass = atoi(p); + if(get_config_string(lookup_config(config_tree, "DeviceClass"), &p)) + { + n->devclass = atoi(p); free(p); } + if(n->devclass < 0 || n->devclass > _DEV_CLASS_MAX) + { n->devclass = _DEV_CLASS_MAX; } + exit: exit_configuration(&config_tree); - return n->dclass != 0; + return n->devclass != 0; } -bool node_write_dclass(meshlink_handle_t *mesh, node_t *n) { +bool node_write_devclass(meshlink_handle_t *mesh, node_t *n) { - if(n->dclass == 0) + if(n->devclass == 0) return false; bool result = false; @@ -165,7 +169,7 @@ bool node_write_dclass(meshlink_handle_t *mesh, node_t *n) { config_add(config_tree, cnf); } - set_config_int(cnf, n->dclass); + set_config_int(cnf, n->devclass); if(!write_host_config(mesh, config_tree, n->name)) goto fail; @@ -199,7 +203,7 @@ void load_all_nodes(meshlink_handle_t *mesh) { n = new_node(); n->name = xstrdup(ent->d_name); - node_read_dclass(mesh, n); + node_read_devclass(mesh, n); node_add(mesh, n); } @@ -329,7 +333,7 @@ bool setup_myself(meshlink_handle_t *mesh) { mesh->self = new_node(); mesh->self->connection = new_connection(); mesh->self->name = name; - mesh->self->dclass = mesh->dclass; + mesh->self->devclass = mesh->devclass; mesh->self->connection->name = xstrdup(name); read_host_config(mesh, mesh->config, name); diff --git a/src/node.h b/src/node.h index 2ece66c5..23237522 100644 --- a/src/node.h +++ b/src/node.h @@ -41,7 +41,7 @@ typedef struct node_status_t { typedef struct node_t { char *name; /* name of this node */ uint32_t options; /* options turned on for this node */ - dclass_t dclass; + dev_class_t devclass; struct meshlink_handle *mesh; /* The mesh this node belongs to */ @@ -67,6 +67,7 @@ typedef struct node_t { struct splay_tree_t *edge_tree; /* Edges with this node as one of the endpoints */ struct connection_t *connection; /* Connection associated with this node (if a direct connection exists) */ + time_t last_connect_try; uint32_t sent_seqno; /* Sequence number last sent to this node */ uint32_t received_seqno; /* Sequence number last received from this node */ diff --git a/src/protocol_auth.c b/src/protocol_auth.c index 65736253..82254593 100644 --- a/src/protocol_auth.c +++ b/src/protocol_auth.c @@ -37,7 +37,7 @@ #include "xalloc.h" #include "ed25519/sha512.h" -extern bool node_write_dclass(meshlink_handle_t *mesh, node_t *n); +extern bool node_write_devclass(meshlink_handle_t *mesh, node_t *n); static bool send_proxyrequest(meshlink_handle_t *mesh, connection_t *c) { switch(mesh->proxytype) { @@ -360,7 +360,7 @@ bool send_ack(meshlink_handle_t *mesh, connection_t *c) { if(mesh->self->options & OPTION_PMTU_DISCOVERY) c->options |= OPTION_PMTU_DISCOVERY; - return send_request(mesh, c, "%d %s %d %x", ACK, mesh->myport, mesh->dclass, (c->options & 0xffffff) | (PROT_MINOR << 24)); + return send_request(mesh, c, "%d %s %d %x", ACK, mesh->myport, mesh->devclass, (c->options & 0xffffff) | (PROT_MINOR << 24)); } static void send_everything(meshlink_handle_t *mesh, connection_t *c) { @@ -375,16 +375,22 @@ static void send_everything(meshlink_handle_t *mesh, connection_t *c) { bool ack_h(meshlink_handle_t *mesh, connection_t *c, const char *request) { char hisport[MAX_STRING_SIZE]; char *hisaddress; - int dclass; + int devclass; uint32_t options; node_t *n; - if(sscanf(request, "%*d " MAX_STRING " %d %x", hisport, &dclass, &options) != 3) { + if(sscanf(request, "%*d " MAX_STRING " %d %x", hisport, &devclass, &options) != 3) { logger(mesh, MESHLINK_ERROR, "Got bad %s from %s (%s)", "ACK", c->name, c->hostname); return false; } + if(devclass < 0 || devclass > _DEV_CLASS_MAX) { + logger(mesh, MESHLINK_ERROR, "Got bad %s from %s (%s): %s", "ACK", c->name, + c->hostname, "devclass invalid"); + return false; + } + /* Check if we already have a node_t for him */ n = lookup_node(mesh, c->name); @@ -413,8 +419,8 @@ bool ack_h(meshlink_handle_t *mesh, connection_t *c, const char *request) { } } - n->dclass = dclass; - node_write_dclass(mesh, n); + n->devclass = devclass; + node_write_devclass(mesh, n); n->connection = c; c->node = n; @@ -444,7 +450,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 = cweight_from_dclass(dclass); + c->edge->weight = dev_class_traits[devclass].edge_weight; c->edge->connection = c; c->edge->options = c->options; diff --git a/src/protocol_edge.c b/src/protocol_edge.c index d09a7877..89ed901d 100644 --- a/src/protocol_edge.c +++ b/src/protocol_edge.c @@ -33,7 +33,7 @@ #include "utils.h" #include "xalloc.h" -extern bool node_write_dclass(meshlink_handle_t *mesh, node_t *n); +extern bool node_write_devclass(meshlink_handle_t *mesh, node_t *n); bool send_add_edge(meshlink_handle_t *mesh, connection_t *c, const edge_t *e) { bool x; @@ -42,7 +42,7 @@ bool send_add_edge(meshlink_handle_t *mesh, connection_t *c, const edge_t *e) { sockaddr2str(&e->address, &address, &port); x = send_request(mesh, c, "%d %x %s %d %s %s %s %d %x %d", ADD_EDGE, rand(), - e->from->name, e->from->dclass, e->to->name, address, port, e->to->dclass, + e->from->name, e->from->devclass, e->to->name, address, port, e->to->devclass, e->options, e->weight); free(address); free(port); @@ -54,17 +54,17 @@ bool add_edge_h(meshlink_handle_t *mesh, connection_t *c, const char *request) { edge_t *e; node_t *from, *to; char from_name[MAX_STRING_SIZE]; - int from_dclass; + int from_devclass; char to_name[MAX_STRING_SIZE]; char to_address[MAX_STRING_SIZE]; char to_port[MAX_STRING_SIZE]; - int to_dclass; + int to_devclass; sockaddr_t address; uint32_t options; int weight; if(sscanf(request, "%*d %*x "MAX_STRING" %d "MAX_STRING" "MAX_STRING" "MAX_STRING" %d %x %d", - from_name, &from_dclass, to_name, to_address, to_port, &to_dclass, &options, &weight) != 8) { + from_name, &from_devclass, to_name, to_address, to_port, &to_devclass, &options, &weight) != 8) { logger(mesh, MESHLINK_ERROR, "Got bad %s from %s (%s)", "ADD_EDGE", c->name, c->hostname); return false; @@ -78,6 +78,20 @@ bool add_edge_h(meshlink_handle_t *mesh, connection_t *c, const char *request) { return false; } + // Check if devclasses are valid + + if(from_devclass < 0 || from_devclass > _DEV_CLASS_MAX) { + logger(mesh, MESHLINK_ERROR, "Got bad %s from %s (%s): %s", "ADD_EDGE", c->name, + c->hostname, "from devclass invalid"); + return false; + } + + if(to_devclass < 0 || to_devclass > _DEV_CLASS_MAX) { + logger(mesh, MESHLINK_ERROR, "Got bad %s from %s (%s): %s", "ADD_EDGE", c->name, + c->hostname, "to devclass invalid"); + return false; + } + if(seen_request(mesh, request)) return true; @@ -92,8 +106,8 @@ bool add_edge_h(meshlink_handle_t *mesh, connection_t *c, const char *request) { node_add(mesh, from); } - from->dclass = from_dclass; - node_write_dclass(mesh, from); + from->devclass = from_devclass; + node_write_devclass(mesh, from); if(!to) { to = new_node(); @@ -101,8 +115,8 @@ bool add_edge_h(meshlink_handle_t *mesh, connection_t *c, const char *request) { node_add(mesh, to); } - to->dclass = to_dclass; - node_write_dclass(mesh, to); + to->devclass = to_devclass; + node_write_devclass(mesh, to); /* Convert addresses */