[RFC BlueZ] mesh: Allow calls to Attach/Leave before replying to JoinComplete

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

 



Instead of failing with "busy", process the call after application
replies to JoinComplete.
---

Inga, Brian,

What do ayou think about this approach? It's a bit more complicated, but
it doesn't impose any restrictions on the application.

 doc/mesh-api.txt |  2 --
 mesh/mesh.c      | 73 +++++++++++++++++++++++++++++++++++++++++++-----
 mesh/node.c      | 38 ++++++++++++-------------
 mesh/node.h      |  8 +++---
 4 files changed, 88 insertions(+), 33 deletions(-)

diff --git a/doc/mesh-api.txt b/doc/mesh-api.txt
index c4440d5fa..a3bf6bb39 100644
--- a/doc/mesh-api.txt
+++ b/doc/mesh-api.txt
@@ -116,7 +116,6 @@ Methods:
 			org.bluez.mesh.Error.InvalidArguments
 			org.bluez.mesh.Error.NotFound,
 			org.bluez.mesh.Error.AlreadyExists,
-			org.bluez.mesh.Error.Busy,
 			org.bluez.mesh.Error.Failed
 
 	void Leave(uint64 token)
@@ -128,7 +127,6 @@ Methods:
 		PossibleErrors:
 			org.bluez.mesh.Error.InvalidArguments
 			org.bluez.mesh.Error.NotFound
-			org.bluez.mesh.Error.Busy
 
 	void CreateNetwork(object app_root, array{byte}[16] uuid)
 
diff --git a/mesh/mesh.c b/mesh/mesh.c
index f6f734725..4189e6435 100644
--- a/mesh/mesh.c
+++ b/mesh/mesh.c
@@ -70,7 +70,7 @@ struct bt_mesh {
 	bool initialized;
 };
 
-struct join_data{
+struct join_data {
 	struct l_dbus_message *msg;
 	char *sender;
 	struct mesh_node *node;
@@ -78,6 +78,13 @@ struct join_data{
 	uint8_t *uuid;
 };
 
+struct call_data {
+	struct mesh_node *node;
+	l_dbus_interface_method_cb_t cb;
+	struct l_dbus_message *msg;
+	void *user_data;
+};
+
 struct mesh_init_request {
 	mesh_ready_func_t cb;
 	void *user_data;
@@ -102,6 +109,8 @@ static struct join_data *join_pending;
 /* Pending method requests */
 static struct l_queue *pending_queue;
 
+static struct l_queue *pending_calls;
+
 static const char *storage_dir;
 
 static bool simple_match(const void *a, const void *b)
@@ -109,6 +118,14 @@ static bool simple_match(const void *a, const void *b)
 	return a == b;
 }
 
+static bool match_call_node(const void *a, const void *b)
+{
+	const struct call_data *call = a;
+	const struct mesh_node *node = b;
+
+	return call->node == node;
+}
+
 /* Used for any outbound traffic that doesn't have Friendship Constraints */
 /* This includes Beacons, Provisioning and unrestricted Network Traffic */
 bool mesh_send_pkt(uint8_t count, uint16_t interval,
@@ -298,6 +315,7 @@ bool mesh_init(const char *config_dir, const char *mesh_conf_fname,
 	mesh.max_filters = caps.max_num_filters;
 
 	pending_queue = l_queue_new();
+	pending_calls = l_queue_new();
 
 	return true;
 }
@@ -349,6 +367,7 @@ void mesh_cleanup(void)
 	}
 
 	l_queue_destroy(pending_queue, pending_request_exit);
+	l_queue_destroy(pending_calls, pending_request_exit);
 	mesh_agent_cleanup();
 	node_cleanup_all();
 	mesh_model_cleanup();
@@ -439,6 +458,37 @@ static void send_join_failed(const char *owner, const char *path,
 	free_pending_join_call(true);
 }
 
+static void queue_pending_call(struct mesh_node *node,
+				l_dbus_interface_method_cb_t cb,
+				struct l_dbus_message *msg, void *user_data)
+{
+	struct call_data *pending_call = l_new(struct call_data, 1);
+	pending_call->node = node;
+	pending_call->cb = cb;
+	pending_call->msg = l_dbus_message_ref(msg);
+	pending_call->user_data = user_data;
+
+	l_queue_push_tail(pending_calls, pending_call);
+}
+
+static void process_pending_call(struct mesh_node *node)
+{
+	struct l_dbus *dbus = dbus_get_bus();
+	struct call_data *pending_call;
+	struct l_dbus_message *reply;
+
+	pending_call = l_queue_remove_if(pending_calls, match_call_node);
+	if (!pending_call)
+		return;
+
+	reply = pending_call->cb(dbus, pending_call->msg,
+						pending_call->user_data);
+	if (reply)
+		l_dbus_send(dbus, reply);
+
+	l_dbus_message_unref(pending_call->msg);
+}
+
 static void prov_join_complete_reply_cb(struct l_dbus_message *msg,
 								void *user_data)
 {
@@ -447,8 +497,10 @@ static void prov_join_complete_reply_cb(struct l_dbus_message *msg,
 	if (!msg || l_dbus_message_is_error(msg))
 		failed = true;
 
-	if (!failed)
+	if (!failed) {
 		node_finalize_new_node(join_pending->node, mesh.io);
+		process_pending_call(join_pending->node);
+	}
 
 	free_pending_join_call(failed);
 }
@@ -645,7 +697,12 @@ static struct l_dbus_message *attach_call(struct l_dbus *dbus,
 	pending_msg = l_dbus_message_ref(msg);
 	l_queue_push_tail(pending_queue, pending_msg);
 
-	node_attach(app_path, sender, token, attach_ready_cb, pending_msg);
+	if (!node_attach(app_path, sender, token, attach_ready_cb,
+								pending_msg)) {
+
+		struct mesh_node *node = node_find_by_token(token);
+		queue_pending_call(node, attach_call, msg, user_data);
+	}
 
 	return NULL;
 }
@@ -666,10 +723,11 @@ static struct l_dbus_message *leave_call(struct l_dbus *dbus,
 	if (!node)
 		return dbus_error(msg, MESH_ERROR_NOT_FOUND, NULL);
 
-	if (node_is_busy(node))
-		return dbus_error(msg, MESH_ERROR_BUSY, NULL);
-
-	node_remove(node);
+	if (!node_remove(node))
+	{
+		queue_pending_call(node, leave_call, msg, user_data);
+		return NULL;
+	}
 
 	return l_dbus_message_new_method_return(msg);
 }
@@ -685,6 +743,7 @@ static void create_join_complete_reply_cb(struct l_dbus_message *msg,
 	}
 
 	node_finalize_new_node(node, mesh.io);
+	process_pending_call(node);
 }
 
 static void create_node_ready_cb(void *user_data, int status,
diff --git a/mesh/node.c b/mesh/node.c
index 39fb0dd02..dcc6bc58b 100644
--- a/mesh/node.c
+++ b/mesh/node.c
@@ -345,16 +345,20 @@ static void free_node_resources(void *data)
  * This function is called to free resources and remove the
  * configuration files for the specified node.
  */
-void node_remove(struct mesh_node *node)
+bool node_remove(struct mesh_node *node)
 {
 	if (!node)
-		return;
+		return true;
+
+	if (node->busy)
+		return false;
 
 	l_queue_remove(nodes, node);
 
 	mesh_config_destroy_nvm(node->cfg);
 
 	free_node_resources(node);
+	return true;
 }
 
 static bool add_models_from_storage(struct mesh_node *node,
@@ -599,11 +603,6 @@ bool node_is_provisioner(struct mesh_node *node)
 	return node->provisioner;
 }
 
-bool node_is_busy(struct mesh_node *node)
-{
-	return node->busy;
-}
-
 void node_app_key_delete(struct mesh_node *node, uint16_t net_idx,
 							uint16_t app_idx)
 {
@@ -1657,31 +1656,29 @@ static void send_managed_objects_request(const char *destination,
 }
 
 /* Establish relationship between application and mesh node */
-void node_attach(const char *app_root, const char *sender, uint64_t token,
-					node_ready_func_t cb, void *user_data)
+bool node_attach(const char *app_root, const char *sender, uint64_t token,
+					node_ready_func_t cb,
+					struct l_dbus_message *pending_msg)
 {
 	struct managed_obj_request *req;
 	struct mesh_node *node;
 
 	node = l_queue_find(nodes, match_token, (void *) &token);
 	if (!node) {
-		cb(user_data, MESH_ERROR_NOT_FOUND, NULL);
-		return;
-	}
-
-	/* Check if there is a pending request associated with this node */
-	if (node->busy) {
-		cb(user_data, MESH_ERROR_BUSY, NULL);
-		return;
+		cb(pending_msg, MESH_ERROR_NOT_FOUND, NULL);
+		return true;
 	}
 
 	/* Check if the node is already in use */
 	if (node->owner) {
 		l_warn("The node is already in use");
-		cb(user_data, MESH_ERROR_ALREADY_EXISTS, NULL);
-		return;
+		cb(pending_msg, MESH_ERROR_ALREADY_EXISTS, NULL);
+		return true;
 	}
 
+	if (node->busy)
+		return false;
+
 	req = l_new(struct managed_obj_request, 1);
 
 	/*
@@ -1691,13 +1688,14 @@ void node_attach(const char *app_root, const char *sender, uint64_t token,
 	req->node = node_new(node->uuid);
 	req->node->owner = l_strdup(sender);
 	req->ready_cb = cb;
-	req->pending_msg = user_data;
+	req->pending_msg = pending_msg;
 	req->attach = node;
 	req->type = REQUEST_TYPE_ATTACH;
 
 	node->busy = true;
 
 	send_managed_objects_request(sender, app_root, req);
+	return true;
 }
 
 /* Create a temporary pre-provisioned node */
diff --git a/mesh/node.h b/mesh/node.h
index b8b2b1b49..34432bd5b 100644
--- a/mesh/node.h
+++ b/mesh/node.h
@@ -30,7 +30,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);
 
-void node_remove(struct mesh_node *node);
+bool node_remove(struct mesh_node *node);
 void node_join(const char *app_root, const char *sender, const uint8_t *uuid,
 						node_join_ready_func_t cb);
 uint8_t *node_uuid_get(struct mesh_node *node);
@@ -39,7 +39,6 @@ struct mesh_node *node_find_by_addr(uint16_t addr);
 struct mesh_node *node_find_by_uuid(uint8_t uuid[16]);
 struct mesh_node *node_find_by_token(uint64_t token);
 bool node_is_provisioner(struct mesh_node *node);
-bool node_is_busy(struct mesh_node *node);
 void node_app_key_delete(struct mesh_node *node, uint16_t net_idx,
 							uint16_t app_idx);
 uint16_t node_get_primary(struct mesh_node *node);
@@ -81,8 +80,9 @@ const char *node_get_app_path(struct mesh_node *node);
 bool node_add_pending_local(struct mesh_node *node, void *info);
 void node_attach_io_all(struct mesh_io *io);
 void node_attach_io(struct mesh_node *node, struct mesh_io *io);
-void node_attach(const char *app_root, const char *sender, uint64_t token,
-					node_ready_func_t cb, void *user_data);
+bool node_attach(const char *app_root, const char *sender, uint64_t token,
+					node_ready_func_t cb,
+					struct l_dbus_message *pending_msg);
 void node_build_attach_reply(struct mesh_node *node,
 						struct l_dbus_message *reply);
 void node_create(const char *app_root, const char *sender, const uint8_t *uuid,
-- 
2.20.1




[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