summaryrefslogtreecommitdiff
path: root/android/ipc.c
diff options
context:
space:
mode:
authorSzymon Janc <szymon.janc@tieto.com>2014-02-18 14:05:14 +0100
committerSzymon Janc <szymon.janc@tieto.com>2014-02-28 15:22:45 +0100
commit5862f2f6a58866e4c4321020e23c082821be3e00 (patch)
tree7e3123bbb6f8f84cdf86172641d3bef1d6dcad29 /android/ipc.c
parentdd1e44fce160c1883d8600ff2816a3403c967b12 (diff)
downloadbluez-5862f2f6a58866e4c4321020e23c082821be3e00.tar.gz
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.
Diffstat (limited to 'android/ipc.c')
-rw-r--r--android/ipc.c106
1 files changed, 69 insertions, 37 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);
}
}