aboutsummaryrefslogtreecommitdiff
path: root/serial/port.c
diff options
context:
space:
mode:
authorLuiz Augusto von Dentz <luiz.dentz@openbossa.org>2009-04-09 10:45:26 -0300
committerJohan Hedberg <johan.hedberg@nokia.com>2009-04-11 18:29:47 +0300
commiteeb8599f0bbf78340d7c40d9eac6ba123f60f5cc (patch)
tree4e59f0c8f017ddb774b72a9b1cc1ab9b045ddfce /serial/port.c
parenta32df6e52f95134d51592404162a1bf99571110f (diff)
downloadbluez-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.
Diffstat (limited to 'serial/port.c')
-rw-r--r--serial/port.c94
1 files changed, 80 insertions, 14 deletions
diff --git a/serial/port.c b/serial/port.c
index 11ab657b..b55cfd64 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;
}