summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWim Taymans <wtaymans@redhat.com>2014-08-08 22:35:40 +0200
committerWim Taymans <wtaymans@redhat.com>2014-08-08 22:35:40 +0200
commit792e0ee80f833c2f0b51d2dd875a2e6590a4914b (patch)
tree5c58446018fb537d88691f02c392e3212fc0464b
parent4c6007ce197ba7fc37dcd20e1fbd780b3cc4f2a8 (diff)
handle onwer vanishingHEADmaster
When the owner of the SCO socket vanishes, close the socket and go IDLE again.
-rw-r--r--src/hsd-headset.c55
-rw-r--r--src/hsd-headset.h1
-rw-r--r--src/hsd-profile.c15
3 files changed, 55 insertions, 16 deletions
diff --git a/src/hsd-headset.c b/src/hsd-headset.c
index dcea642..1ed514d 100644
--- a/src/hsd-headset.c
+++ b/src/hsd-headset.c
@@ -110,6 +110,36 @@ headset_set_state (HsdHeadset *h,
}
}
+static void
+headset_do_disconnect (HsdHeadset *h)
+{
+ if (h->fd != -1) {
+ shutdown (h->fd, SHUT_RDWR);
+ close (h->fd);
+ h->fd = -1;
+ }
+
+ if (h->owner) {
+ g_free (h->owner);
+ h->owner = NULL;
+ g_bus_unwatch_name (h->owner_watch);
+ h->owner_watch = 0;
+ }
+ headset_set_state (h, HSD_HEADSET_STATE_IDLE);
+}
+
+
+static void
+headset_owner_vanished (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ HsdHeadset *h = user_data;
+
+ g_warning ("SCO connection owner vanished");
+ headset_do_disconnect (h);
+}
+
static gboolean
headset_connect_cb (GIOChannel *io, GIOCondition cond, gpointer user_data)
{
@@ -142,11 +172,7 @@ headset_connect_cb (GIOChannel *io, GIOCondition cond, gpointer user_data)
connect_failed:
{
- close (h->fd);
- h->fd = -1;
- g_free (h->owner);
- h->owner = NULL;
- headset_set_state (h, HSD_HEADSET_STATE_IDLE);
+ headset_do_disconnect (h);
g_dbus_method_invocation_return_dbus_error (invocation,
HSD_HEADSET_INTERFACE ".Error.Failed", "failed to connect");
return FALSE;
@@ -180,6 +206,7 @@ headset_connect (HsdHeadset *h,
if (h->state != HSD_HEADSET_STATE_IDLE)
goto not_idle;
+
src_addr = h->adapter_addr;
dst_addr = h->device_addr;
@@ -224,6 +251,13 @@ headset_connect (HsdHeadset *h,
headset_set_state (h, HSD_HEADSET_STATE_PENDING);
h->owner = g_strdup (sender);
h->invocation = invocation;
+ /* we need to make sure the owner stays alive */
+ h->owner_watch = g_bus_watch_name_on_connection (connection,
+ sender,
+ G_BUS_NAME_WATCHER_FLAGS_NONE,
+ NULL,
+ headset_owner_vanished,
+ h, NULL);
io = g_io_channel_unix_new(h->fd);
g_io_add_watch(io, G_IO_OUT | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
@@ -282,14 +316,7 @@ headset_disconnect (HsdHeadset *h,
if (h->owner != NULL && strcmp (h->owner, sender))
goto not_owner;
- if (h->fd != -1) {
- shutdown (h->fd, SHUT_RDWR);
- close (h->fd);
- }
- h->fd = -1;
-
- h->owner = NULL;
- headset_set_state (h, HSD_HEADSET_STATE_IDLE);
+ headset_do_disconnect (h);
g_dbus_method_invocation_return_value (invocation, NULL);
@@ -499,13 +526,13 @@ hsd_headset_free (HsdHeadset *headset)
{
GDBusConnection *conn = hsd_dbus_connection_get ();
+ headset_do_disconnect (headset);
if (headset->id)
g_dbus_connection_unregister_object (conn, headset->id);
g_free (headset->device);
g_free (headset->device_addr);
g_free (headset->adapter);
g_free (headset->adapter_addr);
- g_free (headset->owner);
g_io_channel_unref (headset->rfcomm);
g_free (headset);
}
diff --git a/src/hsd-headset.h b/src/hsd-headset.h
index cecc12d..ba7337a 100644
--- a/src/hsd-headset.h
+++ b/src/hsd-headset.h
@@ -37,6 +37,7 @@ struct _HsdHeadset {
HsdHeadsetState state;
gchar *owner;
+ guint owner_watch;
gint fd;
GDBusMethodInvocation *invocation;
};
diff --git a/src/hsd-profile.c b/src/hsd-profile.c
index 3625a46..d144dfe 100644
--- a/src/hsd-profile.c
+++ b/src/hsd-profile.c
@@ -22,6 +22,7 @@
#include "hsd.h"
#include "hsd-headset.h"
#include "hsd-profile.h"
+#include "hsd-manager.h"
typedef struct {
HsdProfileId id;
@@ -95,7 +96,9 @@ profile_new_connection (HsdProfile *p,
if (headset == NULL)
goto failure;
- hsd_manager_add_headset (p->manager, headset);
+ hsd_manager_add_headset (p->manager, headset, &error);
+ if (error != NULL)
+ goto failure;
g_dbus_method_invocation_return_value (invocation, NULL);
@@ -125,7 +128,10 @@ profile_request_disconnection (HsdProfile *p,
if (headset == NULL)
goto unknown_headset;
- hsd_manager_remove_headset (p->manager, headset);
+ hsd_manager_remove_headset (p->manager, headset, &error);
+ if (error != NULL)
+ goto failure;
+
hsd_headset_free (headset);
g_dbus_method_invocation_return_value (invocation, NULL);
@@ -137,6 +143,11 @@ unknown_headset:
"org.freedesktop.Headset.Error.Rejected", "no such transport");
return;
}
+failure:
+ {
+ g_dbus_method_invocation_take_error (invocation, error);
+ return;
+ }
}
static void