X-Git-Url: http://git.meshlink.io/?a=blobdiff_plain;f=src%2Fmeshlink.c;h=6ebbdcb0aab4481f62d1a368c488f3f7176f823a;hb=fb3ae8985db2f41c498b4fdaf2ca1566dbc84954;hp=0799c4d7bed8b17d659e8b508236dddbc88edd9f;hpb=961386ebb103995bd323efed53fcbff99f5357d1;p=meshlink diff --git a/src/meshlink.c b/src/meshlink.c index 0799c4d7..6ebbdcb0 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: @@ -698,6 +699,20 @@ static bool ecdsa_keygen(meshlink_handle_t *mesh) { return true; } +static struct timeval idle(event_loop_t *loop, void *data) { + meshlink_handle_t *mesh = data; + int t, tmin = -1; + for splay_each(node_t, n, mesh->nodes) { + if(!n->utcp) + continue; + t = utcp_timeout(n->utcp); + if(t >= 0 && t < tmin) + tmin = t; + } + struct timeval tv = {.tv_sec = t}; + return tv; +} + static bool meshlink_setup(meshlink_handle_t *mesh) { if(mkdir(mesh->confbase, 0777) && errno != EEXIST) { logger(mesh, MESHLINK_DEBUG, "Could not create directory %s: %s\n", mesh->confbase, strerror(errno)); @@ -742,11 +757,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 +793,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 @@ -838,6 +859,8 @@ meshlink_handle_t *meshlink_open_with_size(const char *confbase, const char *nam return NULL; } + idle_set(&mesh->loop, idle, mesh); + logger(NULL, MESHLINK_DEBUG, "meshlink_open returning\n"); return mesh; } @@ -866,6 +889,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 +1026,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 +1042,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 +1717,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; } @@ -1811,6 +1825,10 @@ void meshlink_whitelist(meshlink_handle_t *mesh, meshlink_node_t *node) { return; } +void meshlink_set_default_blacklist(meshlink_handle_t *mesh, bool blacklist) { + mesh->default_blacklist = blacklist; +} + /* Hint that a hostname may be found at an address * See header file for detailed comment. */ @@ -1825,7 +1843,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); @@ -1880,9 +1901,7 @@ meshlink_edge_t **meshlink_get_all_edges_state(meshlink_handle_t *mesh, meshlink } 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; @@ -1904,27 +1923,196 @@ meshlink_edge_t **meshlink_get_all_edges_state(meshlink_handle_t *mesh, meshlink 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; +} + +void meshlink_set_channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, meshlink_channel_receive_cb_t cb) { + if(!mesh || !channel) { + meshlink_errno = MESHLINK_EINVAL; + return; + } + + 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) { + if(!mesh) { + meshlink_errno = MESHLINK_EINVAL; + return; + } + + 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); } -int weight_from_dclass(dclass_t dclass) -{ - switch(dclass) - { - case BACKBONE: - return 1; +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) { + if(!mesh || !node) { + meshlink_errno = MESHLINK_EINVAL; + return NULL; + } - case STATIONARY: - return 3; + 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; +} - case PORTABLE: - return 6; +void meshlink_channel_shutdown(meshlink_handle_t *mesh, meshlink_channel_t *channel, int direction) { + if(!mesh || !channel) { + meshlink_errno = MESHLINK_EINVAL; + return; } - return 9; + utcp_shutdown(channel->c, direction); } + +void meshlink_channel_close(meshlink_handle_t *mesh, meshlink_channel_t *channel) { + if(!mesh || !channel) { + meshlink_errno = MESHLINK_EINVAL; + return; + } + + 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) { + if(!mesh || !channel) { + meshlink_errno = MESHLINK_EINVAL; + return -1; + } + + if(!len) + return 0; + + if(!data) { + meshlink_errno = MESHLINK_EINVAL; + return -1; + } + + // TODO: more finegrained 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. + + pthread_mutex_lock(&mesh->mesh_mutex); + ssize_t retval = utcp_send(channel->c, data, len); + pthread_mutex_unlock(&mesh->mesh_mutex); + + if(retval < 0) + meshlink_errno = MESHLINK_ENETWORK; + return retval; +} + +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 +};