Re: [PATCH BlueZ v2] mesh: Use node uuids as storage directory names

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Michał,

On Tue, 2019-05-07 at 09:13 +0200, Michał Lowas-Rzechonek wrote:
> Instead of keeping track of unique 16bit node identifiers, reuse their
> UUIDs to create both storage directories and dbus objects.
> 
> Because of that:
>  - UUID is no longer stored in the JSON file, it's inferred from the
>    directory name instead
>  - Join(), CreateNetwork() and ImportLocalNode() APIs return an error if
>    given UUID already registered within the daemon
> ---
>  doc/mesh-api.txt |  26 ++++++++---
>  mesh/README      |   7 ++-
>  mesh/mesh-db.c   |   4 --
>  mesh/mesh-db.h   |   1 -
>  mesh/mesh.c      |   7 +++
>  mesh/node.c      |  39 ++++++-----------
>  mesh/node.h      |   2 +-
>  mesh/storage.c   | 109 +++++++++++++++++------------------------------
>  8 files changed, 84 insertions(+), 111 deletions(-)
> 
> diff --git a/doc/mesh-api.txt b/doc/mesh-api.txt
> index 81d1a3288..112990a5d 100644
> --- a/doc/mesh-api.txt
> +++ b/doc/mesh-api.txt
> @@ -24,10 +24,14 @@ Methods:
>  		DBus.ObjectManager interface must be available on the
>  		app_defined_root path.
>  
> -		The uuid parameter is a 16-byte array that contains Device UUID.
> +		The uuid parameter is a 16-byte array that contains Device UUID. This
> +		UUID must be unique (at least from the daemon perspective), therefore
> +		attempting to call this function using already registered UUID results
> +		in an error.
>  
>  		PossibleErrors:
>  			org.bluez.mesh.Error.InvalidArguments
> +			org.bluez.mesh.Error.AlreadyExists,
>  
>  	void Cancel(void)
>  
> @@ -127,7 +131,10 @@ Methods:
>  		interface. The standard DBus.ObjectManager interface must be
>  		available on the app_root path.
>  
> -		The uuid parameter is a 16-byte array that contains Device UUID.
> +		The uuid parameter is a 16-byte array that contains Device UUID. This
> +		UUID must be unique (at least from the daemon perspective), therefore
> +		attempting to call this function using already registered UUID results
> +		in an error.
>  
>  		The returned token must be preserved by the application in
>  		order to authenticate itself to the mesh daemon and attach to
> @@ -142,6 +149,7 @@ Methods:
>  
>  		PossibleErrors:
>  			org.bluez.mesh.Error.InvalidArguments
> +			org.bluez.mesh.Error.AlreadyExists,
>  
>  	 uint64 token ImportLocalNode(string json_data)
>  
> @@ -160,8 +168,12 @@ Methods:
>  		permanently remove the identity of the mesh node by calling
>  		Leave() method.
>  
> +		It is an error to attempt importing a node with already registered
> +		Device UUID.
> +
>  		PossibleErrors:
>  			org.bluez.mesh.Error.InvalidArguments,
> +			org.bluez.mesh.Error.AlreadyExists
>  			org.bluez.mesh.Error.NotFound,
>  			org.bluez.mesh.Error.Failed
>  
> @@ -169,8 +181,9 @@ Mesh Node Hierarchy
>  ===================
>  Service		org.bluez.mesh
>  Interface	org.bluez.mesh.Node1
> -Object path	/org/bluez/mesh/node<xxxx>
> -		where xxxx is a 4-digit hexadecimal number generated by daemon
> +Object path	/org/bluez/mesh/node<uuid>
> +		where <uuid> is the Device UUID passed to Join(), CreateNetwork() or
> +		ImportLocalNode()
>  
>  Methods:
>  	void Send(object element_path, uint16 destination, uint16 key_index,
> @@ -334,8 +347,9 @@ Mesh Provisioning Hierarchy
>  ============================
>  Service		org.bluez.mesh
>  Interface	org.bluez.mesh.Management1
> -Object path	/org/bluez/mesh/node<xxxx>
> -		where xxxx is a 4-digit hexadecimal number generated by daemon
> +Object path	/org/bluez/mesh/node<uuid>
> +		where <uuid> is the Device UUID passed to Join(), CreateNetwork() or
> +		ImportLocalNode()
>  
>  Methods:
>  	void UnprovisionedScan(uint16 seconds)
> diff --git a/mesh/README b/mesh/README
> index 151a1e6a1..ca223a6d8 100644
> --- a/mesh/README
> +++ b/mesh/README
> @@ -26,9 +26,8 @@ Storage
>  Default storage directory is /var/lib/bluetooth/mesh.
>  
>  The directory contains the provisioned nodes configurations.
> -Each node has its own subdirectory, named with a 4-digit (hexadecimal)
> -identificator that is internally generated by the mesh daemon at the time
> -of the node provisioning.
> +Each node has its own subdirectory, named after node's Device UUID (32-digit
> +hexadecimal string) that is generated by the application that created a node.
>  
>  Each subdirectory contains the following files:
>  	- node.json:
> @@ -47,4 +46,4 @@ Mailing lists:
>  	linux-bluetooth@xxxxxxxxxxxxxxx
>  
>  For additional information about the project visit BlueZ web site:
> -	http://www.bluez.org
> \ No newline at end of file
> +	http://www.bluez.org
> diff --git a/mesh/mesh-db.c b/mesh/mesh-db.c
> index 64e33cd91..01ae63146 100644
> --- a/mesh/mesh-db.c
> +++ b/mesh/mesh-db.c
> @@ -1466,10 +1466,6 @@ bool mesh_db_add_node(json_object *jnode, struct mesh_db_node *node) {
>  	if (!mesh_db_write_uint16_hex(jnode, "crpl", node->crpl))
>  		return false;
>  
> -	/* Device UUID */
> -	if (!add_key_value(jnode, "UUID", node->uuid))
> -		return false;
> -
>  	/* Features: relay, LPN, friend, proxy*/
>  	if (!mesh_db_write_relay_mode(jnode, modes->relay.state,
>  						modes->relay.cnt,
> diff --git a/mesh/mesh-db.h b/mesh/mesh-db.h
> index 06aba1f31..19913148e 100644
> --- a/mesh/mesh-db.h
> +++ b/mesh/mesh-db.h
> @@ -76,7 +76,6 @@ struct mesh_db_node {
>  	uint16_t unicast;
>  	uint8_t ttl;
>  	struct l_queue *elements;
> -	uint8_t uuid[16];
>  };
>  
>  struct mesh_db_prov {
> diff --git a/mesh/mesh.c b/mesh/mesh.c
> index a084f9200..4d65f266a 100644
> --- a/mesh/mesh.c
> +++ b/mesh/mesh.c
> @@ -577,6 +577,13 @@ static struct l_dbus_message *join_network_call(struct l_dbus *dbus,
>  							"Bad device UUID");
>  	}
>  
> +	if (node_find_by_uuid(join_pending->uuid)) {
> +		l_free(join_pending);
> +		join_pending = NULL;
> +		return dbus_error(msg, MESH_ERROR_ALREADY_EXISTS,
> +							"Node already exists");
> +	}
> +
>  	sender = l_dbus_message_get_sender(msg);
>  
>  	join_pending->sender = l_strdup(sender);
> diff --git a/mesh/node.c b/mesh/node.c
> index 774d03d45..ad444b5c5 100644
> --- a/mesh/node.c
> +++ b/mesh/node.c
> @@ -21,6 +21,7 @@
>  #include <config.h>
>  #endif
>  
> +#define _GNU_SOURCE
>  #include <stdio.h>
>  #include <sys/time.h>
>  #include <ell/ell.h>
> @@ -83,7 +84,6 @@ struct mesh_node {
>  	time_t upd_sec;
>  	uint32_t seq_number;
>  	uint32_t seq_min_cache;
> -	uint16_t id;
>  	bool provisioner;
>  	uint16_t primary;
>  	struct node_composition *comp;
> @@ -92,7 +92,7 @@ struct mesh_node {
>  		uint8_t cnt;
>  		uint8_t mode;
>  	} relay;
> -	uint8_t dev_uuid[16];
> +	uint8_t uuid[16];
>  	uint8_t dev_key[16];
>  	uint8_t token[8];
>  	uint8_t num_ele;
> @@ -126,7 +126,7 @@ static bool match_device_uuid(const void *a, const void *b)
>  	const struct mesh_node *node = a;
>  	const uint8_t *uuid = b;
>  
> -	return (memcmp(node->dev_uuid, uuid, 16) == 0);
> +	return (memcmp(node->uuid, uuid, 16) == 0);
>  }
>  
>  static bool match_token(const void *a, const void *b)
> @@ -187,15 +187,16 @@ uint8_t *node_uuid_get(struct mesh_node *node)
>  {
>  	if (!node)
>  		return NULL;
> -	return node->dev_uuid;
> +	return node->uuid;
>  }
>  
> -struct mesh_node *node_new(void)
> +struct mesh_node *node_new(const uint8_t uuid[16])
>  {
>  	struct mesh_node *node;
>  
>  	node = l_new(struct mesh_node, 1);
>  	node->net = mesh_net_new(node);
> +	memcpy(node->uuid, uuid, sizeof(node->uuid));
>  
>  	if (!nodes)
>  		nodes = l_queue_new();
> @@ -382,8 +383,6 @@ bool node_init_from_storage(struct mesh_node *node, void *data)
>  
>  	node->primary = db_node->unicast;
>  
> -	memcpy(node->dev_uuid, db_node->uuid, 16);
> -
>  	/* Initialize configuration server model */
>  	mesh_config_srv_init(node, PRIMARY_ELE_IDX);
>  
> @@ -973,20 +972,6 @@ fail:
>  	return false;
>  }
>  
> -void node_id_set(struct mesh_node *node, uint16_t id)
> -{
> -	if (node)
> -		node->id = id;
> -}
> -
> -uint16_t node_id_get(struct mesh_node *node)
> -{
> -	if (!node)
> -		return 0;
> -
> -	return node->id;
> -}
> -
>  static void attach_io(void *a, void *b)
>  {
>  	struct mesh_node *node = a;
> @@ -1005,9 +990,13 @@ void node_attach_io(struct mesh_io *io)
>  /* Register node object with D-Bus */
>  static bool register_node_object(struct mesh_node *node)
>  {
> -	node->path = l_malloc(strlen(MESH_NODE_PATH_PREFIX) + 5);
> +	char uuid[33];
>  
> -	snprintf(node->path, 10, MESH_NODE_PATH_PREFIX "%4.4x", node->id);
> +	if (!hex2str(node->uuid, sizeof(node->uuid), uuid, sizeof(uuid)))
> +		return false;
> +
> +	if (asprintf(&node->path, MESH_NODE_PATH_PREFIX "%s", uuid) < 0)
> +		return false;
>  
>  	if (!l_dbus_object_add_interface(dbus_get_bus(), node->path,
>  					MESH_NODE_INTERFACE, node))
> @@ -1232,8 +1221,6 @@ static void convert_node_to_storage(struct mesh_node *node,
>  	db_node->modes.lpn = node->lpn;
>  	db_node->modes.proxy = node->proxy;
>  
> -	memcpy(db_node->uuid, node->dev_uuid, 16);
> -
>  	db_node->modes.friend = node->friend;
>  	db_node->modes.relay.state = node->relay.mode;
>  	db_node->modes.relay.cnt = node->relay.cnt;
> @@ -1469,7 +1456,7 @@ static void get_managed_objects_cb(struct l_dbus_message *msg, void *user_data)
>  		}
>  		node->num_ele = num_ele;
>  		set_defaults(node);
> -		memcpy(node->dev_uuid, req->data, 16);
> +		memcpy(node->uuid, req->data, 16);
>  
>  		if (!create_node_config(node))
>  			goto fail;
> diff --git a/mesh/node.h b/mesh/node.h
> index 20b60099e..1be4de1da 100644
> --- a/mesh/node.h
> +++ b/mesh/node.h
> @@ -33,7 +33,7 @@ typedef void (*node_ready_func_t) (void *user_data, int status,
>  typedef void (*node_join_ready_func_t) (struct mesh_node *node,
>  						struct mesh_agent *agent);
>  
> -struct mesh_node *node_new(void);
> +struct mesh_node *node_new(const uint8_t uuid[16]);
>  void node_remove(struct mesh_node *node);
>  void node_join(const char *app_path, const char *sender, const uint8_t *uuid,
>  						node_join_ready_func_t cb);
> diff --git a/mesh/storage.c b/mesh/storage.c
> index 8a70b5696..6dc251344 100644
> --- a/mesh/storage.c
> +++ b/mesh/storage.c
> @@ -45,6 +45,7 @@
>  #include "mesh/model.h"
>  #include "mesh/mesh-db.h"
>  #include "mesh/storage.h"
> +#include "mesh/util.h"
>  
>  struct write_info {
>  	json_object *jnode;
> @@ -54,12 +55,6 @@ struct write_info {
>  };
>  
>  static const char *storage_dir;
> -static struct l_queue *node_ids;
> -
> -static bool simple_match(const void *a, const void *b)
> -{
> -	return a == b;
> -}
>  
>  static bool read_node_cb(struct mesh_db_node *db_node, void *user_data)
>  {
> @@ -171,7 +166,7 @@ static bool parse_node(struct mesh_node *node, json_object *jnode)
>  	return true;
>  }
>  
> -static bool parse_config(char *in_file, char *out_file, uint16_t node_id)
> +static bool parse_config(char *in_file, char *out_file, const uint8_t uuid[16])
>  {
>  	int fd;
>  	char *str;
> @@ -208,7 +203,7 @@ static bool parse_config(char *in_file, char *out_file, uint16_t node_id)
>  	if (!jnode)
>  		goto done;
>  
> -	node = node_new();
> +	node = node_new(uuid);
>  
>  	result = parse_node(node, jnode);
>  
> @@ -219,7 +214,6 @@ static bool parse_config(char *in_file, char *out_file, uint16_t node_id)
>  
>  	node_jconfig_set(node, jnode);
>  	node_cfg_file_set(node, out_file);
> -	node_id_set(node, node_id);
>  
>  done:
>  	close(fd);
> @@ -533,44 +527,41 @@ bool storage_load_nodes(const char *dir_name)
>  	}
>  
>  	storage_dir = dir_name;
> -	node_ids = l_queue_new();
>  
>  	while ((entry = readdir(dir)) != NULL) {
> -		char name_buf[PATH_MAX];
> -		char *filename;
> -		uint32_t node_id;
> -		size_t len;
> +		char *cfg;
> +		char *bak;
> +		uint8_t uuid[16];
>  
>  		if (entry->d_type != DT_DIR)
>  			continue;
>  
> -		if (sscanf(entry->d_name, "%04x", &node_id) != 1)
> +		if (!str2hex(entry->d_name, strlen(entry->d_name), uuid, sizeof(uuid)))
>  			continue;
>  
> -		snprintf(name_buf, PATH_MAX, "%s/%s/node.json", dir_name,
> -								entry->d_name);
> -
> -		l_queue_push_tail(node_ids, L_UINT_TO_PTR(node_id));
> -
> -		len = strlen(name_buf);
> -		filename = l_malloc(len + 1);
> -
> -		strncpy(filename, name_buf, len + 1);
> +		if (asprintf(&cfg, "%s/%s/node.json", dir_name,
> +						entry->d_name) < 0)
> +			continue;
>  
> -		if (parse_config(name_buf, filename, node_id))
> +		if (parse_config(cfg, cfg, uuid))
>  			continue;
>  
>  		/* Fall-back to Backup version */
> -		snprintf(name_buf, PATH_MAX, "%s/%s/node.json.bak", dir_name,
> -								entry->d_name);
> +		if (asprintf(&bak, "%s/%s/node.json.bak", dir_name,
> +						entry->d_name) < 0) {
> +			l_free(cfg);
> +			continue;
> +		}
>  
> -		if (parse_config(name_buf, filename, node_id)) {
> -			remove(filename);
> -			rename(name_buf, filename);
> +		if (parse_config(bak, cfg, uuid)) {
> +			remove(cfg);
> +			rename(bak, cfg);
> +			l_free(cfg);
>  			continue;
>  		}
>  
> -		l_free(filename);
> +		l_free(cfg);
> +		l_free(bak);
>  	}
>  
>  	return true;
> @@ -579,12 +570,10 @@ bool storage_load_nodes(const char *dir_name)
>  bool storage_create_node_config(struct mesh_node *node, void *data)
>  {
>  	struct mesh_db_node *db_node = data;
> -	uint16_t node_id;
> -	uint8_t num_tries = 0;
> +	char uuid[33];
>  	char name_buf[PATH_MAX];
>  	char *filename;
>  	json_object *jnode;
> -	size_t len;
>  
>  	if (!storage_dir)
>  		return false;
> @@ -594,28 +583,18 @@ bool storage_create_node_config(struct mesh_node *node, void *data)
>  	if (!mesh_db_add_node(jnode, db_node))
>  		return false;
>  
> -	do {
> -		l_getrandom(&node_id, 2);
> -		if (node_id && !l_queue_find(node_ids, simple_match,
> -						L_UINT_TO_PTR(node_id)))
> -			break;
> -	} while (++num_tries < 10);
> -
> -	if (num_tries == 10)
> -		l_error("Failed to generate unique node ID");
> -
> -	node_id_set(node, node_id);
> +	if (!hex2str(node_uuid_get(node), 16, uuid, sizeof(uuid)))
> +		return false;
>  
> -	snprintf(name_buf, PATH_MAX, "%s/%04x", storage_dir, node_id);
> +	snprintf(name_buf, PATH_MAX, "%s/%s", storage_dir, uuid);
>  
>  	/* Create a new directory and node.json file */
>  	if (mkdir(name_buf, 0755) != 0)
>  		goto fail;
>  
> -	len = strlen(name_buf) + strlen("/node.json") + 1;
> -	filename = l_malloc(len);
> +	if (asprintf(&filename, "%s/node.json", name_buf) < 0)
> +		goto fail;
>  
> -	snprintf(filename, len, "%s/node.json", name_buf);
>  	l_debug("New node config %s", filename);
>  
>  	if (!save_config(jnode, filename)) {
> @@ -626,8 +605,6 @@ bool storage_create_node_config(struct mesh_node *node, void *data)
>  	node_jconfig_set(node, jnode);
>  	node_cfg_file_set(node, filename);
>  
> -	l_queue_push_tail(node_ids, L_UINT_TO_PTR(node_id));
> -
>  	return true;
>  fail:
>  	json_object_put(jnode);
> @@ -637,11 +614,9 @@ fail:
>  /* Permanently remove node configuration */
>  void storage_remove_node_config(struct mesh_node *node)
>  {
> -	char *cfgname;
> +	char *cfg;
>  	struct json_object *jnode;
>  	const char *dir_name;
> -	uint16_t node_id;
> -	size_t len;
>  	char *bak;
>  
>  	if (!node)
> @@ -654,30 +629,26 @@ void storage_remove_node_config(struct mesh_node *node)
>  	node_jconfig_set(node, NULL);
>  
>  	/* Delete node configuration file */
> -	cfgname = (char *) node_cfg_file_get(node);
> -	if (!cfgname)
> +	cfg = node_cfg_file_get(node);
> +	if (!cfg)
>  		return;
>  
> -	l_debug("Delete node config file %s", cfgname);
> -	remove(cfgname);
> +	l_debug("Delete node config file %s", cfg);
> +	remove(cfg);
>  
>  	/* Delete the backup file */
> -	len = strlen(cfgname) + 5;
> -	bak = l_malloc(len);
> -	strncpy(bak, cfgname, len);
> -	bak = strncat(bak, ".bak", 5);
> -	remove(bak);
> -	l_free(bak);
> +	if (asprintf(&bak, "%s.bak", cfg))
> +	{
> +		remove(bak);
> +		l_free(bak);
> +	}
>  
>  	/* Delete the node directory */
> -	dir_name = dirname(cfgname);
> +	dir_name = dirname(cfg);
>  
>  	l_debug("Delete directory %s", dir_name);
>  	rmdir(dir_name);
>  
> -	l_free(cfgname);
> +	l_free(cfg);
>  	node_cfg_file_set(node, NULL);
> -
> -	node_id = node_id_get(node);
> -	l_queue_remove(node_ids, L_UINT_TO_PTR(node_id));
>  }
> 

This looks good. Tested the patch, works as expected.

Thanks,
Inga




[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux