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.
}
/// Lock the main configuration file. Creates confbase if necessary.
}
/// 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;
}
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);
if(mkdir(mesh->confbase, 0700) && errno != EEXIST) {
logger(NULL, MESHLINK_ERROR, "Cannot create configuration directory %s: %s", mesh->confbase, strerror(errno));
meshlink_close(mesh);
- 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+");
- 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;
}
meshlink_errno = MESHLINK_ESTORAGE;
return false;
}
#else
if(flock(fileno(mesh->lockfile), LOCK_EX | LOCK_NB) != 0) {
#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;
fclose(mesh->lockfile);
mesh->lockfile = NULL;
meshlink_errno = MESHLINK_EBUSY;
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 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__));
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__));
params->devclass = devclass;
params->netns = -1;
params->devclass = devclass;
params->netns = -1;
+ xasprintf(¶ms->lock_filename, "%s" SLASH "meshlink.lock", confbase);
+
+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");
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->confbase);
free(params->name);
free(params->appname);
+ free(params->lock_filename);
- /* 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 meshlink_open_ex(¶ms);
}
- /* 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;
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. */
}
/* 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);
}
return meshlink_open_ex(¶ms);
}
meshlink_queue_init(&mesh->outpacketqueue);
// Atomically lock the configuration directory.
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;
}
meshlink_close(mesh);
return NULL;
}
-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;
}
meshlink_errno = MESHLINK_EINVAL;
return false;
}
+ if(!params->confbase) {
+ /* Ephemeral instances */
+ return true;
+ }
+
/* Exit early if the confbase directory itself doesn't exist */
/* 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. */
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+");
- 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;
}
meshlink_errno = MESHLINK_ESTORAGE;
return false;
}
#else
if(flock(fileno(lockfile), LOCK_EX | LOCK_NB) != 0) {
#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;
fclose(lockfile);
meshlink_errno = MESHLINK_EBUSY;
return false;
- 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));
- 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);
meshlink_errno = MESHLINK_ESTORAGE;
return false;
- 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;
}
meshlink_errno = MESHLINK_ESTORAGE;
return false;
}
+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_set_receive_cb(meshlink_handle_t *mesh, meshlink_receive_cb_t cb) {
if(!mesh) {
meshlink_errno = MESHLINK_EINVAL;
*/
bool meshlink_open_params_set_storage_policy(meshlink_open_params_t *params, meshlink_storage_policy_t policy) __attribute__((__warn_unused_result__));
*/
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,
/// 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,
*/
bool meshlink_destroy(const char *confbase) __attribute__((__warn_unused_result__));
*/
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.
/// 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.
meshlink_clear_invitation_addresses
meshlink_close
meshlink_destroy
meshlink_clear_invitation_addresses
meshlink_close
meshlink_destroy
meshlink_enable_discovery
meshlink_encrypted_key_rotate
meshlink_errno
meshlink_enable_discovery
meshlink_encrypted_key_rotate
meshlink_errno
meshlink_open_ex
meshlink_open_params_free
meshlink_open_params_init
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
meshlink_open_params_set_netns
meshlink_open_params_set_storage_key
meshlink_open_params_set_storage_policy
struct meshlink_open_params {
char *confbase;
struct meshlink_open_params {
char *confbase;
char *appname;
char *name;
dev_class_t devclass;
char *appname;
char *name;
dev_class_t devclass;