}
/// 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);
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;
}
#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;
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);
}
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;
}
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;
*/
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,
*/
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.