X-Git-Url: http://git.meshlink.io/?a=blobdiff_plain;f=src%2Fmeshlink.c;h=ef02580ea93d641059eb203c7e3a8a17b14c1ab9;hb=7d0d06e82233623ce90c70dac2803a7f299c673e;hp=acb4b0fb1802d10c9bbf556bdedbd5591770371b;hpb=49b8d045d498574b51913be05ea1e9a41609b6e1;p=meshlink diff --git a/src/meshlink.c b/src/meshlink.c index acb4b0fb..ef02580e 100644 --- a/src/meshlink.c +++ b/src/meshlink.c @@ -48,8 +48,6 @@ typedef struct { #define MSG_NOSIGNAL 0 #endif -static pthread_mutex_t global_mutex; - __thread meshlink_errno_t meshlink_errno; meshlink_log_cb_t global_log_cb; meshlink_log_level_t global_log_level; @@ -503,8 +501,10 @@ static bool finalize_join(meshlink_handle_t *mesh) { } char *b64key = ecdsa_get_base64_public_key(mesh->self->connection->ecdsa); - if(!b64key) + if(!b64key) { + fclose(fh); return false; + } fprintf(fh, "ECDSAPublicKey = %s\n", b64key); fprintf(fh, "Port = %s\n", mesh->myport); @@ -554,6 +554,7 @@ static bool invitation_receive(void *handle, uint8_t type, const void *msg, uint break; case 1: + mesh->thedatalen = 0; return finalize_join(mesh); case 2: @@ -742,11 +743,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; @@ -778,10 +779,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); // initialize mutex @@ -866,6 +873,8 @@ bool meshlink_start(meshlink_handle_t *mesh) { logger(mesh, MESHLINK_DEBUG, "meshlink_start called\n"); + mesh->thedatalen = 0; + // TODO: open listening sockets first //Check that a valid name is set @@ -1703,7 +1712,7 @@ char *meshlink_export(meshlink_handle_t *mesh) { fclose(f); buf[len - 1] = 0; - pthread_mutex_lock(&(mesh->mesh_mutex)); + pthread_mutex_unlock(&(mesh->mesh_mutex)); return buf; } @@ -1814,7 +1823,7 @@ void meshlink_whitelist(meshlink_handle_t *mesh, meshlink_node_t *node) { /* Hint that a hostname may be found at an address * See header file for detailed comment. */ -extern void meshlink_hint_address(meshlink_handle_t *mesh, meshlink_node_t *node, const struct sockaddr *addr) { +void meshlink_hint_address(meshlink_handle_t *mesh, meshlink_node_t *node, const struct sockaddr *addr) { if(!mesh || !node || !addr) return; @@ -1825,7 +1834,10 @@ extern void meshlink_hint_address(meshlink_handle_t *mesh, meshlink_node_t *node if(host && port) { xasprintf(&str, "%s %s", host, port); - append_config_file(mesh, node->name, "Address", str); + if ( (strncmp ("fe80",host,4) != 0) && ( strncmp("127.",host,4) != 0 ) && ( strcmp("localhost",host) !=0 ) ) + append_config_file(mesh, node->name, "Address", str); + else + logger(mesh, MESHLINK_DEBUG, "Not adding Link Local IPv6 Address to config\n"); } free(str); @@ -1836,27 +1848,155 @@ extern void meshlink_hint_address(meshlink_handle_t *mesh, meshlink_node_t *node // @TODO do we want to fire off a connection attempt right away? } -static void __attribute__((constructor)) meshlink_init(void) { - crypto_init(); +/* Return an array of edges in the current network graph. + * Data captures the current state and will not be updated. + * Caller must deallocate data when done. + */ +meshlink_edge_t **meshlink_get_all_edges_state(meshlink_handle_t *mesh, meshlink_edge_t **edges, size_t *nmemb) { + if(!mesh || !nmemb || (*nmemb && !edges)) { + meshlink_errno = MESHLINK_EINVAL; + return NULL; + } + + pthread_mutex_lock(&(mesh->mesh_mutex)); + + meshlink_edge_t **result = NULL; + meshlink_edge_t *copy = NULL; + int result_size = 0; + + result_size = mesh->edges->count; + + // if result is smaller than edges, we have to dealloc all the excess meshlink_edge_t + if(result_size > *nmemb) { + result = realloc(edges, result_size * sizeof (meshlink_edge_t*)); + } else { + result = edges; + } + + if(result) { + meshlink_edge_t **p = result; + int n = 0; + for splay_each(edge_t, e, mesh->edges) { + // skip edges that do not represent a two-directional connection + if((!e->reverse) || (e->reverse->to != e->from)) { + result_size--; + continue; + } + n++; + // the first *nmemb members of result can be re-used + if(n > *nmemb) { + copy = xzalloc(sizeof *copy); + } + else { + copy = *p; + } + copy->from = (meshlink_node_t*)e->from; + copy->to = (meshlink_node_t*)e->to; + copy->address = e->address.storage; + copy->options = e->options; + copy->weight = e->weight; + *p++ = copy; + } + // shrink result to the actual amount of memory used + for(int i = *nmemb; i > result_size; i--) { + free(result[i - 1]); + } + result = realloc(result, result_size * sizeof (meshlink_edge_t*)); + *nmemb = result_size; + } else { + *nmemb = 0; + free(result); + meshlink_errno = MESHLINK_ENOMEM; + } + + pthread_mutex_unlock(&(mesh->mesh_mutex)); + + return result; } -static void __attribute__((destructor)) meshlink_exit(void) { - crypto_exit(); +static bool channel_pre_accept(struct utcp *utcp, uint16_t port) { + //TODO: implement + return false; } -int weight_from_dclass(dclass_t dclass) -{ - switch(dclass) - { - case BACKBONE: - return 1; +static void channel_accept(struct utcp_connection *utcp_connection, uint16_t port) { + //TODO: implement +} - case STATIONARY: - return 3; +static int channel_recv(struct utcp_connection *connection, const void *data, size_t len) { + meshlink_channel_t *channel = connection->priv; + node_t *n = channel->node; + meshlink_handle_t *mesh = n->mesh; + if(!channel->receive_cb) + return -1; + else { + channel->receive_cb(mesh, channel, data, len); + return 0; + } +} + +static int channel_send(struct utcp *utcp, const void *data, size_t len) { + node_t *n = utcp->priv; + meshlink_handle_t *mesh = n->mesh; + return meshlink_send(mesh, (meshlink_node_t *)n, data, len) ? len : -1; +} + +void meshlink_set_channel_accept_cb(meshlink_handle_t *mesh, meshlink_channel_accept_cb_t cb) { + mesh->channel_accept_cb = cb; +} - case PORTABLE: - return 6; +void meshlink_set_channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, meshlink_channel_receive_cb_t cb) { + channel->receive_cb = cb; +} + +meshlink_channel_t *meshlink_channel_open(meshlink_handle_t *mesh, meshlink_node_t *node, uint16_t port, meshlink_channel_receive_cb_t cb, const void *data, size_t len) { + node_t *n = (node_t *)node; + if(!n->utcp) { + n->utcp = utcp_init(channel_accept, channel_pre_accept, channel_send, n); + if(!n->utcp) + return NULL; } + meshlink_channel_t *channel = xzalloc(sizeof *channel); + channel->node = n; + channel->receive_cb = cb; + channel->c = utcp_connect(n->utcp, port, channel_recv, channel); + if(!channel->c) { + free(channel); + return NULL; + } + return channel; +} + +void meshlink_channel_shutdown(meshlink_handle_t *mesh, meshlink_channel_t *channel, int direction) { + utcp_shutdown(channel->c, direction); +} + +void meshlink_channel_close(meshlink_handle_t *mesh, meshlink_channel_t *channel) { + utcp_close(channel->c); + free(channel); +} + +ssize_t meshlink_channel_send(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *data, size_t len) { + // TODO: locking. + // Ideally we want to put the data into the UTCP connection's send buffer. + // Then, preferrably only if there is room in the receiver window, + // kick the meshlink thread to go send packets. + return utcp_send(channel->c, data, len); +} - return 9; +static void __attribute__((constructor)) meshlink_init(void) { + crypto_init(); } + +static void __attribute__((destructor)) meshlink_exit(void) { + crypto_exit(); +} + + +/// Device class traits +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 +};