X-Git-Url: http://git.meshlink.io/?a=blobdiff_plain;f=src%2Fmeshlink.c;h=df695b15fa9855a6c5ab9bbee668b39b56cb0fc6;hb=fe1a9111456a73a6e690927e90d8bfa1e1d0ad22;hp=e59170a9f220b50f992e0b07be376923f8ac1018;hpb=6e9e655b538070e8ed4efd160ac0f9b217604a56;p=meshlink diff --git a/src/meshlink.c b/src/meshlink.c index e59170a9..df695b15 100644 --- a/src/meshlink.c +++ b/src/meshlink.c @@ -699,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)); @@ -744,11 +758,6 @@ static bool meshlink_setup(meshlink_handle_t *mesh) { } 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, dev_class_t devclass, size_t size) { - // Validate arguments provided by the application bool usingname = false; @@ -785,7 +794,7 @@ meshlink_handle_t *meshlink_open_with_size(const char *confbase, const char *nam return NULL; } - meshlink_handle_t *mesh = xzalloc(size); + meshlink_handle_t *mesh = xzalloc(sizeof(meshlink_handle_t)); mesh->confbase = xstrdup(confbase); mesh->appname = xstrdup(appname); mesh->devclass = devclass; @@ -845,6 +854,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; } @@ -1809,6 +1820,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. */ @@ -1905,51 +1920,122 @@ meshlink_edge_t **meshlink_get_all_edges_state(meshlink_handle_t *mesh, meshlink static bool channel_pre_accept(struct utcp *utcp, uint16_t port) { //TODO: implement - return false; -} - -static void channel_accept(struct utcp_connection *utcp_connection, uint16_t port) { - //TODO: implement + return true; } -static int channel_recv(struct utcp_connection *connection, const void *data, size_t len) { +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 0; + return len; } } -static int channel_send(struct utcp *utcp, const void *data, size_t len) { - node_t *n = utcp->priv; +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; - return meshlink_send(mesh, (meshlink_node_t *)n, data, len) ? len : -1; + 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); } -void meshlink_set_channel_accept_cb(meshlink_handle_t *mesh, meshlink_channel_accept_cb_t cb) { - mesh->channel_accept_cb = cb; +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); +} + 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; + } + + 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); - if(!n->utcp) + 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; } @@ -1957,20 +2043,57 @@ meshlink_channel_t *meshlink_channel_open(meshlink_handle_t *mesh, meshlink_node } void meshlink_channel_shutdown(meshlink_handle_t *mesh, meshlink_channel_t *channel, int direction) { + if(!mesh || !channel) { + meshlink_errno = MESHLINK_EINVAL; + return; + } + 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) { - // TODO: locking. + 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. - return utcp_send(channel->c, data, len); + + 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) { @@ -1981,7 +2104,6 @@ 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