]> git.meshlink.io Git - meshlink/commitdiff
Allow a different location for the lock file.
authorGuus Sliepen <guus@meshlink.io>
Mon, 15 Feb 2021 22:48:09 +0000 (23:48 +0100)
committerGuus Sliepen <guus@meshlink.io>
Wed, 3 Mar 2021 11:39:50 +0000 (12:39 +0100)
In order to reduce the write load on the configuration directory as much as
possible, allow the location of the lock file to be set by the application
to somewhere outside the configuration directory. On Linux, it can be put
in /dev/shm.

src/conf.c
src/conf.h
src/meshlink.c
src/meshlink.h
src/meshlink.sym
src/meshlink_internal.h

index af080384d4f40a588eabad1fb1b61ecbe21ea5e4..db91d5fb3c9b900a1d4d20d78a8b0df2a9929501 100644 (file)
@@ -484,11 +484,13 @@ bool meshlink_confbase_exists(meshlink_handle_t *mesh) {
 }
 
 /// Lock the main configuration file. Creates confbase if necessary.
-bool main_config_lock(meshlink_handle_t *mesh) {
+bool main_config_lock(meshlink_handle_t *mesh, const char *lock_filename) {
        if(!mesh->confbase) {
                return true;
        }
 
+       assert(lock_filename);
+
        if(mkdir(mesh->confbase, 0700) && errno != EEXIST) {
                logger(NULL, MESHLINK_ERROR, "Cannot create configuration directory %s: %s", mesh->confbase, strerror(errno));
                meshlink_close(mesh);
@@ -496,13 +498,10 @@ bool main_config_lock(meshlink_handle_t *mesh) {
                return NULL;
        }
 
-       char path[PATH_MAX];
-       snprintf(path, sizeof(path), "%s" SLASH "meshlink.lock", mesh->confbase);
-
-       mesh->lockfile = fopen(path, "w+");
+       mesh->lockfile = fopen(lock_filename, "w+");
 
        if(!mesh->lockfile) {
-               logger(NULL, MESHLINK_ERROR, "Cannot not open %s: %s\n", path, strerror(errno));
+               logger(NULL, MESHLINK_ERROR, "Cannot not open %s: %s\n", lock_filename, strerror(errno));
                meshlink_errno = MESHLINK_ESTORAGE;
                return false;
        }
@@ -516,7 +515,7 @@ bool main_config_lock(meshlink_handle_t *mesh) {
 #else
 
        if(flock(fileno(mesh->lockfile), LOCK_EX | LOCK_NB) != 0) {
-               logger(NULL, MESHLINK_ERROR, "Cannot lock %s: %s\n", path, strerror(errno));
+               logger(NULL, MESHLINK_ERROR, "Cannot lock %s: %s\n", lock_filename, strerror(errno));
                fclose(mesh->lockfile);
                mesh->lockfile = NULL;
                meshlink_errno = MESHLINK_EBUSY;
index b42a229b1a82856cc3a907f48783f2d19b923280..656a0acc7e1c605e9a9a7e9185e789aad29440ca 100644 (file)
@@ -43,7 +43,7 @@ bool config_sync(struct meshlink_handle *mesh, const char *conf_subdir) __attrib
 bool sync_path(const char *path) __attribute__((__warn_unused_result__));
 
 bool main_config_exists(struct meshlink_handle *mesh, const char *conf_subdir) __attribute__((__warn_unused_result__));
-bool main_config_lock(struct meshlink_handle *mesh) __attribute__((__warn_unused_result__));
+bool main_config_lock(struct meshlink_handle *mesh, const char *lock_filename) __attribute__((__warn_unused_result__));
 void main_config_unlock(struct meshlink_handle *mesh);
 bool main_config_read(struct meshlink_handle *mesh, const char *conf_subdir, struct config_t *, void *key) __attribute__((__warn_unused_result__));
 bool main_config_write(struct meshlink_handle *mesh, const char *conf_subdir, const struct config_t *, void *key) __attribute__((__warn_unused_result__));
index 8b9e195fa7df2b9a96d4c949d721867d10271783..aa29ce8984bac86c3cbc92955793d4c6837953c6 100644 (file)
@@ -1230,6 +1230,8 @@ meshlink_open_params_t *meshlink_open_params_init(const char *confbase, const ch
        params->devclass = devclass;
        params->netns = -1;
 
+       xasprintf(&params->lock_filename, "%s" SLASH "meshlink.lock", confbase);
+
        return params;
 }
 
@@ -1273,6 +1275,18 @@ bool meshlink_open_params_set_storage_policy(meshlink_open_params_t *params, mes
        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");
@@ -1354,6 +1368,7 @@ void meshlink_open_params_free(meshlink_open_params_t *params) {
        free(params->confbase);
        free(params->name);
        free(params->appname);
+       free(params->lock_filename);
 
        free(params);
 }
@@ -1373,15 +1388,18 @@ meshlink_handle_t *meshlink_open(const char *confbase, const char *name, const c
                return NULL;
        }
 
-       /* Create a temporary struct on the stack, to avoid allocating and freeing one. */
-       meshlink_open_params_t params;
-       memset(&params, 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(&params);
 }
@@ -1393,15 +1411,18 @@ meshlink_handle_t *meshlink_open_encrypted(const char *confbase, const char *nam
                return NULL;
        }
 
-       /* Create a temporary struct on the stack, to avoid allocating and freeing one. */
-       meshlink_open_params_t params;
-       memset(&params, 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(&params, key, keylen)) {
                return false;
@@ -1442,13 +1463,12 @@ meshlink_handle_t *meshlink_open_ephemeral(const char *name, const char *appname
        }
 
        /* Create a temporary struct on the stack, to avoid allocating and freeing one. */
-       meshlink_open_params_t params;
-       memset(&params, 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(&params);
 }
@@ -1548,7 +1568,7 @@ meshlink_handle_t *meshlink_open_ex(const meshlink_open_params_t *params) {
        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;
        }
@@ -1920,25 +1940,27 @@ void meshlink_close(meshlink_handle_t *mesh) {
        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;
        }
@@ -1952,7 +1974,7 @@ bool meshlink_destroy(const char *confbase) {
 #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;
@@ -1960,13 +1982,13 @@ bool meshlink_destroy(const char *confbase) {
 
 #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;
@@ -1974,8 +1996,8 @@ bool meshlink_destroy(const char *confbase) {
 
        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;
        }
@@ -1983,6 +2005,18 @@ bool meshlink_destroy(const char *confbase) {
        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(&params);
+}
+
 void meshlink_set_receive_cb(meshlink_handle_t *mesh, meshlink_receive_cb_t cb) {
        if(!mesh) {
                meshlink_errno = MESHLINK_EINVAL;
index 7960d31051426dc927bc53aaf308a1b272916895..ead75205809f5f3f2e10fa7363ea629cfd0d68ff 100644 (file)
@@ -206,6 +206,17 @@ bool meshlink_open_params_set_storage_key(meshlink_open_params_t *params, const
  */
 bool meshlink_open_params_set_storage_policy(meshlink_open_params_t *params, meshlink_storage_policy_t policy) __attribute__((__warn_unused_result__));
 
+/// Set the filename of the lockfile.
+/** This function changes the path of the lockfile used to ensure only one instance of MeshLink can be open at the same time.
+ *  If an application changes this, it must always set it to the same location.
+ *
+ *  @param params   A pointer to a meshlink_open_params_t which must have been created earlier with meshlink_open_params_init().
+ *  @param filename The filename of the lockfile.
+ *
+ *  @return         This function will return true if the open parameters have been successfully updated, false otherwise.
+ */
+bool meshlink_open_params_set_lock_filename(meshlink_open_params_t *params, const char *filename) __attribute__((__warn_unused_result__));
+
 /// Open or create a MeshLink instance.
 /** This function opens or creates a MeshLink instance.
  *  All parameters needed by MeshLink are passed via a meshlink_open_params_t struct,
@@ -379,6 +390,21 @@ void meshlink_close(struct meshlink_handle *mesh);
  */
 bool meshlink_destroy(const char *confbase) __attribute__((__warn_unused_result__));
 
+/// Destroy a MeshLink instance using open parameters.
+/** This function remove all configuration files of a MeshLink instance. It should only be called when the application
+ *  does not have an open handle to this instance. Afterwards, a call to meshlink_open() will create a completely
+ *  new instance.
+ *
+ *  This version expects a pointer to meshlink_open_params_t,
+ *  and will use exactly the same settings used for opening a handle to destroy it.
+ *
+ *  @param params   A pointer to a meshlink_open_params_t which must be filled in by the application.
+ *                  After the function returns, the application is free to reuse or free @a params.
+ *
+ *  @return         This function will return true if the MeshLink instance was successfully destroyed, false otherwise.
+ */
+bool meshlink_destroy_ex(const meshlink_open_params_t *params) __attribute__((__warn_unused_result__));
+
 /// A callback for receiving data from the mesh.
 /** @param mesh      A handle which represents an instance of MeshLink.
  *  @param source    A pointer to a struct meshlink_node describing the source of the data.
index f8df23e1dc9b0181a2f393c3f9f0a80cb0a1461e..4ecd23e99df950061f8738d090bc8f3d2cc206be 100644 (file)
@@ -30,6 +30,7 @@ meshlink_clear_canonical_address
 meshlink_clear_invitation_addresses
 meshlink_close
 meshlink_destroy
+meshlink_destroy_ex
 meshlink_enable_discovery
 meshlink_encrypted_key_rotate
 meshlink_errno
@@ -65,6 +66,7 @@ meshlink_open_ephemeral
 meshlink_open_ex
 meshlink_open_params_free
 meshlink_open_params_init
+meshlink_open_params_set_lock_filename
 meshlink_open_params_set_netns
 meshlink_open_params_set_storage_key
 meshlink_open_params_set_storage_policy
index 6cbe6093f42258f84ecb5b0c133b7d2018965ffa..d9000feba2cb86d551f2a40965643aee93cdc4a2 100644 (file)
@@ -59,6 +59,7 @@ typedef struct listen_socket_t {
 
 struct meshlink_open_params {
        char *confbase;
+       char *lock_filename;
        char *appname;
        char *name;
        dev_class_t devclass;