From 5862f2f6a58866e4c4321020e23c082821be3e00 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Tue, 18 Feb 2014 14:05:14 +0100 Subject: [PATCH] android: Add support for registering disconnect callback in IPC 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 3d6e2a386..a996935c8 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 601301c6b..63b751d6b 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 9f224869c..01f0b9212 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 054af84e0..9b736a22a 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); -- 2.47.3