Now a RFCOMM incoming connection can be made, all the pieces are here. --- plugins/bluetooth.c | 123 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 122 insertions(+), 1 deletions(-) diff --git a/plugins/bluetooth.c b/plugins/bluetooth.c index 0b5a021..f3b9140 100644 --- a/plugins/bluetooth.c +++ b/plugins/bluetooth.c @@ -90,6 +90,9 @@ struct server { guint handle; ConnectFunc connect_cb; gpointer user_data; + gboolean pending_auth; + GIOChannel *client_io; + guint client_watch; }; typedef struct { @@ -453,10 +456,25 @@ static gboolean property_changed(DBusConnection *connection, DBusMessage *msg, return TRUE; } +static void disconnect(struct server *server) +{ + if (server->client_io == NULL) + return; + + server->client_io = NULL; + + if (server->client_watch > 0) { + g_source_remove(server->client_watch); + server->client_watch = 0; + } +} + static void server_stop(gpointer data) { struct server *server = data; + disconnect(server); + if (server->handle > 0) { DBusMessage *msg; @@ -481,11 +499,114 @@ static void server_stop(gpointer data) server->adapter = NULL; } +static void cancel_authorization(struct server *server) +{ + DBusMessage *msg; + + msg = dbus_message_new_method_call(BLUEZ_SERVICE, server->adapter, + BLUEZ_SERVICE_INTERFACE, "CancelAuthorization"); + if (!msg) + return; + + g_dbus_send_message(connection, msg); +} + +static void auth_cb(DBusPendingCall *call, gpointer user_data) +{ + struct server *server = user_data; + DBusMessage *reply = dbus_pending_call_steal_reply(call); + DBusError derr; + GError *err = NULL; + + dbus_error_init(&derr); + + server->pending_auth = FALSE; + + if (dbus_set_error_from_message(&derr, reply)) { + ofono_error("RequestAuthorization error: %s, %s", + derr.name, derr.message); + + if (dbus_error_has_name(&derr, DBUS_ERROR_NO_REPLY)) + cancel_authorization(server); + + dbus_error_free(&derr); + goto failed; + } + + ofono_info("RequestAuthorization() succeeded"); + + if (!bt_io_accept(server->client_io, server->connect_cb, + server->user_data, NULL, &err)) { + ofono_error("%s", err->message); + g_error_free(err); + goto failed; + } + return; + +failed: + dbus_message_unref(reply); + disconnect(server); +} + +static gboolean client_event(GIOChannel *io, GIOCondition cond, + gpointer user_data) +{ + struct server *server = user_data; + + if (server->pending_auth == TRUE) + cancel_authorization(server); + + server->pending_auth = FALSE; + + disconnect(server); + + return FALSE; +} + static void new_connection(GIOChannel *io, gpointer user_data) { struct server *server = user_data; + GError *err = NULL; + char address[18]; + const char *addr; + guint8 channel; + int ret; + + if (server->client_watch != 0) { + ofono_info("Client already connected"); + return; + } + + bt_io_get(io, BT_IO_RFCOMM, &err, BT_IO_OPT_DEST, address, + BT_IO_OPT_CHANNEL, &channel, + BT_IO_OPT_INVALID); + if (err) { + ofono_error("%s", err->message); + g_error_free(err); + return; + } + + ofono_info("New connection from: %s, channel %u", address, channel); + + addr = address; + ret = bluetooth_send_with_reply(server->adapter, + BLUEZ_SERVICE_INTERFACE, + "RequestAuthorization", + auth_cb, server, NULL, DBUS_TIMEOUT, + DBUS_TYPE_STRING, &addr, + DBUS_TYPE_UINT32, &server->handle, + DBUS_TYPE_INVALID); + if (ret < 0) { + ofono_error("RequestAuthorization() failed"); + return; + } + + server->client_io = io; + server->client_watch = g_io_add_watch(server->client_io, + G_IO_NVAL | G_IO_HUP | G_IO_ERR, + client_event, server); - DBG("%p", server); + server->pending_auth = TRUE; } static void add_record_cb(DBusPendingCall *call, gpointer user_data) -- 1.7.4.rc3