diff options
author | Claudio Takahasi <claudio.takahasi@openbossa.org> | 2007-02-27 21:40:12 +0000 |
---|---|---|
committer | Claudio Takahasi <claudio.takahasi@openbossa.org> | 2007-02-27 21:40:12 +0000 |
commit | 40d70645a6e6954eaeb6790d7e191ff8f8d958f3 (patch) | |
tree | 01d0ad760786f7cb8453632ea0be2546babd3c79 | |
parent | d242929462d90d619156709b9188f455d6f1fea3 (diff) |
Input: added verification for pending connection
-rw-r--r-- | input/device.c | 182 |
1 files changed, 83 insertions, 99 deletions
diff --git a/input/device.c b/input/device.c index 3c6c2f12..816342c0 100644 --- a/input/device.c +++ b/input/device.c @@ -79,13 +79,19 @@ struct fake_input { uint8_t ch; /* RFCOMM channel number */ }; +struct pending_connect { + DBusConnection *conn; + DBusMessage *msg; +}; + struct input_device { + bdaddr_t src; bdaddr_t dst; uint8_t major; uint8_t minor; struct hidp_connadd_req hidp; /* FIXME: Use dynamic alloc? */ struct fake_input *fake; - + struct pending_connect *pending_connect; }; struct input_manager { @@ -103,14 +109,7 @@ struct pending_req { sdp_record_t *hid_rec; }; -struct pending_connect { - bdaddr_t src; - bdaddr_t dst; - DBusConnection *conn; - DBusMessage *msg; -}; - -static struct input_device *input_device_new(bdaddr_t *dst, uint32_t cls) +static struct input_device *input_device_new(bdaddr_t *src, bdaddr_t *dst, uint32_t cls) { struct input_device *idev; @@ -120,6 +119,7 @@ static struct input_device *input_device_new(bdaddr_t *dst, uint32_t cls) memset(idev, 0, sizeof(struct input_device)); + bacpy(&idev->src, src); bacpy(&idev->dst, dst); idev->major = (cls >> 8) & 0x1f; @@ -128,6 +128,17 @@ static struct input_device *input_device_new(bdaddr_t *dst, uint32_t cls) return idev; } +static void pending_connect_free(struct pending_connect *pc) +{ + if (!pc) + return; + if (pc->conn) + dbus_connection_unref(pc->conn); + if (pc->msg) + dbus_message_unref(pc->msg); + free(pc); +} + static void input_device_free(struct input_device *idev) { if (!idev) @@ -136,6 +147,9 @@ static void input_device_free(struct input_device *idev) free(idev->hidp.rd_data); if (idev->fake) free(idev->fake); + if (idev->pending_connect) + pending_connect_free(idev->pending_connect); + free(idev); } @@ -175,34 +189,6 @@ static void pending_req_free(struct pending_req *pr) free(pr); } -static struct pending_connect *pending_connect_new(bdaddr_t *src, bdaddr_t *dst, - DBusConnection *conn, DBusMessage *msg) -{ - struct pending_connect *pc; - pc = malloc(sizeof(struct pending_connect)); - if (!pc) - return NULL; - - memset(pc, 0, sizeof(struct pending_connect)); - bacpy(&pc->src, src); - bacpy(&pc->dst, dst); - pc->conn = dbus_connection_ref(conn); - pc->msg = dbus_message_ref(msg); - - return pc; -} - -static void pending_connect_free(struct pending_connect *pc) -{ - if (!pc) - return; - if (pc->conn) - dbus_connection_unref(pc->conn); - if (pc->msg) - dbus_message_unref(pc->msg); - free(pc); -} - /* * Common D-Bus BlueZ input error functions */ @@ -573,18 +559,14 @@ failed: return FALSE; } -static gboolean rfcomm_connect_cb(GIOChannel *chan, - GIOCondition cond, struct pending_connect *pc) +static gboolean rfcomm_connect_cb(GIOChannel *chan, GIOCondition cond, + struct input_device *idev) { - struct input_device *idev; struct fake_input *fake; DBusMessage *reply; - const char *path; socklen_t len; int ret, err; - path = dbus_message_get_path(pc->msg); - dbus_connection_get_object_path_data(pc->conn, path, (void *) &idev); fake = idev->fake; if (cond & G_IO_NVAL) { @@ -628,24 +610,27 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, g_io_add_watch(fake->io, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, (GIOFunc) rfcomm_io_cb, fake); - reply = dbus_message_new_method_return(pc->msg); + reply = dbus_message_new_method_return(idev->pending_connect->msg); if (reply) { dbus_connection_send(connection, reply, NULL); dbus_message_unref(reply); } - pending_connect_free(pc); + pending_connect_free(idev->pending_connect); + idev->pending_connect = NULL; g_io_channel_unref(chan); return FALSE; failed: - err_connection_failed(pc->conn, pc->msg, strerror(err)); - pending_connect_free(pc); + err_connection_failed(idev->pending_connect->conn, + idev->pending_connect->msg, strerror(err)); + pending_connect_free(idev->pending_connect); + idev->pending_connect = NULL; g_io_channel_unref(chan); return FALSE; } -static int rfcomm_connect(struct pending_connect *pc, uint8_t ch) +static int rfcomm_connect(struct input_device *idev) { struct sockaddr_rc addr; GIOChannel *io; @@ -669,7 +654,7 @@ static int rfcomm_connect(struct pending_connect *pc, uint8_t ch) memset(&addr, 0, sizeof(addr)); addr.rc_family = AF_BLUETOOTH; - bacpy(&addr.rc_bdaddr, &pc->src); + bacpy(&addr.rc_bdaddr, &idev->src); addr.rc_channel = 0; if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { @@ -686,8 +671,8 @@ static int rfcomm_connect(struct pending_connect *pc, uint8_t ch) memset(&addr, 0, sizeof(addr)); addr.rc_family = AF_BLUETOOTH; - bacpy(&addr.rc_bdaddr, &pc->dst); - addr.rc_channel = ch; + bacpy(&addr.rc_bdaddr, &idev->dst); + addr.rc_channel = idev->fake->ch; if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { char peer[18]; /* FIXME: debug purpose */ if (!(errno == EAGAIN || errno == EINPROGRESS)) { @@ -697,13 +682,13 @@ static int rfcomm_connect(struct pending_connect *pc, uint8_t ch) goto failed; } - ba2str(&pc->dst, peer); - debug("RFCOMM connection in progress: %s channel:%d", peer, ch); + ba2str(&idev->dst, peer); + debug("RFCOMM connection in progress: %s channel:%d", peer, idev->fake->ch); g_io_add_watch(io, G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL, - (GIOFunc) rfcomm_connect_cb, pc); + (GIOFunc) rfcomm_connect_cb, idev); } else { debug("Connect succeeded with first try"); - rfcomm_connect_cb(io, G_IO_OUT, pc); + rfcomm_connect_cb(io, G_IO_OUT, idev); } return 0; @@ -718,8 +703,8 @@ failed: return -err; } -static int l2cap_connect(struct pending_connect *pc, - unsigned short psm, GIOFunc cb) +static int l2cap_connect(struct input_device *idev, + unsigned short psm, GIOFunc cb) { GIOChannel *io; struct sockaddr_l2 addr; @@ -731,7 +716,7 @@ static int l2cap_connect(struct pending_connect *pc, memset(&addr, 0, sizeof(addr)); addr.l2_family = AF_BLUETOOTH; - bacpy(&addr.l2_bdaddr, &pc->src); + bacpy(&addr.l2_bdaddr, &idev->src); if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) goto failed; @@ -749,7 +734,7 @@ static int l2cap_connect(struct pending_connect *pc, memset(&addr, 0, sizeof(addr)); addr.l2_family = AF_BLUETOOTH; - bacpy(&addr.l2_bdaddr, &pc->dst); + bacpy(&addr.l2_bdaddr, &idev->dst); addr.l2_psm = htobs(psm); io = g_io_channel_unix_new(sk); @@ -759,9 +744,9 @@ static int l2cap_connect(struct pending_connect *pc, if (!(errno == EAGAIN || errno == EINPROGRESS)) goto failed; - g_io_add_watch(io, G_IO_OUT, (GIOFunc) cb, pc); + g_io_add_watch(io, G_IO_OUT, (GIOFunc) cb, idev); } else { - cb(io, G_IO_OUT, pc); + cb(io, G_IO_OUT, idev); } return 0; @@ -775,15 +760,10 @@ failed: } static gboolean interrupt_connect_cb(GIOChannel *chan, GIOCondition cond, - struct pending_connect *pc) + struct input_device *idev) { - struct input_device *idev; int ctl, isk, ret, err; socklen_t len; - const char *path; - - path = dbus_message_get_path(pc->msg); - dbus_connection_get_object_path_data(pc->conn, path, (void *) &idev); if (cond & G_IO_NVAL) { err = EHOSTDOWN; @@ -816,7 +796,7 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, GIOCondition cond, } if (idev->hidp.subclass & 0x40) { - err = encrypt_link(&pc->src, &pc->dst); + err = encrypt_link(&idev->src, &idev->dst); if (err < 0) { close(ctl); goto failed; @@ -830,13 +810,14 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, GIOCondition cond, } - send_message_and_unref(pc->conn, - dbus_message_new_method_return(pc->msg)); + send_message_and_unref(idev->pending_connect->conn, + dbus_message_new_method_return(idev->pending_connect->msg)); close (ctl); goto cleanup; failed: - err_connection_failed(pc->conn, pc->msg, strerror(err)); + err_connection_failed(idev->pending_connect->conn, + idev->pending_connect->msg, strerror(err)); cleanup: if (isk > 0) @@ -847,22 +828,18 @@ cleanup: idev->hidp.intr_sock = -1; idev->hidp.ctrl_sock = -1; - pending_connect_free(pc); + pending_connect_free(idev->pending_connect); + idev->pending_connect = NULL; g_io_channel_unref(chan); return FALSE; } static gboolean control_connect_cb(GIOChannel *chan, GIOCondition cond, - struct pending_connect *pc) + struct input_device *idev) { - struct input_device *idev; int ret, csk, err; socklen_t len; - const char *path; - - path = dbus_message_get_path(pc->msg); - dbus_connection_get_object_path_data(pc->conn, path, (void *) &idev); if (cond & G_IO_NVAL) { err = EHOSTDOWN; @@ -888,7 +865,7 @@ static gboolean control_connect_cb(GIOChannel *chan, GIOCondition cond, } /* Connect to the HID interrupt channel */ - if (l2cap_connect(pc, L2CAP_PSM_HIDP_INTR, + if (l2cap_connect(idev, L2CAP_PSM_HIDP_INTR, (GIOFunc) interrupt_connect_cb) < 0) { err = errno; @@ -904,8 +881,10 @@ failed: close(csk); idev->hidp.ctrl_sock = -1; - err_connection_failed(pc->conn, pc->msg, strerror(err)); - pending_connect_free(pc); + err_connection_failed(idev->pending_connect->conn, + idev->pending_connect->msg, strerror(err)); + pending_connect_free(idev->pending_connect); + idev->pending_connect = NULL; g_io_channel_unref(chan); return FALSE; @@ -970,7 +949,7 @@ fail: idev->hidp.intr_sock = -1; idev->hidp.ctrl_sock = -1; - return -errno; + return -err; } static int is_connected(struct input_device *idev) @@ -1014,36 +993,41 @@ static DBusHandlerResult device_connect(DBusConnection *conn, DBusMessage *msg, void *data) { struct input_device *idev = data; - struct fake_input *fake = idev->fake; - struct input_manager *mgr; - struct pending_connect *pc; + + if (idev->pending_connect) + return err_connection_failed(conn, msg, "Connection in progress"); if (is_connected(idev)) return err_connection_failed(conn, msg, "Already connected"); - /* FIXME: Check if there is a pending connection */ - - dbus_connection_get_object_path_data(conn, INPUT_PATH, (void *) &mgr); - pc = pending_connect_new(&mgr->src, &idev->dst, conn, msg); - if (!pc) + idev->pending_connect = malloc(sizeof(struct pending_connect)); + if (!idev->pending_connect) { + error("Out of memory when allocating new struct pending_connect"); return DBUS_HANDLER_RESULT_NEED_MEMORY; + } + + memset(idev->pending_connect, 0, sizeof(struct pending_connect)); + idev->pending_connect->conn = dbus_connection_ref(conn); + idev->pending_connect->msg = dbus_message_ref(msg); /* Fake input device */ - if (fake) { - if (rfcomm_connect(pc, fake->ch) < 0) { + if (idev->fake) { + if (rfcomm_connect(idev) < 0) { const char *str = strerror(errno); error("RFCOMM connect failed: %s(%d)", str, errno); - pending_connect_free(pc); + pending_connect_free(idev->pending_connect); + idev->pending_connect = NULL; return err_connection_failed(conn, msg, str); } return DBUS_HANDLER_RESULT_HANDLED; } /* HID devices */ - if (l2cap_connect(pc, L2CAP_PSM_HIDP_CTRL, + if (l2cap_connect(idev, L2CAP_PSM_HIDP_CTRL, (GIOFunc) control_connect_cb) < 0) { error("L2CAP connect failed: %s(%d)", strerror(errno), errno); - pending_connect_free(pc); + pending_connect_free(idev->pending_connect); + idev->pending_connect = NULL; return err_connection_failed(conn, msg, strerror(errno)); } @@ -1422,7 +1406,7 @@ static void hid_record_reply(DBusPendingCall *call, void *data) goto fail; } - idev = input_device_new(&pr->dst, cls); + idev = input_device_new(&pr->src, &pr->dst, cls); extract_hid_record(pr->hid_rec, &idev->hidp); if (pr->pnp_rec) @@ -1656,7 +1640,7 @@ static void headset_record_reply(DBusPendingCall *call, void *data) goto fail; } - idev = input_device_new(&pr->dst, cls); + idev = input_device_new(&pr->src, &pr->dst, cls); if (!idev) { error("Out of memory when allocating new input"); goto fail; @@ -1776,7 +1760,7 @@ static DBusHandlerResult manager_create_device(DBusConnection *conn, return err_not_supported(conn, msg); } - idev = input_device_new(&dst, cls); + idev = input_device_new(&mgr->src, &dst, cls); if (!idev) return DBUS_HANDLER_RESULT_NEED_MEMORY; @@ -1958,7 +1942,7 @@ static void stored_input(char *key, char *value, void *data) if (get_class(src, &dst, &cls) < 0) return; - idev = input_device_new(&dst, cls); + idev = input_device_new(src, &dst, cls); if (parse_stored_device_info(value, &idev->hidp) < 0) { input_device_free(idev); return; |