[PATCH 2/6] android: Add support for registering disconnect callback in IPC

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

 



Allow to register callback which is called in case of IPC failure
(eg malformed message) or disconnection. This makes caller responsible
for performing expected action in such case.
---
 android/ipc.c      | 106 ++++++++++++++++++++++++++++++++++-------------------
 android/ipc.h      |   5 ++-
 android/main.c     |   7 +++-
 android/test-ipc.c |   8 ++--
 4 files changed, 83 insertions(+), 43 deletions(-)

diff --git a/android/ipc.c b/android/ipc.c
index 3d6e2a3..a996935 100644
--- a/android/ipc.c
+++ b/android/ipc.c
@@ -52,8 +52,42 @@ struct ipc {
 
 	GIOChannel *notif_io;
 	guint notif_watch;
+
+	ipc_disconnect_cb disconnect_cb;
+	void *disconnect_cb_data;
 };
 
+static void ipc_disconnect(struct ipc *ipc, bool in_cleanup)
+{
+	if (ipc->cmd_watch) {
+		g_source_remove(ipc->cmd_watch);
+		ipc->cmd_watch = 0;
+	}
+
+	if (ipc->cmd_io) {
+		g_io_channel_shutdown(ipc->cmd_io, TRUE, NULL);
+		g_io_channel_unref(ipc->cmd_io);
+		ipc->cmd_io = NULL;
+	}
+
+	if (ipc->notif_watch) {
+		g_source_remove(ipc->notif_watch);
+		ipc->notif_watch = 0;
+	}
+
+	if (ipc->notif_io) {
+		g_io_channel_shutdown(ipc->notif_io, TRUE, NULL);
+		g_io_channel_unref(ipc->notif_io);
+		ipc->notif_io = NULL;
+	}
+
+	if (in_cleanup)
+		return;
+
+	if (ipc->disconnect_cb)
+		ipc->disconnect_cb(ipc->disconnect_cb_data);
+}
+
 int ipc_handle_msg(struct service_handler *handlers, size_t max_index,
 						const void *buf, ssize_t len)
 {
@@ -116,7 +150,9 @@ static gboolean cmd_watch_cb(GIOChannel *io, GIOCondition cond,
 	int fd, err;
 
 	if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
-		info("IPC: command socket closed, terminating");
+		info("IPC: command socket closed");
+
+		ipc->cmd_watch = 0;
 		goto fail;
 	}
 
@@ -124,30 +160,34 @@ static gboolean cmd_watch_cb(GIOChannel *io, GIOCondition cond,
 
 	ret = read(fd, buf, sizeof(buf));
 	if (ret < 0) {
-		error("IPC: command read failed, terminating (%s)",
-							strerror(errno));
+		error("IPC: command read failed (%s)", strerror(errno));
 		goto fail;
 	}
 
 	err = ipc_handle_msg(ipc->services, ipc->service_max, buf, ret);
 	if (err < 0) {
-		error("IPC: failed to handle message, terminating (%s)",
-							strerror(-err));
+		error("IPC: failed to handle message (%s)", strerror(-err));
 		goto fail;
 	}
 
 	return TRUE;
 
 fail:
-	raise(SIGTERM);
+	ipc_disconnect(ipc, false);
+
 	return FALSE;
 }
 
 static gboolean notif_watch_cb(GIOChannel *io, GIOCondition cond,
 							gpointer user_data)
 {
-	info("IPC: notification socket closed, terminating");
-	raise(SIGTERM);
+	struct ipc *ipc = user_data;
+
+	info("IPC: notification socket closed");
+
+	ipc->notif_watch = 0;
+
+	ipc_disconnect(ipc, false);
 
 	return FALSE;
 }
@@ -194,8 +234,10 @@ static gboolean notif_connect_cb(GIOChannel *io, GIOCondition cond,
 	DBG("");
 
 	if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
-		error("IPC: notification socket connect failed, terminating");
-		raise(SIGTERM);
+		error("IPC: notification socket connect failed");
+
+		ipc_disconnect(ipc, false);
+
 		return FALSE;
 	}
 
@@ -220,20 +262,25 @@ static gboolean cmd_connect_cb(GIOChannel *io, GIOCondition cond,
 	DBG("");
 
 	if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
-		error("IPC: command socket connect failed, terminating");
-		raise(SIGTERM);
-		return FALSE;
+		error("IPC: command socket connect failed");
+		goto failed;
 	}
 
 	ipc->notif_io = ipc_connect(ipc->path, ipc->size, notif_connect_cb,
 									ipc);
 	if (!ipc->notif_io)
-		raise(SIGTERM);
+		goto failed;
+
+	return FALSE;
+
+failed:
+	ipc_disconnect(ipc, false);
 
 	return FALSE;
 }
 
-struct ipc *ipc_init(const char *path, size_t size, int max_service_id)
+struct ipc *ipc_init(const char *path, size_t size, int max_service_id,
+					ipc_disconnect_cb cb, void *cb_data)
 {
 	struct ipc *ipc;
 
@@ -252,32 +299,15 @@ struct ipc *ipc_init(const char *path, size_t size, int max_service_id)
 		return NULL;
 	}
 
+	ipc->disconnect_cb = cb;
+	ipc->disconnect_cb_data = cb_data;
+
 	return ipc;
 }
 
 void ipc_cleanup(struct ipc *ipc)
 {
-	if (ipc->cmd_watch) {
-		g_source_remove(ipc->cmd_watch);
-		ipc->cmd_watch = 0;
-	}
-
-	if (ipc->cmd_io) {
-		g_io_channel_shutdown(ipc->cmd_io, TRUE, NULL);
-		g_io_channel_unref(ipc->cmd_io);
-		ipc->cmd_io = NULL;
-	}
-
-	if (ipc->notif_watch) {
-		g_source_remove(ipc->notif_watch);
-		ipc->notif_watch = 0;
-	}
-
-	if (ipc->notif_io) {
-		g_io_channel_shutdown(ipc->notif_io, TRUE, NULL);
-		g_io_channel_unref(ipc->notif_io);
-		ipc->notif_io = NULL;
-	}
+	ipc_disconnect(ipc, true);
 
 	g_free(ipc->services);
 	g_free(ipc);
@@ -323,7 +353,9 @@ void ipc_send(int sk, uint8_t service_id, uint8_t opcode, uint16_t len,
 	}
 
 	if (sendmsg(sk, &msg, 0) < 0) {
-		error("IPC send failed, terminating :%s", strerror(errno));
+		error("IPC send failed :%s", strerror(errno));
+
+		/* TODO disconnect IPC here when this function becomes static */
 		raise(SIGTERM);
 	}
 }
diff --git a/android/ipc.h b/android/ipc.h
index 601301c..63b751d 100644
--- a/android/ipc.h
+++ b/android/ipc.h
@@ -34,7 +34,10 @@ struct service_handler {
 
 struct ipc;
 
-struct ipc *ipc_init(const char *path, size_t size, int max_service_id);
+typedef void (*ipc_disconnect_cb) (void *data);
+
+struct ipc *ipc_init(const char *path, size_t size, int max_service_id,
+					ipc_disconnect_cb cb, void *cb_data);
 void ipc_cleanup(struct ipc *ipc);
 
 GIOChannel *ipc_connect(const char *path, size_t size, GIOFunc connect_cb,
diff --git a/android/main.c b/android/main.c
index 9f22486..01f0b92 100644
--- a/android/main.c
+++ b/android/main.c
@@ -228,6 +228,11 @@ static void stop_bluetooth(void)
 	g_timeout_add_seconds(SHUTDOWN_GRACE_SECONDS, quit_eventloop, NULL);
 }
 
+static void ipc_disconnected(void *data)
+{
+	stop_bluetooth();
+}
+
 static void adapter_ready(int err, const bdaddr_t *addr)
 {
 	if (err < 0) {
@@ -245,7 +250,7 @@ static void adapter_ready(int err, const bdaddr_t *addr)
 	info("Adapter initialized");
 
 	hal_ipc = ipc_init(BLUEZ_HAL_SK_PATH, sizeof(BLUEZ_HAL_SK_PATH),
-							HAL_SERVICE_ID_MAX);
+				HAL_SERVICE_ID_MAX, ipc_disconnected, NULL);
 	if (!hal_ipc) {
 		error("Failed to initialize IPC");
 		exit(EXIT_FAILURE);
diff --git a/android/test-ipc.c b/android/test-ipc.c
index 054af84..9b736a2 100644
--- a/android/test-ipc.c
+++ b/android/test-ipc.c
@@ -286,7 +286,7 @@ static void test_init(gconstpointer data)
 	struct context *context = create_context(data);
 
 	ipc = ipc_init(BLUEZ_HAL_SK_PATH, sizeof(BLUEZ_HAL_SK_PATH),
-							HAL_SERVICE_ID_MAX);
+						HAL_SERVICE_ID_MAX, NULL, NULL);
 
 	g_assert(ipc);
 
@@ -337,7 +337,7 @@ static void test_cmd(gconstpointer data)
 	struct context *context = create_context(data);
 
 	ipc = ipc_init(BLUEZ_HAL_SK_PATH, sizeof(BLUEZ_HAL_SK_PATH),
-							HAL_SERVICE_ID_MAX);
+						HAL_SERVICE_ID_MAX, NULL, NULL);
 
 	g_assert(ipc);
 
@@ -355,7 +355,7 @@ static void test_cmd_reg(gconstpointer data)
 	const struct test_data *test_data = context->data;
 
 	ipc = ipc_init(BLUEZ_HAL_SK_PATH, sizeof(BLUEZ_HAL_SK_PATH),
-							HAL_SERVICE_ID_MAX);
+						HAL_SERVICE_ID_MAX, NULL, NULL);
 
 	g_assert(ipc);
 
@@ -375,7 +375,7 @@ static void test_cmd_reg_1(gconstpointer data)
 	struct context *context = create_context(data);
 
 	ipc = ipc_init(BLUEZ_HAL_SK_PATH, sizeof(BLUEZ_HAL_SK_PATH),
-							HAL_SERVICE_ID_MAX);
+						HAL_SERVICE_ID_MAX, NULL, NULL);
 
 	g_assert(ipc);
 
-- 
1.8.3.2

--
To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[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