/*
meshlink.c -- Implementation of the MeshLink API.
- Copyright (C) 2014-2018 Guus Sliepen <guus@meshlink.io>
+ Copyright (C) 2014-2021 Guus Sliepen <guus@meshlink.io>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
params->devclass = devclass;
params->netns = -1;
+ xasprintf(¶ms->lock_filename, "%s" SLASH "meshlink.lock", confbase);
+
return params;
}
return true;
}
+bool meshlink_open_params_set_lock_filename(meshlink_open_params_t *params, const char *filename) {
+ if(!params || !filename) {
+ meshlink_errno = MESHLINK_EINVAL;
+ return false;
+ }
+
+ free(params->lock_filename);
+ params->lock_filename = xstrdup(filename);
+
+ return true;
+}
+
bool meshlink_encrypted_key_rotate(meshlink_handle_t *mesh, const void *new_key, size_t new_keylen) {
if(!mesh || !new_key || !new_keylen) {
logger(mesh, MESHLINK_ERROR, "Invalid arguments given!\n");
free(params->confbase);
free(params->name);
free(params->appname);
+ free(params->lock_filename);
free(params);
}
return NULL;
}
- /* Create a temporary struct on the stack, to avoid allocating and freeing one. */
- meshlink_open_params_t params;
- memset(¶ms, 0, sizeof(params));
+ char lock_filename[PATH_MAX];
+ snprintf(lock_filename, sizeof(lock_filename), "%s" SLASH "meshlink.lock", confbase);
- params.confbase = (char *)confbase;
- params.name = (char *)name;
- params.appname = (char *)appname;
- params.devclass = devclass;
- params.netns = -1;
+ /* Create a temporary struct on the stack, to avoid allocating and freeing one. */
+ meshlink_open_params_t params = {
+ .confbase = (char *)confbase,
+ .lock_filename = lock_filename,
+ .name = (char *)name,
+ .appname = (char *)appname,
+ .devclass = devclass,
+ .netns = -1,
+ };
return meshlink_open_ex(¶ms);
}
return NULL;
}
- /* Create a temporary struct on the stack, to avoid allocating and freeing one. */
- meshlink_open_params_t params;
- memset(¶ms, 0, sizeof(params));
+ char lock_filename[PATH_MAX];
+ snprintf(lock_filename, sizeof(lock_filename), "%s" SLASH "meshlink.lock", confbase);
- params.confbase = (char *)confbase;
- params.name = (char *)name;
- params.appname = (char *)appname;
- params.devclass = devclass;
- params.netns = -1;
+ /* Create a temporary struct on the stack, to avoid allocating and freeing one. */
+ meshlink_open_params_t params = {
+ .confbase = (char *)confbase,
+ .lock_filename = lock_filename,
+ .name = (char *)name,
+ .appname = (char *)appname,
+ .devclass = devclass,
+ .netns = -1,
+ };
if(!meshlink_open_params_set_storage_key(¶ms, key, keylen)) {
return false;
}
/* Create a temporary struct on the stack, to avoid allocating and freeing one. */
- meshlink_open_params_t params;
- memset(¶ms, 0, sizeof(params));
-
- params.name = (char *)name;
- params.appname = (char *)appname;
- params.devclass = devclass;
- params.netns = -1;
+ meshlink_open_params_t params = {
+ .name = (char *)name,
+ .appname = (char *)appname,
+ .devclass = devclass,
+ .netns = -1,
+ };
return meshlink_open_ex(¶ms);
}
mesh->appname = xstrdup(params->appname);
mesh->devclass = params->devclass;
- mesh->discovery = true;
+ mesh->discovery.enabled = true;
mesh->invitation_timeout = 604800; // 1 week
mesh->netns = params->netns;
mesh->submeshes = NULL;
pthread_mutex_init(&mesh->mutex, &attr);
pthread_cond_init(&mesh->cond, NULL);
- pthread_mutex_init(&mesh->discovery_mutex, NULL);
- pthread_cond_init(&mesh->discovery_cond, NULL);
-
pthread_cond_init(&mesh->adns_cond, NULL);
mesh->threadstarted = false;
meshlink_queue_init(&mesh->outpacketqueue);
// Atomically lock the configuration directory.
- if(!main_config_lock(mesh)) {
+ if(!main_config_lock(mesh, params->lock_filename)) {
meshlink_close(mesh);
return NULL;
}
#endif // HAVE_SETNS
}
-#if HAVE_CATTA
-
- if(mesh->discovery) {
+ if(mesh->discovery.enabled) {
discovery_start(mesh);
}
-#endif
-
if(pthread_mutex_lock(&mesh->mutex) != 0) {
abort();
}
pthread_mutex_unlock(&mesh->mutex);
-#if HAVE_CATTA
-
// Stop discovery
- if(mesh->discovery) {
+ if(mesh->discovery.enabled) {
discovery_stop(mesh);
}
-#endif
-
return NULL;
}
free(mesh);
}
-bool meshlink_destroy(const char *confbase) {
- if(!confbase) {
+bool meshlink_destroy_ex(const meshlink_open_params_t *params) {
+ if(!params) {
meshlink_errno = MESHLINK_EINVAL;
return false;
}
+ if(!params->confbase) {
+ /* Ephemeral instances */
+ return true;
+ }
+
/* Exit early if the confbase directory itself doesn't exist */
- if(access(confbase, F_OK) && errno == ENOENT) {
+ if(access(params->confbase, F_OK) && errno == ENOENT) {
return true;
}
/* Take the lock the same way meshlink_open() would. */
- char lockfilename[PATH_MAX];
- snprintf(lockfilename, sizeof(lockfilename), "%s" SLASH "meshlink.lock", confbase);
-
- FILE *lockfile = fopen(lockfilename, "w+");
+ FILE *lockfile = fopen(params->lock_filename, "w+");
if(!lockfile) {
- logger(NULL, MESHLINK_ERROR, "Could not open lock file %s: %s", lockfilename, strerror(errno));
+ logger(NULL, MESHLINK_ERROR, "Could not open lock file %s: %s", params->lock_filename, strerror(errno));
meshlink_errno = MESHLINK_ESTORAGE;
return false;
}
#else
if(flock(fileno(lockfile), LOCK_EX | LOCK_NB) != 0) {
- logger(NULL, MESHLINK_ERROR, "Configuration directory %s still in use\n", lockfilename);
+ logger(NULL, MESHLINK_ERROR, "Configuration directory %s still in use\n", params->lock_filename);
fclose(lockfile);
meshlink_errno = MESHLINK_EBUSY;
return false;
#endif
- if(!config_destroy(confbase, "current") || !config_destroy(confbase, "new") || !config_destroy(confbase, "old")) {
- logger(NULL, MESHLINK_ERROR, "Cannot remove sub-directories in %s: %s\n", confbase, strerror(errno));
+ if(!config_destroy(params->confbase, "current") || !config_destroy(params->confbase, "new") || !config_destroy(params->confbase, "old")) {
+ logger(NULL, MESHLINK_ERROR, "Cannot remove sub-directories in %s: %s\n", params->confbase, strerror(errno));
return false;
}
- if(unlink(lockfilename)) {
- logger(NULL, MESHLINK_ERROR, "Cannot remove lock file %s: %s\n", lockfilename, strerror(errno));
+ if(unlink(params->lock_filename)) {
+ logger(NULL, MESHLINK_ERROR, "Cannot remove lock file %s: %s\n", params->lock_filename, strerror(errno));
fclose(lockfile);
meshlink_errno = MESHLINK_ESTORAGE;
return false;
fclose(lockfile);
- if(!sync_path(confbase)) {
- logger(NULL, MESHLINK_ERROR, "Cannot sync directory %s: %s\n", confbase, strerror(errno));
+ if(!sync_path(params->confbase)) {
+ logger(NULL, MESHLINK_ERROR, "Cannot sync directory %s: %s\n", params->confbase, strerror(errno));
meshlink_errno = MESHLINK_ESTORAGE;
return false;
}
return true;
}
+bool meshlink_destroy(const char *confbase) {
+ char lock_filename[PATH_MAX];
+ snprintf(lock_filename, sizeof(lock_filename), "%s" SLASH "meshlink.lock", confbase);
+
+ meshlink_open_params_t params = {
+ .confbase = (char *)confbase,
+ .lock_filename = lock_filename,
+ };
+
+ return meshlink_destroy_ex(¶ms);
+}
+
void meshlink_set_receive_cb(meshlink_handle_t *mesh, meshlink_receive_cb_t cb) {
if(!mesh) {
meshlink_errno = MESHLINK_EINVAL;
}
void meshlink_enable_discovery(meshlink_handle_t *mesh, bool enable) {
-#if HAVE_CATTA
-
if(!mesh) {
meshlink_errno = MESHLINK_EINVAL;
return;
abort();
}
- if(mesh->discovery == enable) {
+ if(mesh->discovery.enabled == enable) {
goto end;
}
}
}
- mesh->discovery = enable;
+ mesh->discovery.enabled = enable;
end:
pthread_mutex_unlock(&mesh->mutex);
-#else
- (void)mesh;
- (void)enable;
- meshlink_errno = MESHLINK_ENOTSUP;
-#endif
+}
+
+void meshlink_hint_network_change(struct meshlink_handle *mesh) {
+ if(!mesh) {
+ meshlink_errno = MESHLINK_EINVAL;
+ return;
+ }
+
+ if(pthread_mutex_lock(&mesh->mutex) != 0) {
+ abort();
+ }
+
+ if(mesh->discovery.enabled) {
+ scan_ifaddrs(mesh);
+ }
+
+ if(mesh->loop.now.tv_sec > mesh->discovery.last_update + 5) {
+ mesh->discovery.last_update = mesh->loop.now.tv_sec;
+ handle_network_change(mesh, 1);
+ }
+
+ pthread_mutex_unlock(&mesh->mutex);
}
void meshlink_set_dev_class_timeouts(meshlink_handle_t *mesh, dev_class_t devclass, int pinginterval, int pingtimeout) {
}
handle_network_change(mesh, true);
+
+ if(mesh->discovery.enabled) {
+ discovery_refresh(mesh);
+ }
+
pthread_mutex_unlock(&mesh->mutex);
}