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;
if(argc > 2)
nick = argv[2];
- ChatMesh* mesh = meshlink::open<ChatMesh>(confbase, nick, "chatpp", STATIONARY);
+ ChatMesh* mesh = meshlink::open<ChatMesh>(confbase, nick, "chatpp", DEV_CLASS_STATIONARY);
if(!mesh) {
fprintf(stderr, "Could not open MeshLink: %s\n", meshlink::strerror());
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");
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);
* @return This function will return a pointer to a meshlink::mesh if MeshLink has succesfully set up its configuration files, NULL otherwise.
*/
template<class MESH>
- 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;
}
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;
} 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;
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
+};
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
struct meshlink_handle {
const char *name;
+ char *appname;
+ dev_class_t devclass;
void *priv;
};
* 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
struct meshlink_handle {
char *name;
char *appname;
- dclass_t dclass;
+ dev_class_t devclass;
void *priv;
char *confbase;
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
#include "protocol.h"
#include "xalloc.h"
+
static const int min(int a, int b) {
return a < b ? a : b;
}
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;
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 ---");
}
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;
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;
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;
n = new_node();
n->name = xstrdup(ent->d_name);
- node_read_dclass(mesh, n);
+ node_read_devclass(mesh, n);
node_add(mesh, n);
}
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);
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 */
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 */
#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) {
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) {
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);
}
}
- n->dclass = dclass;
- node_write_dclass(mesh, n);
+ n->devclass = devclass;
+ node_write_devclass(mesh, n);
n->connection = c;
c->node = n;
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;
#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;
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);
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;
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;
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();
node_add(mesh, to);
}
- to->dclass = to_dclass;
- node_write_dclass(mesh, to);
+ to->devclass = to_devclass;
+ node_write_devclass(mesh, to);
/* Convert addresses */