X-Git-Url: http://git.meshlink.io/?a=blobdiff_plain;f=src%2Fmeshlink.c;h=4538548d97a17baf46739925b983d8876c4995b6;hb=c6cc7da56d108f05ea6f9a2f765f699e6e2353db;hp=9011879312ea34b27a5bb0833782640ab1372ea8;hpb=42e9341c12c630ebe3a550a4ce813aac4b1b047c;p=meshlink diff --git a/src/meshlink.c b/src/meshlink.c index 90118793..4538548d 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 @@ -1001,7 +1010,10 @@ void meshlink_set_log_cb(meshlink_handle_t *mesh, meshlink_log_level_t level, me } bool meshlink_send(meshlink_handle_t *mesh, meshlink_node_t *destination, const void *data, size_t len) { - if(!mesh || !destination) { + meshlink_packethdr_t *hdr; + + // Validate arguments + if(!mesh || !destination || len >= MAXSIZE - sizeof *hdr) { meshlink_errno = MESHLINK_EINVAL; return false; } @@ -1014,59 +1026,45 @@ bool meshlink_send(meshlink_handle_t *mesh, meshlink_node_t *destination, const return false; } - pthread_mutex_lock(&(mesh->mesh_mutex)); + // Prepare the packet + vpn_packet_t *packet = malloc(sizeof *packet); + if(!packet) { + meshlink_errno = MESHLINK_ENOMEM; + return false; + } - //add packet to the queue - outpacketqueue_t *packet_in_queue = xzalloc(sizeof *packet_in_queue); - packet_in_queue->destination=destination; - packet_in_queue->data=data; - packet_in_queue->len=len; - if(!meshlink_queue_push(&mesh->outpacketqueue, packet_in_queue)) { - free(packet_in_queue); - pthread_mutex_unlock(&(mesh->mesh_mutex)); + packet->probe = false; + packet->tcp = false; + packet->len = len + sizeof *hdr; + + hdr = (meshlink_packethdr_t *)packet->data; + memset(hdr, 0, sizeof *hdr); + memcpy(hdr->destination, destination->name, sizeof hdr->destination); + memcpy(hdr->source, mesh->self->name, sizeof hdr->source); + + memcpy(packet->data + sizeof *hdr, data, len); + + // Queue it + if(!meshlink_queue_push(&mesh->outpacketqueue, packet)) { + free(packet); + meshlink_errno = MESHLINK_ENOMEM; return false; } - //notify event loop + // Notify event loop signal_trigger(&(mesh->loop),&(mesh->datafromapp)); - pthread_mutex_unlock(&(mesh->mesh_mutex)); return true; } -void meshlink_send_from_queue(event_loop_t* el,meshlink_handle_t *mesh) { - pthread_mutex_lock(&(mesh->mesh_mutex)); - - vpn_packet_t packet; - meshlink_packethdr_t *hdr = (meshlink_packethdr_t *)packet.data; - - outpacketqueue_t* p = meshlink_queue_pop(&mesh->outpacketqueue); - if(!p) - { - pthread_mutex_unlock(&(mesh->mesh_mutex)); +void meshlink_send_from_queue(event_loop_t *loop, meshlink_handle_t *mesh) { + vpn_packet_t *packet = meshlink_queue_pop(&mesh->outpacketqueue); + if(!packet) return; - } - - if (sizeof(meshlink_packethdr_t) + p->len > MAXSIZE) { - pthread_mutex_unlock(&(mesh->mesh_mutex)); - //log something - return; - } - - packet.probe = false; - memset(hdr, 0, sizeof *hdr); - memcpy(hdr->destination, p->destination->name, sizeof hdr->destination); - memcpy(hdr->source, mesh->self->name, sizeof hdr->source); - - packet.len = sizeof *hdr + p->len; - memcpy(packet.data + sizeof *hdr, p->data, p->len); - mesh->self->in_packets++; - mesh->self->in_bytes += packet.len; - route(mesh, mesh->self, &packet); - - pthread_mutex_unlock(&(mesh->mesh_mutex)); - return ; + mesh->self->in_packets++; + mesh->self->in_bytes += packet->len; + route(mesh, mesh->self, packet); } ssize_t meshlink_get_pmtu(meshlink_handle_t *mesh, meshlink_node_t *destination) { @@ -1703,7 +1701,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; } @@ -1825,7 +1823,10 @@ void meshlink_hint_address(meshlink_handle_t *mesh, meshlink_node_t *node, const 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); @@ -1840,8 +1841,8 @@ void meshlink_hint_address(meshlink_handle_t *mesh, meshlink_node_t *node, const * 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, size_t *nmemb) { - if(!mesh || !nmemb) { +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; } @@ -1850,35 +1851,50 @@ meshlink_edge_t **meshlink_get_all_edges_state(meshlink_handle_t *mesh, size_t * meshlink_edge_t **result = NULL; meshlink_edge_t *copy = NULL; + int result_size = 0; - // mesh->edges->count is the max size - *nmemb = mesh->edges->count; + result_size = mesh->edges->count; - result = xzalloc(*nmemb * sizeof (meshlink_edge_t*)); + // 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)) { - *nmemb--; + result_size--; continue; } - // copy the edge so it can't be mutated - copy = xzalloc(sizeof *copy); + 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; -#ifdef HAVE_STRUCT_SOCKADDR_STORAGE copy->address = e->address.storage; -#endif copy->options = e->options; copy->weight = e->weight; *p++ = copy; } // shrink result to the actual amount of memory used - result = realloc(result, *nmemb * sizeof (meshlink_edge_t*)); + 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; } @@ -1887,27 +1903,154 @@ meshlink_edge_t **meshlink_get_all_edges_state(meshlink_handle_t *mesh, size_t * return result; } -static void __attribute__((constructor)) meshlink_init(void) { - crypto_init(); +static bool channel_pre_accept(struct utcp *utcp, uint16_t port) { + //TODO: implement + return true; } -static void __attribute__((destructor)) meshlink_exit(void) { - crypto_exit(); +static ssize_t channel_recv(struct utcp_connection *connection, const void *data, size_t len) { + meshlink_channel_t *channel = connection->priv; + if(!channel) + abort(); + 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 len; + } +} + +static void channel_accept(struct utcp_connection *utcp_connection, uint16_t port) { + node_t *n = utcp_connection->utcp->priv; + if(!n) + abort(); + meshlink_handle_t *mesh = n->mesh; + if(!mesh->channel_accept_cb) + return; + meshlink_channel_t *channel = xzalloc(sizeof *channel); + channel->node = n; + channel->c = utcp_connection; + if(mesh->channel_accept_cb(mesh, channel, port, NULL, 0)) + utcp_accept(utcp_connection, channel_recv, channel); + else + free(channel); +} + +static ssize_t channel_send(struct utcp *utcp, const void *data, size_t len) { + node_t *n = utcp->priv; + meshlink_handle_t *mesh = n->mesh; + char hex[len * 2 + 1]; + bin2hex(data, hex, len); + logger(mesh, MESHLINK_WARNING, "channel_send(%p, %p, %zu): %s\n", utcp, data, len, hex); + return meshlink_send(mesh, (meshlink_node_t *)n, data, len) ? len : -1; } -int weight_from_dclass(dclass_t dclass) -{ - switch(dclass) - { - case BACKBONE: - return 1; +void meshlink_set_channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, meshlink_channel_receive_cb_t cb) { + channel->receive_cb = cb; +} + +static void channel_receive(meshlink_handle_t *mesh, meshlink_node_t *source, const void *data, size_t len) { + node_t *n = (node_t *)source; + if(!n->utcp) + abort(); + char hex[len * 2 + 1]; + bin2hex(data, hex, len); + logger(mesh, MESHLINK_WARNING, "channel_receive(%p, %p, %zu): %s\n", n->utcp, data, len, hex); + utcp_recv(n->utcp, data, len); +} + +static void channel_poll(struct utcp_connection *connection, size_t len) { + meshlink_channel_t *channel = connection->priv; + if(!channel) + abort(); + node_t *n = channel->node; + meshlink_handle_t *mesh = n->mesh; + if(channel->poll_cb) + channel->poll_cb(mesh, channel, len); +} + +void meshlink_set_channel_poll_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, meshlink_channel_poll_cb_t cb) { + channel->poll_cb = cb; + utcp_set_poll_cb(channel->c, cb ? channel_poll : NULL); +} + +void meshlink_set_channel_accept_cb(meshlink_handle_t *mesh, meshlink_channel_accept_cb_t cb) { + pthread_mutex_lock(&mesh->mesh_mutex); + mesh->channel_accept_cb = cb; + mesh->receive_cb = channel_receive; + for splay_each(node_t, n, mesh->nodes) { + if(!n->utcp && n != mesh->self) { + logger(mesh, MESHLINK_WARNING, "utcp_init on node %s", n->name); + n->utcp = utcp_init(channel_accept, channel_pre_accept, channel_send, n); + } + } + pthread_mutex_unlock(&mesh->mesh_mutex); +} - case STATIONARY: - return 3; +void meshlink_channel_init(meshlink_handle_t *mesh) { +} - case PORTABLE: - return 6; +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) { + logger(mesh, MESHLINK_WARNING, "meshlink_channel_open(%p, %s, %u, %p, %p, %zu)\n", mesh, node->name, port, cb, data, len); + node_t *n = (node_t *)node; + if(!n->utcp) { + n->utcp = utcp_init(channel_accept, channel_pre_accept, channel_send, n); + mesh->receive_cb = channel_receive; + if(!n->utcp) { + meshlink_errno = errno == ENOMEM ? MESHLINK_ENOMEM : MESHLINK_EINTERNAL; + 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) { + meshlink_errno = errno == ENOMEM ? MESHLINK_ENOMEM : MESHLINK_EINTERNAL; + 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); +} - return 9; +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); } + +void update_node_status(meshlink_handle_t *mesh, node_t *n) { + if(n->status.reachable && mesh->channel_accept_cb && !n->utcp) + n->utcp = utcp_init(channel_accept, channel_pre_accept, channel_send, n); + if(mesh->node_status_cb) + mesh->node_status_cb(mesh, (meshlink_node_t *)n, n->status.reachable); +} + +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 +};