diff options
author | Luiz Augusto von Dentz <luiz.dentz@openbossa.org> | 2009-04-09 10:45:26 -0300 |
---|---|---|
committer | Johan Hedberg <johan.hedberg@nokia.com> | 2009-04-11 18:29:47 +0300 |
commit | eeb8599f0bbf78340d7c40d9eac6ba123f60f5cc (patch) | |
tree | 4e59f0c8f017ddb774b72a9b1cc1ab9b045ddfce | |
parent | a32df6e52f95134d51592404162a1bf99571110f (diff) | |
download | bluez-eeb8599f0bbf78340d7c40d9eac6ba123f60f5cc.tar.gz |
Make serial port to not use channels from record storage.
Some devices are known to change the channels of its records so the storage
might become invalid over time. The solution is to always attempt to retrieve
the channel when connecting.
-rw-r--r-- | serial/port.c | 94 |
1 files changed, 80 insertions, 14 deletions
diff --git a/serial/port.c b/serial/port.c index 11ab657ba..b55cfd647 100644 --- a/serial/port.c +++ b/serial/port.c @@ -355,14 +355,88 @@ fail: port->listener_id = 0; } +static void get_record_cb(sdp_list_t *recs, int err, gpointer user_data) +{ + struct serial_port *port = user_data; + struct serial_device *device = port->device; + sdp_record_t *record = NULL; + sdp_list_t *protos; + DBusMessage *reply; + GIOChannel *io; + GError *gerr = NULL; + + if (err < 0) { + error("Unable to get service record: %s (%d)", strerror(-err), + -err); + reply = failed(port->msg, strerror(-err)); + goto failed; + } + + if (!recs || !recs->data) { + error("No record found"); + reply = failed(port->msg, "No record found"); + goto failed; + } + + record = recs->data; + + if (sdp_get_access_protos(record, &protos) < 0) { + error("Unable to get access protos from port record"); + reply = failed(port->msg, "Invalid channel"); + goto failed; + } + + port->channel = sdp_get_proto_port(protos, RFCOMM_UUID); + + sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL); + sdp_list_free(protos, NULL); + + io = bt_io_connect(BT_IO_RFCOMM, rfcomm_connect_cb, port, + NULL, &gerr, + BT_IO_OPT_SOURCE_BDADDR, &device->src, + BT_IO_OPT_DEST_BDADDR, &device->dst, + BT_IO_OPT_CHANNEL, port->channel, + BT_IO_OPT_INVALID); + if (!io) { + error("%s", gerr->message); + reply = failed(port->msg, gerr->message); + g_error_free(gerr); + goto failed; + } + + g_io_channel_unref(io); + + return; + +failed: + g_dbus_remove_watch(device->conn, port->listener_id); + port->listener_id = 0; + g_dbus_send_message(device->conn, reply); +} + +static int connect_port(struct serial_port *port) +{ + struct serial_device *device = port->device; + uuid_t uuid; + int err; + + err = bt_string2uuid(&uuid, port->uuid); + if (err < 0) + return err; + + sdp_uuid128_to_uuid(&uuid); + + return bt_search_service(&device->src, &device->dst, &uuid, + get_record_cb, port, NULL); +} + static DBusMessage *port_connect(DBusConnection *conn, DBusMessage *msg, void *user_data) { struct serial_device *device = user_data; struct serial_port *port; const char *uuid; - GIOChannel *io; - GError *err = NULL; + int err; if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &uuid, DBUS_TYPE_INVALID) == FALSE) @@ -381,25 +455,17 @@ static DBusMessage *port_connect(DBusConnection *conn, NULL); port->msg = dbus_message_ref(msg); - io = bt_io_connect(BT_IO_RFCOMM, rfcomm_connect_cb, port, - NULL, &err, - BT_IO_OPT_SOURCE_BDADDR, &device->src, - BT_IO_OPT_DEST_BDADDR, &device->dst, - BT_IO_OPT_CHANNEL, port->channel, - BT_IO_OPT_INVALID); - if (!io) { + err = connect_port(port); + if (err < 0) { DBusMessage *reply; - error("%s", err->message); + error("%s", strerror(-err)); g_dbus_remove_watch(conn, port->listener_id); port->listener_id = 0; - reply = failed(msg, err->message); - g_error_free(err); + reply = failed(msg, strerror(-err)); return reply; } - g_io_channel_unref(io); - return NULL; } |