X-Git-Url: http://git.meshlink.io/?a=blobdiff_plain;f=src%2Fmeshlink.c;h=9a0e914ac9be34a863103df10965889a29026705;hb=4a839c62c32ae4933b24215e3fb25cdb159fcd4e;hp=4ff26ac16f8847fd3b3ad0522b0d274ef78ec4ce;hpb=4400e95379cf5256d48376eacf98562e232a3cdf;p=meshlink diff --git a/src/meshlink.c b/src/meshlink.c index 4ff26ac1..9a0e914a 100644 --- a/src/meshlink.c +++ b/src/meshlink.c @@ -59,6 +59,7 @@ const var_t variables[] = { {"ConnectTo", VAR_SERVER | VAR_MULTIPLE | VAR_SAFE}, {"Name", VAR_SERVER}, /* Host configuration */ + {"CanonicalAddress", VAR_HOST}, {"Address", VAR_HOST | VAR_MULTIPLE}, {"ECDSAPublicKey", VAR_HOST}, {"Port", VAR_HOST}, @@ -96,6 +97,7 @@ static int rstrip(char *value) { static void scan_for_hostname(const char *filename, char **hostname, char **port) { char line[4096]; + bool canonical = false; if(!filename || (*hostname && *port)) { return; @@ -135,25 +137,33 @@ static void scan_for_hostname(const char *filename, char **hostname, char **port p += strspn(p, "\t "); p[strcspn(p, "\t ")] = 0; - // p is now pointing to the port - - // Check that the hostname is a symbolic name (it's not a numeric IPv4 or IPv6 address) - if(!q[strspn(q, "0123456789.")] || strchr(q, ':')) { - continue; - } + // p is now pointing to the port, if present if(!*port && !strcasecmp(line, "Port")) { *port = xstrdup(q); - } else if(!*hostname && !strcasecmp(line, "Address")) { + } else if(!canonical && !*hostname && !strcasecmp(line, "Address")) { + // Check that the hostname is a symbolic name (it's not a numeric IPv4 or IPv6 address) + if(!q[strspn(q, "0123456789.")] || strchr(q, ':')) { + continue; + } + *hostname = xstrdup(q); + if(*p) { + free(*port); + *port = xstrdup(p); + } + } else if(!strcasecmp(line, "CanonicalAddress")) { + *hostname = xstrdup(q); + canonical = true; + if(*p) { free(*port); *port = xstrdup(p); } } - if(*hostname && *port) { + if(canonical && *hostname && *port) { break; } } @@ -162,6 +172,10 @@ static void scan_for_hostname(const char *filename, char **hostname, char **port } static bool is_valid_hostname(const char *hostname) { + if(!*hostname) { + return false; + } + for(const char *p = hostname; *p; p++) { if(!(isalnum(*p) || *p == '-' || *p == '.' || *p == ':')) { return false; @@ -171,6 +185,26 @@ static bool is_valid_hostname(const char *hostname) { return true; } +static bool is_valid_port(const char *port) { + if(!*port) { + return false; + } + + if(isdigit(*port)) { + char *end; + unsigned long int result = strtoul(port, &end, 10); + return result && result < 65536 && !*end; + } + + for(const char *p = port; *p; p++) { + if(!(isalnum(*p) || *p == '-')) { + return false; + } + } + + return true; +} + static void set_timeout(int sock, int timeout) { #ifdef _WIN32 DWORD tv = timeout; @@ -500,6 +534,31 @@ int check_port(meshlink_handle_t *mesh) { return 0; } +static void deltree(const char *dirname) { + DIR *d = opendir(dirname); + + if(d) { + struct dirent *ent; + + while((ent = readdir(d))) { + if(ent->d_name[0] == '.') { + continue; + } + + char filename[PATH_MAX]; + snprintf(filename, sizeof(filename), "%s" SLASH "%s", dirname, ent->d_name); + + if(unlink(filename)) { + deltree(filename); + } + } + + closedir(d); + } + + rmdir(dirname); +} + static bool finalize_join(meshlink_handle_t *mesh) { char *name = xstrdup(get_value(mesh->data, "Name")); @@ -525,6 +584,19 @@ static bool finalize_join(meshlink_handle_t *mesh) { fprintf(f, "Name = %s\n", name); + // Wipe all old host config files and invitations + snprintf(filename, sizeof(filename), "%s" SLASH "hosts", mesh->confbase); + deltree(filename); + + if(mkdir(filename, 0777) && errno != EEXIST) { + logger(mesh, MESHLINK_DEBUG, "Could not create directory %s: %s\n", filename, strerror(errno)); + return false; + } + + snprintf(filename, sizeof(filename), "%s" SLASH "invitations", mesh->confbase); + deltree(filename); + + // Create a new host config file for ourself snprintf(filename, sizeof(filename), "%s" SLASH "hosts" SLASH "%s", mesh->confbase, name); FILE *fh = fopen(filename, "w"); @@ -656,8 +728,10 @@ static bool finalize_join(meshlink_handle_t *mesh) { sptps_send_record(&(mesh->sptps), 1, b64key, strlen(b64key)); free(b64key); + free(mesh->name); free(mesh->self->name); free(mesh->self->connection->name); + mesh->name = xstrdup(name); mesh->self->name = xstrdup(name); mesh->self->connection->name = name; @@ -999,6 +1073,7 @@ meshlink_handle_t *meshlink_open(const char *confbase, const char *name, const c mesh->appname = xstrdup(appname); mesh->devclass = devclass; mesh->discovery = true; + mesh->invitation_timeout = 604800; // 1 week if(usingname) { mesh->name = xstrdup(name); @@ -1127,6 +1202,7 @@ bool meshlink_start(meshlink_handle_t *mesh) { logger(mesh, MESHLINK_DEBUG, "Could not start thread: %s\n", strerror(errno)); memset(&mesh->thread, 0, sizeof(mesh)->thread); meshlink_errno = MESHLINK_EINTERNAL; + event_loop_stop(&mesh->loop); pthread_mutex_unlock(&(mesh->mesh_mutex)); return false; } @@ -1173,12 +1249,14 @@ void meshlink_stop(meshlink_handle_t *mesh) { } } - // Wait for the main thread to finish - pthread_mutex_unlock(&(mesh->mesh_mutex)); - pthread_join(mesh->thread, NULL); - pthread_mutex_lock(&(mesh->mesh_mutex)); + if(mesh->threadstarted) { + // Wait for the main thread to finish + pthread_mutex_unlock(&(mesh->mesh_mutex)); + pthread_join(mesh->thread, NULL); + pthread_mutex_lock(&(mesh->mesh_mutex)); - mesh->threadstarted = false; + mesh->threadstarted = false; + } // Close all metaconnections if(mesh->connections) { @@ -1192,10 +1270,9 @@ void meshlink_stop(meshlink_handle_t *mesh) { if(mesh->outgoings) { list_delete_list(mesh->outgoings); + mesh->outgoings = NULL; } - mesh->outgoings = NULL; - pthread_mutex_unlock(&(mesh->mesh_mutex)); } @@ -1240,32 +1317,6 @@ void meshlink_close(meshlink_handle_t *mesh) { free(mesh); } -static void deltree(const char *dirname) { - DIR *d = opendir(dirname); - - if(d) { - struct dirent *ent; - - while((ent = readdir(d))) { - if(ent->d_name[0] == '.') { - continue; - } - - char filename[PATH_MAX]; - snprintf(filename, sizeof(filename), "%s" SLASH "%s", dirname, ent->d_name); - - if(unlink(filename)) { - deltree(filename); - } - } - - closedir(d); - } - - rmdir(dirname); - return; -} - bool meshlink_destroy(const char *confbase) { if(!confbase) { meshlink_errno = MESHLINK_EINVAL; @@ -1673,8 +1724,8 @@ static bool refresh_invitation_key(meshlink_handle_t *mesh) { return mesh->invitation_key; } -bool meshlink_add_address(meshlink_handle_t *mesh, const char *address) { - if(!mesh || !address) { +bool meshlink_set_canonical_address(meshlink_handle_t *mesh, meshlink_node_t *node, const char *address, const char *port) { + if(!mesh || !node || !address) { meshlink_errno = MESHLINK_EINVAL; return false; } @@ -1685,15 +1736,32 @@ bool meshlink_add_address(meshlink_handle_t *mesh, const char *address) { return false; } - bool rval = false; + if(port && !is_valid_port(port)) { + logger(mesh, MESHLINK_DEBUG, "Invalid character in port: %s\n", address); + meshlink_errno = MESHLINK_EINVAL; + return false; + } + + char *canonical_address; + + if(port) { + xasprintf(&canonical_address, "%s %s", address, port); + } else { + canonical_address = xstrdup(address); + } pthread_mutex_lock(&(mesh->mesh_mutex)); - rval = append_config_file(mesh, mesh->self->name, "Address", address); + bool rval = modify_config_file(mesh, node->name, "CanonicalAddress", canonical_address, 1); pthread_mutex_unlock(&(mesh->mesh_mutex)); + free(canonical_address); return rval; } +bool meshlink_add_address(meshlink_handle_t *mesh, const char *address) { + return meshlink_set_canonical_address(mesh, (meshlink_node_t *)mesh->self, address, NULL); +} + bool meshlink_add_external_address(meshlink_handle_t *mesh) { if(!mesh) { meshlink_errno = MESHLINK_EINVAL; @@ -1779,6 +1847,10 @@ done: return rval; } +void meshlink_set_invitation_timeout(meshlink_handle_t *mesh, int timeout) { + mesh->invitation_timeout = timeout; +} + char *meshlink_invite(meshlink_handle_t *mesh, const char *name) { if(!mesh) { meshlink_errno = MESHLINK_EINVAL; @@ -2396,6 +2468,11 @@ static void channel_accept(struct utcp_connection *utcp_connection, uint16_t por static ssize_t channel_send(struct utcp *utcp, const void *data, size_t len) { node_t *n = utcp->priv; + + if(n->status.destroyed) { + return -1; + } + meshlink_handle_t *mesh = n->mesh; return meshlink_send(mesh, (meshlink_node_t *)n, data, len) ? (ssize_t)len : -1; }