bool config_sync(meshlink_handle_t *mesh, const char *conf_subdir) {
assert(conf_subdir);
- if(!mesh->confbase) {
+ if(!mesh->confbase || mesh->storage_policy == MESHLINK_STORAGE_DISABLED) {
return true;
}
n->last_reachable = time(NULL);
if(first_time_reachable) {
- if(!node_write_config(mesh, n)) {
+ if(!node_write_config(mesh, n, false)) {
logger(mesh, MESHLINK_WARNING, "Could not write host config file for node %s!\n", n->name);
}
meshlink_set_scheduling_granularity(handle, granularity);
}
+ /// Sets the storage policy used by MeshLink
+ /** This sets the policy MeshLink uses when it has new information about nodes.
+ * By default, all udpates will be stored to disk (unless an ephemeral instance has been opened).
+ * Setting the policy to MESHLINK_STORAGE_KEYS_ONLY, only updates that contain new keys for nodes
+ * are stored, as well as blacklist/whitelist settings.
+ * By setting the policy to MESHLINK_STORAGE_DISABLED, no updates will be stored.
+ *
+ * @param policy The storage policy to use.
+ */
+ void set_storage_policy(meshlink_storage_policy_t policy) {
+ meshlink_set_storage_policy(handle, policy);
+ }
+
/// Invite another node into the mesh.
/** This function generates an invitation that can be used by another node to join the same mesh as the local node.
* The generated invitation is a string containing a URL.
}
/* Write our own host config file */
- if(!node_write_config(mesh, mesh->self)) {
+ if(!node_write_config(mesh, mesh->self, true)) {
return false;
}
n->last_reachable = 0;
n->last_unreachable = 0;
- if(!node_write_config(mesh, n)) {
+ if(!node_write_config(mesh, n, true)) {
free_node(n);
return false;
}
return true;
}
+bool meshlink_open_params_set_storage_policy(meshlink_open_params_t *params, meshlink_storage_policy_t policy) {
+ if(!params) {
+ meshlink_errno = MESHLINK_EINVAL;
+ return false;
+ }
+
+ params->storage_policy = policy;
+
+ 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");
// If no configuration exists yet, create it.
+ bool new_configuration = false;
+
if(!meshlink_confbase_exists(mesh)) {
if(!mesh->name) {
logger(NULL, MESHLINK_ERROR, "No configuration files found!\n");
meshlink_close(mesh);
return NULL;
}
+
+ new_configuration = true;
} else {
if(!meshlink_read_config(mesh)) {
logger(NULL, MESHLINK_ERROR, "Cannot read main configuration\n");
}
}
+ mesh->storage_policy = params->storage_policy;
+
#ifdef HAVE_MINGW
struct WSAData wsa_state;
WSAStartup(MAKEWORD(2, 2), &wsa_state);
add_local_addresses(mesh);
- if(!node_write_config(mesh, mesh->self)) {
+ if(!node_write_config(mesh, mesh->self, new_configuration)) {
logger(NULL, MESHLINK_ERROR, "Cannot update configuration\n");
return NULL;
}
if(mesh->nodes) {
for splay_each(node_t, n, mesh->nodes) {
if(n->status.dirty) {
- n->status.dirty = !node_write_config(mesh, n);
+ n->status.dirty = !node_write_config(mesh, n, false);
}
}
}
free(n->canonical_address);
n->canonical_address = canonical_address;
- if(!node_write_config(mesh, n)) {
+ if(!node_write_config(mesh, n, false)) {
pthread_mutex_unlock(&mesh->mutex);
return false;
}
free(n->canonical_address);
n->canonical_address = NULL;
- if(!node_write_config(mesh, n)) {
+ if(!node_write_config(mesh, n, false)) {
pthread_mutex_unlock(&mesh->mutex);
return false;
}
// If we changed our own host config file, write it out now
if(mesh->self->status.dirty) {
- if(!node_write_config(mesh, mesh->self)) {
+ if(!node_write_config(mesh, mesh->self, false)) {
logger(mesh, MESHLINK_ERROR, "Could not write our own host config file!\n");
pthread_mutex_unlock(&mesh->mutex);
return NULL;
n->last_reachable = 0;
n->last_unreachable = 0;
- if(!node_write_config(mesh, n)) {
+ if(!node_write_config(mesh, n, true)) {
free_node(n);
return false;
}
/* Remove any outstanding invitations */
invitation_purge_node(mesh, n->name);
- return node_write_config(mesh, n) && config_sync(mesh, "current");
+ return node_write_config(mesh, n, true) && config_sync(mesh, "current");
}
bool meshlink_blacklist(meshlink_handle_t *mesh, meshlink_node_t *node) {
update_node_status(mesh, n);
}
- return node_write_config(mesh, n) && config_sync(mesh, "current");
+ return node_write_config(mesh, n, true) && config_sync(mesh, "current");
}
bool meshlink_whitelist(meshlink_handle_t *mesh, meshlink_node_t *node) {
node_t *n = (node_t *)node;
if(node_add_recent_address(mesh, n, (sockaddr_t *)addr)) {
- if(!node_write_config(mesh, n)) {
+ if(!node_write_config(mesh, n, false)) {
logger(mesh, MESHLINK_DEBUG, "Could not update %s\n", n->name);
}
}
utcp_set_clock_granularity(granularity);
}
+void meshlink_set_storage_policy(struct meshlink_handle *mesh, meshlink_storage_policy_t policy) {
+ if(!mesh) {
+ meshlink_errno = EINVAL;
+ return;
+ }
+
+ if(pthread_mutex_lock(&mesh->mutex) != 0) {
+ abort();
+ }
+
+ mesh->storage_policy = policy;
+ pthread_mutex_unlock(&mesh->mutex);
+}
+
void handle_network_change(meshlink_handle_t *mesh, bool online) {
(void)online;
DEV_CLASS_COUNT
} dev_class_t;
+/// Storage policy
+typedef enum {
+ MESHLINK_STORAGE_ENABLED, ///< Store all updates.
+ MESHLINK_STORAGE_DISABLED, ///< Don't store any updates.
+ MESHLINK_STORAGE_KEYS_ONLY, ///< Only store updates when a node's key has changed.
+} meshlink_storage_policy_t;
+
/// Invitation flags
static const uint32_t MESHLINK_INVITE_LOCAL = 1; // Only use local addresses in the URL
static const uint32_t MESHLINK_INVITE_PUBLIC = 2; // Only use public or canonical addresses in the URL
*/
bool meshlink_open_params_set_storage_key(meshlink_open_params_t *params, const void *key, size_t keylen) __attribute__((__warn_unused_result__));
+/// Set the encryption key MeshLink should use for local storage.
+/** This function changes the open parameters to use the given storage policy.
+ *
+ * @param params A pointer to a meshlink_open_params_t which must have been created earlier with meshlink_open_params_init().
+ * @param policy The storage policy to use.
+ *
+ * @return This function will return true if the open parameters have been successfully updated, false otherwise.
+ */
+bool meshlink_open_params_set_storage_policy(meshlink_open_params_t *params, meshlink_storage_policy_t policy) __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,
*/
void meshlink_set_scheduling_granularity(struct meshlink_handle *mesh, long granularity);
+/// Sets the storage policy used by MeshLink
+/** This sets the policy MeshLink uses when it has new information about nodes.
+ * By default, all udpates will be stored to disk (unless an ephemeral instance has been opened).
+ * Setting the policy to MESHLINK_STORAGE_KEYS_ONLY, only updates that contain new keys for nodes
+ * are stored, as well as blacklist/whitelist settings.
+ * By setting the policy to MESHLINK_STORAGE_DISABLED, no updates will be stored.
+ *
+ * \memberof meshlink_handle
+ * @param mesh A handle which represents an instance of MeshLink.
+ * @param policy The storage policy to use.
+ */
+void meshlink_set_storage_policy(struct meshlink_handle *mesh, meshlink_storage_policy_t policy);
+
#ifdef __cplusplus
}
#endif
meshlink_open_params_init
meshlink_open_params_set_netns
meshlink_open_params_set_storage_key
+meshlink_open_params_set_storage_policy
meshlink_reset_timers
meshlink_send
meshlink_set_blacklisted_cb
meshlink_sign
meshlink_start
meshlink_stop
+meshlink_set_storage_policy
meshlink_strerror
meshlink_submesh_open
meshlink_verify
const void *key;
size_t keylen;
+ meshlink_storage_policy_t storage_policy;
};
/// Device class traits
void *config_key;
char *external_address_url;
struct list_t *invitation_addresses;
+ meshlink_storage_policy_t storage_policy;
// Thread management
pthread_t thread;
for splay_each(node_t, n, mesh->nodes) {
if(n->status.dirty) {
- if(!node_write_config(mesh, n)) {
+ if(!node_write_config(mesh, n, false)) {
logger(mesh, MESHLINK_DEBUG, "Could not update %s", n->name);
}
-
- n->status.dirty = false;
}
if(n->status.reachable && n->status.validkey && n->last_req_key + 3600 < mesh->loop.now.tv_sec) {
bool node_read_from_config(struct meshlink_handle *mesh, struct node_t *, const config_t *config) __attribute__((__warn_unused_result__));
bool read_ecdsa_public_key(struct meshlink_handle *mesh, struct connection_t *) __attribute__((__warn_unused_result__));
bool read_ecdsa_private_key(struct meshlink_handle *mesh) __attribute__((__warn_unused_result__));
-bool node_write_config(struct meshlink_handle *mesh, struct node_t *) __attribute__((__warn_unused_result__));
+bool node_write_config(struct meshlink_handle *mesh, struct node_t *, bool new_key) __attribute__((__warn_unused_result__));
void send_mtu_probe(struct meshlink_handle *mesh, struct node_t *);
void handle_meta_connection_data(struct meshlink_handle *mesh, struct connection_t *);
void retry(struct meshlink_handle *mesh);
return packmsg_done(&in);
}
-bool node_write_config(meshlink_handle_t *mesh, node_t *n) {
+bool node_write_config(meshlink_handle_t *mesh, node_t *n, bool new_key) {
if(!mesh->confbase) {
return true;
}
+ switch(mesh->storage_policy) {
+ case MESHLINK_STORAGE_KEYS_ONLY:
+ if(!new_key) {
+ return true;
+ }
+
+ break;
+
+ case MESHLINK_STORAGE_DISABLED:
+ return true;
+
+ default:
+ break;
+ }
+
uint8_t buf[4096];
packmsg_output_t out = {buf, sizeof(buf)};
return false;
}
+ n->status.dirty = false;
return true;
}
// Remember its current address
node_add_recent_address(mesh, n, &c->address);
- if(!node_write_config(mesh, n) || !config_sync(mesh, "current")) {
+ if(!node_write_config(mesh, n, true) || !config_sync(mesh, "current")) {
logger(mesh, MESHLINK_ERROR, "Error writing configuration file for invited node %s!\n", c->name);
free_node(n);
return false;