return false;
}
- if(!main_config_lock(mesh)) {
- logger(NULL, MESHLINK_ERROR, "Cannot lock main config file\n");
- meshlink_errno = MESHLINK_ESTORAGE;
- return false;
- }
-
return true;
}
static bool meshlink_read_config(meshlink_handle_t *mesh) {
- // Open the configuration file and lock it
- if(!main_config_lock(mesh)) {
- logger(NULL, MESHLINK_ERROR, "Cannot lock main config file\n");
- meshlink_errno = MESHLINK_ESTORAGE;
- return false;
- }
-
config_t config;
if(!main_config_read(mesh, "current", &config, mesh->config_key)) {
devtool_keyrotate_probe(1);
- main_config_unlock(mesh);
-
// Rename confbase/current/ to confbase/old
if(!config_rename(mesh, "current", "old")) {
logger(mesh, MESHLINK_ERROR, "Cannot rename %s/current to %s/old\n", mesh->confbase, mesh->confbase);
meshlink_errno = MESHLINK_ESTORAGE;
- main_config_lock(mesh);
pthread_mutex_unlock(&mesh->mutex);
return false;
}
if(!config_rename(mesh, "new", "current")) {
logger(mesh, MESHLINK_ERROR, "Cannot rename %s/new to %s/current\n", mesh->confbase, mesh->confbase);
meshlink_errno = MESHLINK_ESTORAGE;
- main_config_lock(mesh);
pthread_mutex_unlock(&mesh->mutex);
return false;
}
devtool_keyrotate_probe(3);
- if(!main_config_lock(mesh)) {
- pthread_mutex_unlock(&mesh->mutex);
- return false;
- }
-
// Cleanup the "old" confbase sub-directory
if(!config_destroy(mesh->confbase, "old")) {
meshlink_queue_init(&mesh->outpacketqueue);
+ // Atomically lock the configuration directory.
+ if(!main_config_lock(mesh)) {
+ meshlink_close(mesh);
+ return NULL;
+ }
+
// If no configuration exists yet, create it.
if(!meshlink_confbase_exists(mesh)) {
return false;
}
- if(!config_destroy(confbase, "current")) {
- logger(NULL, MESHLINK_ERROR, "Cannot remove confbase sub-directories %s: %s\n", confbase, strerror(errno));
+ /* Exit early if the confbase directory itself doesn't exist */
+ if(access(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+");
+
+ if(!lockfile) {
+ logger(NULL, MESHLINK_ERROR, "Could not open lock file %s: %s", lockfilename, strerror(errno));
+ meshlink_errno = MESHLINK_ESTORAGE;
+ return false;
+ }
+
+#ifdef FD_CLOEXEC
+ fcntl(fileno(lockfile), F_SETFD, FD_CLOEXEC);
+#endif
+
+#ifdef HAVE_MINGW
+ // TODO: use _locking()?
+#else
+
+ if(flock(fileno(lockfile), LOCK_EX | LOCK_NB) != 0) {
+ logger(NULL, MESHLINK_ERROR, "Configuration directory %s still in use\n", lockfilename);
+ fclose(lockfile);
+ meshlink_errno = MESHLINK_EBUSY;
return false;
}
- config_destroy(confbase, "new");
- config_destroy(confbase, "old");
+#endif
- if(rmdir(confbase) && errno != ENOENT) {
- logger(NULL, MESHLINK_ERROR, "Cannot remove directory %s: %s\n", confbase, strerror(errno));
+ 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));
+ return false;
+ }
+
+ if(unlink(lockfilename)) {
+ logger(NULL, MESHLINK_ERROR, "Cannot remove lock file %s: %s\n", lockfilename, strerror(errno));
+ fclose(lockfile);
+ meshlink_errno = MESHLINK_ESTORAGE;
+ return false;
+ }
+
+ fclose(lockfile);
+
+ /* TODO: do we need to remove confbase? Potential race condition? */
+ if(!sync_path(confbase)) {
+ logger(NULL, MESHLINK_ERROR, "Cannot sync directory %s: %s\n", confbase, strerror(errno));
meshlink_errno = MESHLINK_ESTORAGE;
return false;
}
logger(mesh, MESHLINK_DEBUG, "Blacklisted %s.\n", node->name);
- //Immediately terminate any connections we have with the blacklisted node
+ /* Immediately shut down any connections we have with the blacklisted node.
+ * We can't call terminate_connection(), because we might be called from a callback function.
+ */
for list_each(connection_t, c, mesh->connections) {
if(c->node == n) {
- terminate_connection(mesh, c, c->status.active);
+ shutdown(c->socket, SHUT_RDWR);
}
}
n->mtuprobes = 0;
n->status.udp_confirmed = false;
- if(n->status.reachable) {
- update_node_status(mesh, n);
- }
-
pthread_mutex_unlock(&mesh->mutex);
}