From 92283d7342fabd882126a892b2636d57ff0458de Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Tue, 9 Oct 2018 14:06:04 +0200 Subject: [PATCH] Lock meshlink.conf to ensure only one instance can run at a time. --- src/conf.c | 36 +++++++++--------------------------- src/conf.h | 5 ----- src/meshlink.c | 32 ++++++++++++++++++++++++++++++++ src/meshlink.h | 21 +++++++++++---------- src/meshlink_internal.h | 1 + src/net_socket.c | 4 ++-- 6 files changed, 55 insertions(+), 44 deletions(-) diff --git a/src/conf.c b/src/conf.c index 5d5c46c1..e3574ea5 100644 --- a/src/conf.c +++ b/src/conf.c @@ -40,13 +40,7 @@ static int config_compare(const config_t *a, const config_t *b) { return result; } - result = a->line - b->line; - - if(result) { - return result; - } else { - return a->file ? strcmp(a->file, b->file) : 0; - } + return result = a->line - b->line; } void init_configuration(splay_tree_t **config_tree) { @@ -66,18 +60,8 @@ config_t *new_config(void) { } void free_config(config_t *cfg) { - if(cfg->variable) { - free(cfg->variable); - } - - if(cfg->value) { - free(cfg->value); - } - - if(cfg->file) { - free(cfg->file); - } - + free(cfg->variable); + free(cfg->value); free(cfg); } @@ -89,7 +73,6 @@ config_t *lookup_config(splay_tree_t *config_tree, char *variable) { config_t cfg, *found; cfg.variable = variable; - cfg.file = NULL; cfg.line = 0; found = splay_search_closest_greater(config_tree, &cfg); @@ -137,8 +120,8 @@ bool get_config_bool(const config_t *cfg, bool *result) { return true; } - logger(NULL, MESHLINK_ERROR, "\"yes\" or \"no\" expected for configuration variable %s in %s line %d", - cfg->variable, cfg->file, cfg->line); + logger(NULL, MESHLINK_ERROR, "\"yes\" or \"no\" expected for configuration variable %s in line %d", + cfg->variable, cfg->line); return false; } @@ -152,8 +135,8 @@ bool get_config_int(const config_t *cfg, int *result) { return true; } - logger(NULL, MESHLINK_ERROR, "Integer expected for configuration variable %s in %s line %d", - cfg->variable, cfg->file, cfg->line); + logger(NULL, MESHLINK_ERROR, "Integer expected for configuration variable %s in line %d", + cfg->variable, cfg->line); return false; } @@ -213,8 +196,8 @@ bool get_config_address(const config_t *cfg, struct addrinfo **result) { return true; } - logger(NULL, MESHLINK_ERROR, "Hostname or IP address expected for configuration variable %s in %s line %d", - cfg->variable, cfg->file, cfg->line); + logger(NULL, MESHLINK_ERROR, "Hostname or IP address expected for configuration variable %s in line %d", + cfg->variable, cfg->line); return false; } @@ -285,7 +268,6 @@ config_t *parse_config_line(char *line, const char *fname, int lineno) { cfg = new_config(); cfg->variable = xstrdup(variable); cfg->value = xstrdup(value); - cfg->file = xstrdup(fname); cfg->line = lineno; return cfg; diff --git a/src/conf.h b/src/conf.h index fd48ea64..fb29f02c 100644 --- a/src/conf.h +++ b/src/conf.h @@ -27,7 +27,6 @@ typedef struct config_t { char *variable; char *value; - char *file; int line; } config_t; @@ -45,10 +44,6 @@ extern bool get_config_string(const config_t *, char **); extern bool set_config_string(config_t *, const char *); extern bool get_config_address(const config_t *, struct addrinfo **); -extern config_t *parse_config_line(char *, const char *, int); -extern bool read_config_file(struct splay_tree_t *, const char *); -extern bool write_config_file(const struct splay_tree_t *, const char *); - extern bool read_server_config(struct meshlink_handle *mesh); extern bool read_host_config(struct meshlink_handle *mesh, struct splay_tree_t *, const char *); extern bool write_host_config(struct meshlink_handle *mesh, const struct splay_tree_t *, const char *); diff --git a/src/meshlink.c b/src/meshlink.c index a26c4181..6df7c419 100644 --- a/src/meshlink.c +++ b/src/meshlink.c @@ -869,6 +869,8 @@ static const char *errstr[] = { [MESHLINK_ESTORAGE] = "Storage error", [MESHLINK_ENETWORK] = "Network error", [MESHLINK_EPEER] = "Error communicating with peer", + [MESHLINK_ENOTSUP] = "Operation not supported", + [MESHLINK_EBUSY] = "MeshLink instance already in use", }; const char *meshlink_strerror(meshlink_errno_t err) { @@ -1116,6 +1118,32 @@ meshlink_handle_t *meshlink_open(const char *confbase, const char *name, const c } } + // Open the configuration file and lock it + + mesh->conffile = fopen(filename, "r"); + + if(!mesh->conffile) { + logger(NULL, MESHLINK_ERROR, "Cannot not open %s: %s\n", filename, strerror(errno)); + meshlink_close(mesh); + meshlink_errno = MESHLINK_ESTORAGE; + return NULL; + } + +#ifdef FD_CLOEXEC + fcntl(fileno(mesh->conffile), F_SETFD, FD_CLOEXEC); +#endif + +#ifdef HAVE_MINGW + // TODO: use _locking()? +#else + if(flock(fileno(mesh->conffile), LOCK_EX | LOCK_NB) != 0) { + logger(NULL, MESHLINK_ERROR, "Cannot lock %s: %s\n", filename, strerror(errno)); + meshlink_close(mesh); + meshlink_errno = MESHLINK_EBUSY; + return NULL; + } +#endif + // Read the configuration init_configuration(&mesh->config); @@ -1325,6 +1353,10 @@ void meshlink_close(meshlink_handle_t *mesh) { free(mesh->confbase); pthread_mutex_destroy(&(mesh->mesh_mutex)); + if(mesh->conffile) { + fclose(mesh->conffile); + } + memset(mesh, 0, sizeof(*mesh)); free(mesh); diff --git a/src/meshlink.h b/src/meshlink.h index 15fb6e69..2f2e7f84 100644 --- a/src/meshlink.h +++ b/src/meshlink.h @@ -53,17 +53,18 @@ typedef struct meshlink_channel meshlink_channel_t; /// Code of most recent error encountered. typedef enum { - MESHLINK_OK, ///< Everything is fine - MESHLINK_EINVAL, ///< Invalid parameter(s) to function call - MESHLINK_ENOMEM, ///< Out of memory - MESHLINK_ENOENT, ///< Node is not known - MESHLINK_EEXIST, ///< Node already exists + MESHLINK_OK, ///< Everything is fine + MESHLINK_EINVAL, ///< Invalid parameter(s) to function call + MESHLINK_ENOMEM, ///< Out of memory + MESHLINK_ENOENT, ///< Node is not known + MESHLINK_EEXIST, ///< Node already exists MESHLINK_EINTERNAL, ///< MeshLink internal error - MESHLINK_ERESOLV, ///< MeshLink could not resolve a hostname - MESHLINK_ESTORAGE, ///< MeshLink coud not load or write data from/to disk - MESHLINK_ENETWORK, ///< MeshLink encountered a network error - MESHLINK_EPEER, ///< A peer caused an error - MESHLINK_ENOTSUP, ///< The operation is not supported in the current configuration of MeshLink + MESHLINK_ERESOLV, ///< MeshLink could not resolve a hostname + MESHLINK_ESTORAGE, ///< MeshLink coud not load or write data from/to disk + MESHLINK_ENETWORK, ///< MeshLink encountered a network error + MESHLINK_EPEER, ///< A peer caused an error + MESHLINK_ENOTSUP, ///< The operation is not supported in the current configuration of MeshLink + MESHLINK_EBUSY, ///< The MeshLink instance is already in use by another process } meshlink_errno_t; /// Device class diff --git a/src/meshlink_internal.h b/src/meshlink_internal.h index 545bd526..92774c49 100644 --- a/src/meshlink_internal.h +++ b/src/meshlink_internal.h @@ -66,6 +66,7 @@ struct meshlink_handle { dev_class_t devclass; char *confbase; + FILE *conffile; meshlink_receive_cb_t receive_cb; meshlink_node_status_cb_t node_status_cb; diff --git a/src/net_socket.c b/src/net_socket.c index 1e981af6..ea5fdaa0 100644 --- a/src/net_socket.c +++ b/src/net_socket.c @@ -782,8 +782,8 @@ void try_outgoing_connections(meshlink_handle_t *mesh) { if(!check_id(name)) { logger(mesh, MESHLINK_ERROR, - "Invalid name for outgoing connection in %s line %d", - cfg->file, cfg->line); + "Invalid name for outgoing connection in line %d", + cfg->line); free(name); continue; } -- 2.39.5