diff options
Diffstat (limited to 'serial/manager.c')
-rw-r--r-- | serial/manager.c | 103 |
1 files changed, 69 insertions, 34 deletions
diff --git a/serial/manager.c b/serial/manager.c index 8eb1b906..8d7af3f9 100644 --- a/serial/manager.c +++ b/serial/manager.c @@ -64,11 +64,13 @@ struct pending_connect { DBusConnection *conn; DBusMessage *msg; + DBusPendingCall *pcall; /* Pending get handles/records */ char *bda; /* Destination address */ char *adapter_path; /* Adapter D-Bus path */ char *pattern; /* Connection request pattern */ bdaddr_t src; uint8_t channel; + guint io_id; /* GIOChannel watch id */ int id; /* RFCOMM device id */ int ntries; /* Open attempts */ int canceled; /* Operation canceled */ @@ -119,15 +121,11 @@ static void pending_connect_free(struct pending_connect *pc) g_free(pc->pattern); if (pc->adapter_path) g_free(pc->adapter_path); + if (pc->pcall) + dbus_pending_call_unref(pc->pcall); g_free(pc); } -static void pending_connect_remove(struct pending_connect *pc) -{ - pending_connects = g_slist_remove(pending_connects, pc); - pending_connect_free(pc); -} - static struct pending_connect *find_pending_connect_by_pattern(const char *bda, const char *pattern) { @@ -258,7 +256,7 @@ static int rfcomm_bind(bdaddr_t *src, bdaddr_t *dst, int16_t dev_id, uint8_t ch) static void open_notify(int fd, int err, void *data) { char port_name[16]; - const char *owner, *pname = port_name; + const char *pname = port_name; struct pending_connect *pc = data; DBusMessage *reply; bdaddr_t dst; @@ -275,14 +273,6 @@ static void open_notify(int fd, int err, void *data) return; } - /* FIXME: it must be a per request listener */ - owner = dbus_message_get_sender(pc->msg); - if (!dbus_bus_name_has_owner(pc->conn, owner, NULL)) { - error("Connect requestor %s exited", owner); - rfcomm_release(pc->id); - return; - } - snprintf(port_name, sizeof(port_name), "/dev/rfcomm%d", pc->id); /* Reply to the requestor */ @@ -299,7 +289,49 @@ static void open_notify(int fd, int err, void *data) DBUS_TYPE_INVALID); str2ba(pc->bda, &dst); - port_add_listener(pc->conn, pc->id, &dst, fd, port_name, owner); + + /* Add the RFCOMM connection listener */ + port_add_listener(pc->conn, pc->id, &dst, fd, + port_name, dbus_message_get_sender(pc->msg)); +} + +static void transaction_owner_exited(const char *name, void *data) +{ + GSList *l, *tmp = NULL; + debug("transaction owner %s exited", name); + + /* Clean all pending calls that belongs to this owner */ + for (l = pending_connects; l != NULL; l = l->next) { + struct pending_connect *pc = l->data; + if (strcmp(name, dbus_message_get_sender(pc->msg)) != 0) { + tmp = g_slist_append(tmp, pc); + continue; + } + + if (pc->pcall) + dbus_pending_call_cancel(pc->pcall); + + if (pc->io_id > 0) + g_source_remove(pc->io_id); + + if (pc->id >= 0) + rfcomm_release(pc->id); + + pending_connect_free(pc); + } + + g_slist_free(pending_connects); + pending_connects = tmp; +} + +static void pending_connect_remove(struct pending_connect *pc) +{ + /* Remove the connection request owner */ + name_listener_remove(pc->conn, dbus_message_get_sender(pc->msg), + (name_cb_t) transaction_owner_exited, NULL); + + pending_connects = g_slist_remove(pending_connects, pc); + pending_connect_free(pc); } static gboolean rfcomm_connect_cb(GIOChannel *chan, @@ -377,8 +409,7 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, open_notify(fd, 0, pc); fail: - pending_connects = g_slist_remove(pending_connects, pc); - pending_connect_free(pc); + pending_connect_remove(pc); if (close_chan) g_io_channel_close(chan); @@ -421,8 +452,8 @@ static int rfcomm_connect(struct pending_connect *pc) } debug("Connect in progress"); - g_io_add_watch(io, G_IO_OUT | G_IO_ERR | G_IO_NVAL | G_IO_HUP, - (GIOFunc) rfcomm_connect_cb, pc); + pc->io_id = g_io_add_watch(io, G_IO_OUT | G_IO_ERR | G_IO_NVAL | G_IO_HUP, + (GIOFunc) rfcomm_connect_cb, pc); } else { debug("Connect succeeded with first try"); (void) rfcomm_connect_cb(io, G_IO_OUT, pc); @@ -551,8 +582,7 @@ static void record_reply(DBusPendingCall *call, void *data) } fail: - pending_connects = g_slist_remove(pending_connects, pc); - pending_connect_free(pc); + pending_connect_remove(pc); done: if (rec) sdp_record_free(rec); @@ -563,7 +593,6 @@ static int get_record(struct pending_connect *pc, uint32_t handle, DBusPendingCallNotifyFunction cb) { DBusMessage *msg; - DBusPendingCall *pending; msg = dbus_message_new_method_call("org.bluez", pc->adapter_path, "org.bluez.Adapter", "GetRemoteServiceRecord"); @@ -575,14 +604,13 @@ static int get_record(struct pending_connect *pc, uint32_t handle, DBUS_TYPE_UINT32, &handle, DBUS_TYPE_INVALID); - if (dbus_connection_send_with_reply(pc->conn, msg, &pending, -1) == FALSE) { + if (dbus_connection_send_with_reply(pc->conn, msg, &pc->pcall, -1) == FALSE) { error("Can't send D-Bus message."); return -1; } - dbus_pending_call_set_notify(pending, cb, pc, NULL); + dbus_pending_call_set_notify(pc->pcall, cb, pc, NULL); dbus_message_unref(msg); - dbus_pending_call_unref(pending); return 0; } @@ -637,15 +665,13 @@ static void handles_reply(DBusPendingCall *call, void *data) return; fail: dbus_message_unref(reply); - pending_connects = g_slist_remove(pending_connects, pc); - pending_connect_free(pc); + pending_connect_remove(pc); } static int get_handles(struct pending_connect *pc, const char *uuid, DBusPendingCallNotifyFunction cb) { DBusMessage *msg; - DBusPendingCall *pending; msg = dbus_message_new_method_call("org.bluez", pc->adapter_path, "org.bluez.Adapter", "GetRemoteServiceHandles"); @@ -657,14 +683,13 @@ static int get_handles(struct pending_connect *pc, const char *uuid, DBUS_TYPE_STRING, &uuid, DBUS_TYPE_INVALID); - if (dbus_connection_send_with_reply(pc->conn, msg, &pending, -1) == FALSE) { + if (dbus_connection_send_with_reply(pc->conn, msg, &pc->pcall, -1) == FALSE) { error("Can't send D-Bus message."); return -1; } - dbus_pending_call_set_notify(pending, cb, pc, NULL); + dbus_pending_call_set_notify(pc->pcall, cb, pc, NULL); dbus_message_unref(msg); - dbus_pending_call_unref(pending); return 0; } @@ -748,6 +773,7 @@ static DBusHandlerResult create_port(DBusConnection *conn, pc->conn = dbus_connection_ref(conn); pc->msg = dbus_message_ref(msg); pc->bda = g_strdup(bda); + pc->id = -1; pc->pattern = g_strdup(pattern); pc->adapter_path = g_malloc0(16); snprintf(pc->adapter_path, 16, "/org/bluez/hci%d", dev_id); @@ -761,6 +787,8 @@ static DBusHandlerResult create_port(DBusConnection *conn, return err_not_supported(conn, msg); } pending_connects = g_slist_append(pending_connects, pc); + name_listener_add(conn, dbus_message_get_sender(msg), + (name_cb_t) transaction_owner_exited, NULL); return DBUS_HANDLER_RESULT_HANDLED; } @@ -784,6 +812,8 @@ static DBusHandlerResult create_port(DBusConnection *conn, return err_not_supported(conn, msg); } pending_connects = g_slist_append(pending_connects, pc); + name_listener_add(conn, dbus_message_get_sender(msg), + (name_cb_t) transaction_owner_exited, NULL); return DBUS_HANDLER_RESULT_HANDLED; } @@ -926,6 +956,7 @@ static DBusHandlerResult connect_service(DBusConnection *conn, pc->conn = dbus_connection_ref(conn); pc->msg = dbus_message_ref(msg); pc->bda = g_strdup(bda); + pc->id = -1; pc->pattern = g_strdup(pattern); pc->adapter_path = g_malloc0(16); snprintf(pc->adapter_path, 16, "/org/bluez/hci%d", dev_id); @@ -939,7 +970,7 @@ static DBusHandlerResult connect_service(DBusConnection *conn, return err_not_supported(conn, msg); } pending_connects = g_slist_append(pending_connects, pc); - return DBUS_HANDLER_RESULT_HANDLED; + goto done; } /* Record handle or channel */ @@ -962,7 +993,7 @@ static DBusHandlerResult connect_service(DBusConnection *conn, return err_not_supported(conn, msg); } pending_connects = g_slist_append(pending_connects, pc); - return DBUS_HANDLER_RESULT_HANDLED; + goto done; } /* RFCOMM Channel range: 1 - 30 */ @@ -984,6 +1015,10 @@ static DBusHandlerResult connect_service(DBusConnection *conn, pending_connect_free(pc); return err_connection_failed(conn, msg, strerr); } +done: + name_listener_add(conn, dbus_message_get_sender(msg), + (name_cb_t) transaction_owner_exited, NULL); + return DBUS_HANDLER_RESULT_HANDLED; } |