summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMaciej S. Szmigiero <mail@maciej.szmigiero.name>2022-06-18 22:31:24 +0200
committerMaciej S. Szmigiero <mail@maciej.szmigiero.name>2022-07-10 02:01:47 +0200
commitae8bd98df2121996fd1074d5ad523a70bfdf19e2 (patch)
tree4f599736bb1df48fe0521984be092dc58dcc0628 /src
parent6afe20f2178413dc6f44fe4519cb979db39bfbb2 (diff)
downloadgeoclue-ae8bd98df2121996fd1074d5ad523a70bfdf19e2.tar.gz
nmea-source: Fix a few issues
* Try to reconnect a broken Avahi client each time the source is started so a restarted or late-started Avahi daemon won't cause this source to stop working, * Try to reconnect to a network NMEA service if its connection drops for any reason (they are often provided by mobile phones which are known for having aggressive network connection management to save power), * Don't add duplicate Avahi services to the service candidates list, * Fix a few memory leaks and random bugs. Tested under Valgrind.
Diffstat (limited to 'src')
-rw-r--r--src/gclue-nmea-source.c555
1 files changed, 416 insertions, 139 deletions
diff --git a/src/gclue-nmea-source.c b/src/gclue-nmea-source.c
index 0172c9b..ea267f7 100644
--- a/src/gclue-nmea-source.c
+++ b/src/gclue-nmea-source.c
@@ -39,21 +39,35 @@
#include <avahi-glib/glib-watch.h>
#include <gio/gunixsocketaddress.h>
+/* Once we run out of NMEA services to try how long to wait
+ * until retrying all of them.
+ * In seconds.
+ */
+#define SERVICE_UNBREAK_TIME 5
+
typedef struct AvahiServiceInfo AvahiServiceInfo;
struct _GClueNMEASourcePrivate {
GSocketConnection *connection;
+ GDataInputStream *input_stream;
GSocketClient *client;
GCancellable *cancellable;
+ AvahiGLibPoll *glib_poll;
+
AvahiClient *avahi_client;
AvahiServiceInfo *active_service;
- /* List of all services but only the most accurate one is used. */
- GList *all_services;
+ /* List of services to try but only the most accurate one is used. */
+ GList *try_services;
+
+ /* List of known-broken services. */
+ GList *broken_services;
+
+ guint accuracy_refresh_source, unbreak_timer;
};
G_DEFINE_TYPE_WITH_CODE (GClueNMEASource,
@@ -67,16 +81,15 @@ static GClueLocationSourceStopResult
gclue_nmea_source_stop (GClueLocationSource *source);
static void
-connect_to_service (GClueNMEASource *source);
-static void
-disconnect_from_service (GClueNMEASource *source);
+try_connect_to_service (GClueNMEASource *source);
struct AvahiServiceInfo {
char *identifier;
char *host_name;
+ gboolean is_socket;
guint16 port;
GClueAccuracyLevel accuracy;
- guint64 timestamp;
+ gint64 timestamp_add;
};
static void
@@ -101,7 +114,7 @@ avahi_service_new (const char *identifier,
service->host_name = g_strdup (host_name);
service->port = port;
service->accuracy = accuracy;
- service->timestamp = g_get_real_time () / G_USEC_PER_SEC;
+ service->timestamp_add = g_get_monotonic_time ();
return service;
}
@@ -124,16 +137,41 @@ compare_avahi_service_by_accuracy_n_time (gconstpointer a,
{
AvahiServiceInfo *first, *second;
gint diff;
+ gint64 tdiff;
first = (AvahiServiceInfo *) a;
second = (AvahiServiceInfo *) b;
diff = second->accuracy - first->accuracy;
+ if (diff)
+ return diff;
+
+ g_assert (first->timestamp_add >= 0);
+ g_assert (second->timestamp_add >= 0);
+ tdiff = first->timestamp_add - second->timestamp_add;
+ if (tdiff < 0)
+ return -1;
+ else if (tdiff > 0)
+ return 1;
+ else
+ return 0;
+}
- if (diff == 0)
- return first->timestamp - second->timestamp;
+static void
+disconnect_from_service (GClueNMEASource *source)
+{
+ GClueNMEASourcePrivate *priv = source->priv;
- return diff;
+ if (!priv->active_service)
+ return;
+
+ g_cancellable_cancel (priv->cancellable);
+
+ g_clear_object (&priv->input_stream);
+ g_clear_object (&priv->connection);
+ g_clear_object (&priv->client);
+ g_clear_object (&priv->cancellable);
+ priv->active_service = NULL;
}
static gboolean
@@ -147,9 +185,9 @@ reconnection_required (GClueNMEASource *source)
* 2. a more accurate service than one currently in use, is now
* available.
*/
- return (priv->active_service != NULL &&
- (priv->all_services == NULL ||
- priv->active_service != priv->all_services->data));
+ return priv->active_service == NULL ||
+ priv->try_services == NULL ||
+ priv->active_service != priv->try_services->data;
}
static void
@@ -159,25 +197,35 @@ reconnect_service (GClueNMEASource *source)
return;
disconnect_from_service (source);
- connect_to_service (source);
+ try_connect_to_service (source);
}
-static void
-refresh_accuracy_level (GClueNMEASource *source)
+static GClueAccuracyLevel get_head_accuracy (GList *list)
{
- GClueAccuracyLevel new, existing;
+ AvahiServiceInfo *service;
+
+ if (!list)
+ return GCLUE_ACCURACY_LEVEL_NONE;
+
+ service = (AvahiServiceInfo *) list->data;
+ return service->accuracy;
+}
+
+static gboolean
+on_refresh_accuracy_level (gpointer user_data)
+{
+ GClueNMEASource *source = GCLUE_NMEA_SOURCE (user_data);
+ GClueNMEASourcePrivate *priv = source->priv;
+ GClueAccuracyLevel new_try, new_broken, new, existing;
+
+ priv->accuracy_refresh_source = 0;
existing = gclue_location_source_get_available_accuracy_level
(GCLUE_LOCATION_SOURCE (source));
- if (source->priv->all_services != NULL) {
- AvahiServiceInfo *service;
-
- service = (AvahiServiceInfo *) source->priv->all_services->data;
- new = service->accuracy;
- } else {
- new = GCLUE_ACCURACY_LEVEL_NONE;
- }
+ new_try = get_head_accuracy (priv->try_services);
+ new_broken = get_head_accuracy (priv->broken_services);
+ new = MAX (new_try, new_broken);
if (new != existing) {
g_debug ("Available accuracy level from %s: %u",
@@ -186,6 +234,109 @@ refresh_accuracy_level (GClueNMEASource *source)
"available-accuracy-level", new,
NULL);
}
+
+ return G_SOURCE_REMOVE;
+}
+
+static void
+refresh_accuracy_level (GClueNMEASource *source)
+{
+ GClueNMEASourcePrivate *priv = source->priv;
+
+ if (priv->accuracy_refresh_source) {
+ return;
+ }
+
+ g_debug ("Scheduling accuracy level refresh");
+ priv->accuracy_refresh_source = g_idle_add (on_refresh_accuracy_level,
+ source);
+}
+
+static gboolean
+on_service_unbreak_time (gpointer source)
+{
+ GClueNMEASourcePrivate *priv = GCLUE_NMEA_SOURCE (source)->priv;
+
+ priv->unbreak_timer = 0;
+
+ if (!priv->try_services && priv->broken_services) {
+ g_debug ("Unbreaking existing services");
+
+ priv->try_services = priv->broken_services;
+ priv->broken_services = NULL;
+
+ reconnect_service (source);
+ }
+
+ return G_SOURCE_REMOVE;
+}
+
+static void
+check_unbreak_timer (GClueNMEASource *source)
+{
+ GClueNMEASourcePrivate *priv = source->priv;
+
+ if (priv->try_services || !priv->broken_services) {
+ if (priv->unbreak_timer) {
+ g_debug ("Removing unnecessary unbreaking timer");
+
+ g_source_remove (priv->unbreak_timer);
+ priv->unbreak_timer = 0;
+ }
+
+ return;
+ }
+
+ if (priv->unbreak_timer) {
+ return;
+ }
+
+ g_debug ("Scheduling unbreaking timer");
+ priv->unbreak_timer = g_timeout_add_seconds (SERVICE_UNBREAK_TIME,
+ on_service_unbreak_time,
+ source);
+}
+
+static void
+service_lists_changed (GClueNMEASource *source)
+{
+ check_unbreak_timer (source);
+ reconnect_service (source);
+ refresh_accuracy_level (source);
+}
+
+static gboolean
+check_service_exists (GClueNMEASource *source,
+ const char *name)
+{
+ GClueNMEASourcePrivate *priv = source->priv;
+ AvahiServiceInfo *service;
+ GList *item;
+ gboolean ret = FALSE;
+
+ /* only `name` is required here */
+ service = avahi_service_new (name,
+ NULL,
+ 0,
+ GCLUE_ACCURACY_LEVEL_NONE);
+
+ item = g_list_find_custom (priv->try_services,
+ service,
+ compare_avahi_service_by_identifier);
+ if (item) {
+ ret = TRUE;
+ } else {
+ item = g_list_find_custom (priv->broken_services,
+ service,
+ compare_avahi_service_by_identifier);
+ if (item) {
+ ret = TRUE;
+ }
+ }
+
+ g_clear_pointer (&service, avahi_service_free);
+
+ return ret;
}
static void
@@ -193,6 +344,7 @@ add_new_service (GClueNMEASource *source,
const char *name,
const char *host_name,
uint16_t port,
+ gboolean is_socket,
AvahiStringList *txt)
{
GClueAccuracyLevel accuracy = GCLUE_ACCURACY_LEVEL_NONE;
@@ -203,7 +355,12 @@ add_new_service (GClueNMEASource *source,
GEnumClass *enum_class;
GEnumValue *enum_value;
- if (port == 0) {
+ if (check_service_exists (source, name)) {
+ g_debug ("Service %s already exists", name);
+ return;
+ }
+
+ if (!txt) {
accuracy = GCLUE_ACCURACY_LEVEL_EXACT;
goto CREATE_SERVICE;
@@ -244,43 +401,72 @@ add_new_service (GClueNMEASource *source,
CREATE_SERVICE:
service = avahi_service_new (name, host_name, port, accuracy);
+ service->is_socket = is_socket;
- source->priv->all_services = g_list_insert_sorted
- (source->priv->all_services,
+ source->priv->try_services = g_list_insert_sorted
+ (source->priv->try_services,
service,
compare_avahi_service_by_accuracy_n_time);
- refresh_accuracy_level (source);
- reconnect_service (source);
+ n_services = g_list_length (source->priv->try_services);
+ g_debug ("No. of _nmea-0183._tcp services %u", n_services);
- n_services = g_list_length (source->priv->all_services);
+ service_lists_changed (source);
+}
- g_debug ("No. of _nmea-0183._tcp services %u", n_services);
+static void
+add_new_service_avahi (GClueNMEASource *source,
+ const char *name,
+ const char *host_name,
+ uint16_t port,
+ AvahiStringList *txt)
+{
+ add_new_service (source, name, host_name, port, FALSE, txt);
}
static void
-remove_service (GClueNMEASource *source,
- AvahiServiceInfo *service)
+add_new_service_socket (GClueNMEASource *source,
+ const char *name,
+ const char *socket_path)
{
- guint n_services = 0;
+ add_new_service (source, name, socket_path, 0, TRUE, NULL);
+}
- avahi_service_free (service);
- source->priv->all_services = g_list_remove
- (source->priv->all_services, service);
+static void
+service_broken (GClueNMEASource *source)
+{
+ GClueNMEASourcePrivate *priv = source->priv;
+ AvahiServiceInfo *service = priv->active_service;
- n_services = g_list_length (source->priv->all_services);
+ g_assert (service);
- g_debug ("No. of _nmea-0183._tcp services %u",
- n_services);
+ disconnect_from_service (source);
- refresh_accuracy_level (source);
- reconnect_service (source);
+ priv->try_services = g_list_remove (priv->try_services,
+ service);
+ priv->broken_services = g_list_insert_sorted
+ (priv->broken_services,
+ service,
+ compare_avahi_service_by_accuracy_n_time);
+
+ service_lists_changed (source);
+}
+
+static void
+remove_service_from_list (GList **list,
+ GList *item)
+{
+ AvahiServiceInfo *service = item->data;
+
+ *list = g_list_delete_link (*list, item);
+ avahi_service_free (service);
}
static void
remove_service_by_name (GClueNMEASource *source,
const char *name)
{
+ GClueNMEASourcePrivate *priv = source->priv;
AvahiServiceInfo *service;
GList *item;
@@ -290,15 +476,31 @@ remove_service_by_name (GClueNMEASource *source,
0,
GCLUE_ACCURACY_LEVEL_NONE);
- item = g_list_find_custom (source->priv->all_services,
+ item = g_list_find_custom (priv->try_services,
service,
compare_avahi_service_by_identifier);
- avahi_service_free (service);
+ if (item) {
+ if (item->data == priv->active_service) {
+ g_debug ("Active NMEA service removed, disconnecting.");
+ disconnect_from_service (source);
+ }
- if (item == NULL)
- return;
+ remove_service_from_list (&priv->try_services,
+ item);
+ } else {
+ item = g_list_find_custom (priv->broken_services,
+ service,
+ compare_avahi_service_by_identifier);
+ if (item) {
+ g_assert (item->data != priv->active_service);
+ remove_service_from_list (&priv->broken_services,
+ item);
+ }
+ }
- remove_service (source, item->data);
+ g_clear_pointer (&service, avahi_service_free);
+
+ service_lists_changed (source);
}
static void
@@ -339,15 +541,18 @@ resolve_callback (AvahiServiceResolver *service_resolver,
}
case AVAHI_RESOLVER_FOUND:
- g_debug ("Service %s:%u resolved",
+ g_debug ("Service '%s' of type '%s' in domain '%s' resolved to %s:%u",
+ name,
+ type,
+ domain,
host_name,
- port);
+ (unsigned int)port);
- add_new_service (GCLUE_NMEA_SOURCE (user_data),
- name,
- host_name,
- port,
- txt);
+ add_new_service_avahi (GCLUE_NMEA_SOURCE (user_data),
+ name,
+ host_name,
+ port,
+ txt);
break;
}
@@ -360,12 +565,8 @@ client_callback (AvahiClient *avahi_client,
AvahiClientState state,
void *user_data)
{
- GClueNMEASourcePrivate *priv = GCLUE_NMEA_SOURCE (user_data)->priv;
-
g_return_if_fail (avahi_client != NULL);
- priv->avahi_client = avahi_client;
-
if (state == AVAHI_CLIENT_FAILURE) {
const char *errorstr = avahi_strerror
(avahi_client_errno (avahi_client));
@@ -514,21 +715,19 @@ on_read_nmea_sentence (GObject *object,
do {
if (message == NULL) {
if (error != NULL) {
- if (error->code == G_IO_ERROR_CLOSED)
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+ return;
+ } else if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CLOSED)) {
g_debug ("Socket closed.");
- else if (error->code != G_IO_ERROR_CANCELLED)
+ } else {
g_warning ("Error when receiving message: %s",
error->message);
+ }
} else {
g_debug ("Nothing to read");
}
- g_object_unref (data_input_stream);
- if (source->priv->active_service != NULL)
- /* In case service did not advertise it exiting
- * or we failed to receive it's notification.
- */
- remove_service (source, source->priv->active_service);
+ service_broken (source);
return;
}
@@ -594,28 +793,34 @@ on_connection_to_location_server (GObject *object,
{
GClueNMEASource *source = GCLUE_NMEA_SOURCE (user_data);
GSocketClient *client = G_SOCKET_CLIENT (object);
- GError *error = NULL;
- GDataInputStream *data_input_stream;
- GInputStream *input_stream;
+ g_autoptr(GSocketConnection) connection = NULL;
+ g_autoptr(GError) error = NULL;
- source->priv->connection = g_socket_client_connect_to_host_finish
+ connection = g_socket_client_connect_to_host_finish
(client,
result,
&error);
if (error != NULL) {
- if (error->code != G_IO_ERROR_CANCELLED)
- g_warning ("Failed to connect to NMEA service: %s", error->message);
- g_clear_error (&error);
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+ return;
+ }
+ g_warning ("Failed to connect to NMEA service: %s", error->message);
+ service_broken (source);
return;
}
- input_stream = g_io_stream_get_input_stream
- (G_IO_STREAM (source->priv->connection));
- data_input_stream = g_data_input_stream_new (input_stream);
+ g_debug ("NMEA service connected.");
- g_data_input_stream_read_upto_async (data_input_stream,
+ g_assert (!source->priv->connection);
+ source->priv->connection = g_steal_pointer (&connection);
+
+ g_assert (!source->priv->input_stream);
+ source->priv->input_stream = g_data_input_stream_new
+ (g_io_stream_get_input_stream (G_IO_STREAM (source->priv->connection)));
+
+ g_data_input_stream_read_upto_async (source->priv->input_stream,
NMEA_LINE_END,
NMEA_LINE_END_CTR,
G_PRIORITY_DEFAULT,
@@ -625,24 +830,39 @@ on_connection_to_location_server (GObject *object,
}
static void
-connect_to_service (GClueNMEASource *source)
+try_connect_to_service (GClueNMEASource *source)
{
GClueNMEASourcePrivate *priv = source->priv;
- GSocketAddress *addr;
- GSocketConnectable *connectable;
- if (priv->all_services == NULL)
+ if (!gclue_location_source_get_active (GCLUE_LOCATION_SOURCE (source))) {
+ g_warn_if_fail (!priv->active_service);
+
+ return;
+ }
+
+ if (priv->active_service)
return;
+ if (priv->try_services == NULL)
+ return;
+
+ g_assert (!priv->cancellable);
+ priv->cancellable = g_cancellable_new ();
+
+ g_assert (!priv->client);
priv->client = g_socket_client_new ();
- g_cancellable_reset (priv->cancellable);
/* The service with the highest accuracy will be stored in the beginning
* of the list.
*/
- priv->active_service = (AvahiServiceInfo *) priv->all_services->data;
+ priv->active_service = (AvahiServiceInfo *) priv->try_services->data;
- if ( priv->active_service->port != 0 )
+ g_debug ("Trying to connect to NMEA %sservice %s:%u.",
+ priv->active_service->is_socket ? "socket " : "",
+ priv->active_service->host_name,
+ (unsigned int) priv->active_service->port);
+
+ if (!priv->active_service->is_socket) {
g_socket_client_connect_to_host_async
(priv->client,
priv->active_service->host_name,
@@ -650,52 +870,86 @@ connect_to_service (GClueNMEASource *source)
priv->cancellable,
on_connection_to_location_server,
source);
- else {
- addr = g_unix_socket_address_new(priv->active_service->host_name);
- connectable = G_SOCKET_CONNECTABLE (addr);
+ } else {
+ g_autoptr(GSocketAddress) addr = NULL;
+
+ addr = g_unix_socket_address_new (priv->active_service->host_name);
g_socket_client_connect_async (priv->client,
- connectable,
+ G_SOCKET_CONNECTABLE (addr),
priv->cancellable,
on_connection_to_location_server,
source);
}
}
-static void
-disconnect_from_service (GClueNMEASource *source)
+static gboolean
+remove_avahi_services_from_list (GClueNMEASource *source, GList **list)
{
GClueNMEASourcePrivate *priv = source->priv;
+ gboolean removed_active = FALSE;
+ GList *l = *list;
+
+ while (l != NULL) {
+ GList *next = l->next;
+ AvahiServiceInfo *service = l->data;
+
+ if (!service->is_socket) {
+ if (service == priv->active_service) {
+ g_debug ("Active NMEA service was Avahi-provided, disconnecting.");
+ disconnect_from_service (source);
+ removed_active = TRUE;
+ }
- g_cancellable_cancel (priv->cancellable);
+ remove_service_from_list (list, l);
+ }
+
+ l = next;
+ }
- if (priv->connection != NULL) {
- GError *error = NULL;
+ return removed_active;
+}
- g_io_stream_close (G_IO_STREAM (priv->connection),
- NULL,
- &error);
- if (error != NULL)
- g_warning ("Error in closing socket connection: %s", error->message);
+static void
+disconnect_avahi_client (GClueNMEASource *source)
+{
+ GClueNMEASourcePrivate *priv = source->priv;
+
+ remove_avahi_services_from_list (source, &priv->try_services);
+ if (remove_avahi_services_from_list (source, &priv->broken_services)) {
+ g_warn_if_reached ();
}
- g_clear_object (&priv->connection);
- g_clear_object (&priv->client);
- priv->active_service = NULL;
+ g_clear_pointer (&priv->avahi_client, avahi_client_free);
+
+ service_lists_changed (source);
}
static void
gclue_nmea_source_finalize (GObject *gnmea)
{
- GClueNMEASourcePrivate *priv = GCLUE_NMEA_SOURCE (gnmea)->priv;
+ GClueNMEASource *source = GCLUE_NMEA_SOURCE (gnmea);
+ GClueNMEASourcePrivate *priv = source->priv;
G_OBJECT_CLASS (gclue_nmea_source_parent_class)->finalize (gnmea);
- g_clear_object (&priv->connection);
- g_clear_object (&priv->client);
- g_clear_object (&priv->cancellable);
- if (priv->avahi_client)
- avahi_client_free (priv->avahi_client);
- g_list_free_full (priv->all_services,
+ disconnect_avahi_client (source);
+ disconnect_from_service (source);
+
+ if (priv->accuracy_refresh_source) {
+ g_source_remove (priv->accuracy_refresh_source);
+ priv->accuracy_refresh_source = 0;
+ }
+
+ if (priv->unbreak_timer) {
+ g_source_remove (priv->unbreak_timer);
+ priv->unbreak_timer = 0;
+ }
+
+ g_clear_pointer (&priv->glib_poll, avahi_glib_poll_free);
+
+ g_list_free_full (g_steal_pointer (&priv->try_services),
+ avahi_service_free);
+ g_list_free_full (g_steal_pointer (&priv->broken_services),
avahi_service_free);
}
@@ -712,41 +966,33 @@ gclue_nmea_source_class_init (GClueNMEASourceClass *klass)
}
static void
-gclue_nmea_source_init (GClueNMEASource *source)
+try_connect_avahi_client (GClueNMEASource *source)
{
- GClueNMEASourcePrivate *priv;
AvahiServiceBrowser *service_browser;
+ GClueNMEASourcePrivate *priv = source->priv;
const AvahiPoll *poll_api;
- AvahiGLibPoll *glib_poll;
- const char *nmea_socket;
- GClueConfig *config;
int error;
- source->priv = gclue_nmea_source_get_instance_private (source);
- priv = source->priv;
+ if (priv->avahi_client) {
+ AvahiClientState avahi_state;
- glib_poll = avahi_glib_poll_new (NULL, G_PRIORITY_DEFAULT);
- poll_api = avahi_glib_poll_get (glib_poll);
-
- priv->cancellable = g_cancellable_new ();
-
- config = gclue_config_get_singleton ();
+ avahi_state = avahi_client_get_state (priv->avahi_client);
+ if (avahi_state != AVAHI_CLIENT_FAILURE) {
+ return;
+ }
- nmea_socket = gclue_config_get_nmea_socket (config);
- if (nmea_socket != NULL) {
- add_new_service (source,
- "nmea-socket",
- nmea_socket,
- 0,
- NULL);
+ g_debug ("Avahi client in failure state, trying to reinit.");
+ disconnect_avahi_client (source);
}
- avahi_client_new (poll_api,
- 0,
- client_callback,
- source,
- &error);
+ g_assert (priv->glib_poll);
+ poll_api = avahi_glib_poll_get (priv->glib_poll);
+ priv->avahi_client = avahi_client_new (poll_api,
+ 0,
+ client_callback,
+ source,
+ &error);
if (priv->avahi_client == NULL) {
g_warning ("Failed to connect to avahi service: %s",
avahi_strerror (error));
@@ -762,15 +1008,43 @@ gclue_nmea_source_init (GClueNMEASource *source)
0,
browse_callback,
source);
-
-
if (service_browser == NULL) {
const char *errorstr;
error = avahi_client_errno (priv->avahi_client);
errorstr = avahi_strerror (error);
g_warning ("Failed to browse avahi services: %s", errorstr);
+ goto fail_client;
+ }
+
+ return;
+
+fail_client:
+ disconnect_avahi_client (source);
+}
+
+static void
+gclue_nmea_source_init (GClueNMEASource *source)
+{
+ GClueNMEASourcePrivate *priv;
+ const char *nmea_socket;
+ GClueConfig *config;
+
+ source->priv = gclue_nmea_source_get_instance_private (source);
+ priv = source->priv;
+
+ priv->glib_poll = avahi_glib_poll_new (NULL, G_PRIORITY_DEFAULT);
+
+ config = gclue_config_get_singleton ();
+
+ nmea_socket = gclue_config_get_nmea_socket (config);
+ if (nmea_socket != NULL) {
+ add_new_service_socket (source,
+ "nmea-socket",
+ nmea_socket);
}
+
+ try_connect_avahi_client (source);
}
/**
@@ -790,8 +1064,10 @@ gclue_nmea_source_get_singleton (void)
source = g_object_new (GCLUE_TYPE_NMEA_SOURCE, NULL);
g_object_add_weak_pointer (G_OBJECT (source),
(gpointer) &source);
- } else
+ } else {
g_object_ref (source);
+ try_connect_avahi_client (source);
+ }
return source;
}
@@ -807,10 +1083,11 @@ gclue_nmea_source_start (GClueLocationSource *source)
base_class = GCLUE_LOCATION_SOURCE_CLASS (gclue_nmea_source_parent_class);
base_result = base_class->start (source);
- if (base_result != GCLUE_LOCATION_SOURCE_START_RESULT_OK)
+ if (base_result == GCLUE_LOCATION_SOURCE_START_RESULT_FAILED)
return base_result;
- connect_to_service (GCLUE_NMEA_SOURCE (source));
+ try_connect_avahi_client (GCLUE_NMEA_SOURCE (source));
+ reconnect_service (GCLUE_NMEA_SOURCE (source));
return base_result;
}