Gentoo Websites Logo
Go to: Gentoo Home Documentation Forums Lists Bugs Planet Store Wiki Get Gentoo!
View | Details | Raw Unified | Return to bug 880847
Collapse All | Expand All

(-)geoclue-2.6.0/.gitlab-ci.yml (-28 lines)
Lines 1-28 Link Here
1
before_script:
2
    -  sed -i '/^#\sdeb-src /s/^#//' '/etc/apt/sources.list'
3
    - apt-get --allow-unauthenticated update && apt-get build-dep --yes geoclue-2.0
4
    - apt-get install --yes git gobject-introspection libmm-glib-dev wget valac
5
    - apt-get install --yes libnotify-dev xsltproc gtk-doc-tools python3-pip
6
    - apt-get install --yes ninja-build gettext modemmanager-dev
7
    - pip3 install meson==0.53.2
8
9
# Ubuntu 14.04 is not supported, see README for details
10
#
11
12
ubuntu-18.04:
13
    image: ubuntu:bionic
14
    artifacts:
15
        when: always
16
        name: "bionic-${CI_COMMIT_REF_NAME}"
17
        paths:
18
            - "${CI_PROJECT_DIR}/build"
19
    script: meson build && ninja -C build && ninja -C build test && ninja -C build install
20
21
ubuntu-18.04-no-backend:
22
    image: ubuntu:bionic
23
    artifacts:
24
        when: always
25
        name: "bionic-no-backend-${CI_COMMIT_REF_NAME}"
26
        paths:
27
            - "${CI_PROJECT_DIR}/build"
28
    script: meson -Denable-backend=false build && ninja -C build && ninja -C build test && ninja -C build install
(-)geoclue-2.6.0/data/geoclue.conf.in (+6 lines)
Lines 64-69 Link Here
64
# If set to true, geoclue will automatically submit network data to Mozilla
64
# If set to true, geoclue will automatically submit network data to Mozilla
65
# each time it gets a GPS lock.
65
# each time it gets a GPS lock.
66
#
66
#
67
# Currently, only Modem-GPS or Network NMEA sources are supported as providers
68
# of a location to submit (one at a time).
69
# If Modem-GPS source is enabled above it will be the exclusive provider
70
# (regardless whether the system is actually equipped with such modem),
71
# otherwise Network NMEA source will be considered.
72
#
67
submit-data=false
73
submit-data=false
68
74
69
# URL to submission API of Mozilla Location Service. If not set, defaults to
75
# URL to submission API of Mozilla Location Service. If not set, defaults to
(-)geoclue-2.6.0/data/geoclue.service.in (+1 lines)
Lines 5-10 Link Here
5
Type=dbus
5
Type=dbus
6
BusName=org.freedesktop.GeoClue2
6
BusName=org.freedesktop.GeoClue2
7
User=@dbus_srv_user@
7
User=@dbus_srv_user@
8
Environment="GSETTINGS_BACKEND=memory"
8
ExecStart=@libexecdir@/geoclue
9
ExecStart=@libexecdir@/geoclue
9
10
10
# Filesystem lockdown
11
# Filesystem lockdown
(-)geoclue-2.6.0/src/gclue-3g-tower.h (-2 / +5 lines)
Lines 26-34 Link Here
26
26
27
typedef enum {
27
typedef enum {
28
  GCLUE_TOWER_TEC_UNKNOWN = 0,
28
  GCLUE_TOWER_TEC_UNKNOWN = 0,
29
  GCLUE_TOWER_TEC_3G = 1,
29
  GCLUE_TOWER_TEC_2G = 1,
30
  GCLUE_TOWER_TEC_4G = 2,
30
  GCLUE_TOWER_TEC_3G = 2,
31
  GCLUE_TOWER_TEC_4G = 3,
32
  GCLUE_TOWER_TEC_NO_FIX = 99,
31
} GClueTowerTec;
33
} GClueTowerTec;
34
# define GCLUE_TOWER_TEC_MAX_VALID GCLUE_TOWER_TEC_4G
32
35
33
typedef struct _GClue3GTower GClue3GTower;
36
typedef struct _GClue3GTower GClue3GTower;
34
37
(-)geoclue-2.6.0/src/gclue-3g.c (-45 / +154 lines)
Lines 24-32 Link Here
24
#include <libsoup/soup.h>
24
#include <libsoup/soup.h>
25
#include <string.h>
25
#include <string.h>
26
#include "gclue-3g.h"
26
#include "gclue-3g.h"
27
#include "gclue-3g-tower.h"
27
#include "gclue-modem-manager.h"
28
#include "gclue-modem-manager.h"
28
#include "gclue-location.h"
29
#include "gclue-location.h"
29
#include "gclue-mozilla.h"
30
#include "gclue-mozilla.h"
31
#include "gclue-wifi.h"
30
32
31
/**
33
/**
32
 * SECTION:gclue-3g
34
 * SECTION:gclue-3g
Lines 35-48 Link Here
35
 * Contains functions to get the geolocation based on 3GPP cell towers.
37
 * Contains functions to get the geolocation based on 3GPP cell towers.
36
 **/
38
 **/
37
39
40
/* Should be slightly less than MAX_LOCATION_AGE in gclue-locator.c, so we don't
41
 * get replaced by a less accurate WiFi location while still connected to a tower.
42
 * Technically, this can only happen on the NEIGHBORHOOD accuracy level (since at
43
 * this level WiFi does scrambling), but it won't hurt on higher ones, too.
44
 * In seconds.
45
 */
46
#define LOCATION_3GPP_TIMEOUT (25 * 60)
47
48
static unsigned int gclue_3g_running;
49
38
struct _GClue3GPrivate {
50
struct _GClue3GPrivate {
51
        GClueMozilla *mozilla;
39
        GClueModem *modem;
52
        GClueModem *modem;
40
53
41
        GCancellable *cancellable;
54
        GCancellable *cancellable;
42
55
43
        gulong threeg_notify_id;
56
        gulong threeg_notify_id;
44
57
        guint location_3gpp_timeout_id;
45
        GClue3GTower *tower;
46
};
58
};
47
59
48
G_DEFINE_TYPE_WITH_CODE (GClue3G,
60
G_DEFINE_TYPE_WITH_CODE (GClue3G,
Lines 56-61 Link Here
56
gclue_3g_stop (GClueLocationSource *source);
68
gclue_3g_stop (GClueLocationSource *source);
57
static SoupMessage *
69
static SoupMessage *
58
gclue_3g_create_query (GClueWebSource *web,
70
gclue_3g_create_query (GClueWebSource *web,
71
                       const char **query_data_description,
59
                       GError        **error);
72
                       GError        **error);
60
static SoupMessage *
73
static SoupMessage *
61
gclue_3g_create_submit_query (GClueWebSource  *web,
74
gclue_3g_create_submit_query (GClueWebSource  *web,
Lines 64-87 Link Here
64
static GClueAccuracyLevel
77
static GClueAccuracyLevel
65
gclue_3g_get_available_accuracy_level (GClueWebSource *web,
78
gclue_3g_get_available_accuracy_level (GClueWebSource *web,
66
                                       gboolean available);
79
                                       gboolean available);
67
static GClueLocation *
68
gclue_3g_parse_response (GClueWebSource *web,
69
                         const char     *xml,
70
                         GError        **error);
71
80
72
static void
81
static void
73
on_3g_enabled (GObject      *source_object,
82
on_3g_enabled (GObject      *source_object,
74
               GAsyncResult *result,
83
               GAsyncResult *result,
75
               gpointer      user_data)
84
               gpointer      user_data)
76
{
85
{
77
        GClue3G *source = GCLUE_3G (user_data);
86
        g_autoptr(GError) error = NULL;
78
        GError *error = NULL;
79
87
80
        if (!gclue_modem_enable_3g_finish (source->priv->modem,
88
        if (!gclue_modem_enable_3g_finish (GCLUE_MODEM (source_object),
81
                                           result,
89
                                           result,
82
                                           &error)) {
90
                                           &error)) {
91
                if (error && !g_error_matches (error, G_IO_ERROR,
92
                                               G_IO_ERROR_CANCELLED)) {
83
                g_warning ("Failed to enable 3GPP: %s", error->message);
93
                g_warning ("Failed to enable 3GPP: %s", error->message);
84
                g_error_free (error);
94
                }
85
        }
95
        }
86
}
96
}
87
97
Lines 92-114 Link Here
92
{
102
{
93
        GClue3G *source = GCLUE_3G (user_data);
103
        GClue3G *source = GCLUE_3G (user_data);
94
        GClue3GPrivate *priv = source->priv;
104
        GClue3GPrivate *priv = source->priv;
105
        gboolean available_3g;
106
107
        available_3g = gclue_modem_get_is_3g_available (priv->modem);
108
        g_debug ("3G available notify %d", (int)available_3g);
95
109
96
        gclue_web_source_refresh (GCLUE_WEB_SOURCE (source));
110
        gclue_web_source_refresh (GCLUE_WEB_SOURCE (source));
97
111
98
        if (gclue_location_source_get_active (GCLUE_LOCATION_SOURCE (source)) &&
112
        if (gclue_location_source_get_active (GCLUE_LOCATION_SOURCE (source)) &&
99
            gclue_modem_get_is_3g_available (priv->modem))
113
            available_3g)
100
                gclue_modem_enable_3g (priv->modem,
114
                gclue_modem_enable_3g (priv->modem,
101
                                       priv->cancellable,
115
                                       priv->cancellable,
102
                                       on_3g_enabled,
116
                                       on_3g_enabled,
103
                                       source);
117
                                       source);
104
}
118
}
105
119
106
static GClueLocation *
120
static void cancel_location_3gpp_timeout (GClue3G *g3g)
107
gclue_3g_parse_response (GClueWebSource *web,
108
                         const char     *content,
109
                         GError        **error)
110
{
121
{
111
        return gclue_mozilla_parse_response (content, error);
122
        GClue3GPrivate *priv = g3g->priv;
123
124
        if (!priv->location_3gpp_timeout_id)
125
                return;
126
127
        g_source_remove (priv->location_3gpp_timeout_id);
128
        priv->location_3gpp_timeout_id = 0;
112
}
129
}
113
130
114
static void
131
static void
Lines 125-131 Link Here
125
                                     priv->threeg_notify_id);
142
                                     priv->threeg_notify_id);
126
        priv->threeg_notify_id = 0;
143
        priv->threeg_notify_id = 0;
127
144
145
        cancel_location_3gpp_timeout (source);
146
128
        g_clear_object (&priv->modem);
147
        g_clear_object (&priv->modem);
148
        g_clear_object (&priv->mozilla);
129
        g_clear_object (&priv->cancellable);
149
        g_clear_object (&priv->cancellable);
130
}
150
}
131
151
Lines 142-148 Link Here
142
        source_class->stop = gclue_3g_stop;
162
        source_class->stop = gclue_3g_stop;
143
        web_class->create_query = gclue_3g_create_query;
163
        web_class->create_query = gclue_3g_create_query;
144
        web_class->create_submit_query = gclue_3g_create_submit_query;
164
        web_class->create_submit_query = gclue_3g_create_submit_query;
145
        web_class->parse_response = gclue_3g_parse_response;
146
        web_class->get_available_accuracy_level =
165
        web_class->get_available_accuracy_level =
147
                gclue_3g_get_available_accuracy_level;
166
                gclue_3g_get_available_accuracy_level;
148
}
167
}
Lines 151-168 Link Here
151
gclue_3g_init (GClue3G *source)
170
gclue_3g_init (GClue3G *source)
152
{
171
{
153
        GClue3GPrivate *priv;
172
        GClue3GPrivate *priv;
173
        GClueWebSource *web_source = GCLUE_WEB_SOURCE (source);
154
174
155
        source->priv = gclue_3g_get_instance_private (source);
175
        source->priv = gclue_3g_get_instance_private (source);
156
        priv = source->priv;
176
        priv = source->priv;
157
177
158
        priv->cancellable = g_cancellable_new ();
178
        priv->cancellable = g_cancellable_new ();
159
179
180
        priv->mozilla = gclue_mozilla_get_singleton ();
181
        gclue_web_source_set_locate_url (web_source,
182
                                         gclue_mozilla_get_locate_url (priv->mozilla));
183
        gclue_web_source_set_submit_url (web_source,
184
                                         gclue_mozilla_get_submit_url (priv->mozilla));
185
160
        priv->modem = gclue_modem_manager_get_singleton ();
186
        priv->modem = gclue_modem_manager_get_singleton ();
161
        priv->threeg_notify_id =
187
        priv->threeg_notify_id =
162
                        g_signal_connect (priv->modem,
188
                        g_signal_connect (priv->modem,
163
                                          "notify::is-3g-available",
189
                                          "notify::is-3g-available",
164
                                          G_CALLBACK (on_is_3g_available_notify),
190
                                          G_CALLBACK (on_is_3g_available_notify),
165
                                          source);
191
                                          source);
192
        priv->location_3gpp_timeout_id = 0;
166
}
193
}
167
194
168
static void
195
static void
Lines 177-212 Link Here
177
/**
204
/**
178
 * gclue_3g_new:
205
 * gclue_3g_new:
179
 *
206
 *
180
 * Get the #GClue3G singleton.
207
 * Get the #GClue3G singleton, for the specified max accuracy level @level.
181
 *
208
 *
182
 * Returns: (transfer full): a new ref to #GClue3G. Use g_object_unref()
209
 * Returns: (transfer full): a new ref to #GClue3G. Use g_object_unref()
183
 * when done.
210
 * when done.
184
 **/
211
 **/
185
GClue3G *
212
GClue3G *
186
gclue_3g_get_singleton (void)
213
gclue_3g_get_singleton (GClueAccuracyLevel level)
187
{
214
{
188
        static GClue3G *source = NULL;
215
        static GClue3G *source[] = { NULL, NULL };
216
        int i;
217
218
        g_return_val_if_fail (level >= GCLUE_ACCURACY_LEVEL_CITY, NULL);
189
219
190
        if (source == NULL) {
220
        i = gclue_wifi_should_skip_bsss (level) ? 0 : 1;
191
                source = g_object_new (GCLUE_TYPE_3G,
221
        if (source[i] == NULL) {
222
                source[i] = g_object_new (GCLUE_TYPE_3G,
223
                                          "accuracy-level", level,
192
                                       "compute-movement", FALSE,
224
                                       "compute-movement", FALSE,
193
                                       NULL);
225
                                       NULL);
194
                g_object_weak_ref (G_OBJECT (source),
226
                g_object_weak_ref (G_OBJECT (source[i]),
195
                                   on_3g_destroyed,
227
                                   on_3g_destroyed,
196
                                   &source);
228
                                   &source[i]);
197
        } else
229
        } else
198
                g_object_ref (source);
230
                g_object_ref (source[i]);
199
231
200
        return source;
232
        return source[i];
233
}
234
235
static gboolean
236
g3g_should_skip_bsss (GClue3G *g3g)
237
{
238
        GClueAccuracyLevel level;
239
240
        g_object_get (G_OBJECT (g3g), "accuracy-level", &level, NULL);
241
        return gclue_wifi_should_skip_bsss (level);
201
}
242
}
202
243
203
static SoupMessage *
244
static SoupMessage *
204
gclue_3g_create_query (GClueWebSource *web,
245
gclue_3g_create_query (GClueWebSource *web,
246
                       const char **query_data_description,
205
                       GError        **error)
247
                       GError        **error)
206
{
248
{
207
        GClue3GPrivate *priv = GCLUE_3G (web)->priv;
249
        GClue3G *g3g = GCLUE_3G (web);
250
        GClue3GPrivate *priv = g3g->priv;
251
        gboolean skip_bss;
208
252
209
        if (priv->tower == NULL) {
253
        if (!gclue_mozilla_has_tower (priv->mozilla)) {
210
                g_set_error_literal (error,
254
                g_set_error_literal (error,
211
                                     G_IO_ERROR,
255
                                     G_IO_ERROR,
212
                                     G_IO_ERROR_NOT_INITIALIZED,
256
                                     G_IO_ERROR_NOT_INITIALIZED,
Lines 214-220 Link Here
214
                return NULL; /* Not initialized yet */
258
                return NULL; /* Not initialized yet */
215
        }
259
        }
216
260
217
        return gclue_mozilla_create_query (NULL, priv->tower, error);
261
        skip_bss = g3g_should_skip_bsss (g3g);
262
        if (skip_bss) {
263
                g_debug ("Will skip BSSs in query due to our accuracy level");
264
        }
265
266
        return gclue_mozilla_create_query (priv->mozilla, FALSE, skip_bss,
267
                                           query_data_description, error);
218
}
268
}
219
269
220
static SoupMessage *
270
static SoupMessage *
Lines 224-230 Link Here
224
{
274
{
225
        GClue3GPrivate *priv = GCLUE_3G (web)->priv;
275
        GClue3GPrivate *priv = GCLUE_3G (web)->priv;
226
276
227
        if (priv->tower == NULL) {
277
        if (!gclue_mozilla_has_tower (priv->mozilla)) {
228
                g_set_error_literal (error,
278
                g_set_error_literal (error,
229
                                     G_IO_ERROR,
279
                                     G_IO_ERROR,
230
                                     G_IO_ERROR_NOT_INITIALIZED,
280
                                     G_IO_ERROR_NOT_INITIALIZED,
Lines 232-240 Link Here
232
                return NULL; /* Not initialized yet */
282
                return NULL; /* Not initialized yet */
233
        }
283
        }
234
284
235
        return gclue_mozilla_create_submit_query (location,
285
        return gclue_mozilla_create_submit_query (priv->mozilla,
236
                                                  NULL,
286
                                                  location,
237
                                                  priv->tower,
238
                                                  error);
287
                                                  error);
239
}
288
}
240
289
Lines 249-254 Link Here
249
                return GCLUE_ACCURACY_LEVEL_NONE;
298
                return GCLUE_ACCURACY_LEVEL_NONE;
250
}
299
}
251
300
301
gboolean gclue_3g_should_skip_tower (GClueAccuracyLevel level)
302
{
303
        return level < GCLUE_ACCURACY_LEVEL_NEIGHBORHOOD;
304
}
305
306
static gboolean
307
on_location_3gpp_timeout (gpointer user_data)
308
{
309
        GClue3G *g3g = GCLUE_3G (user_data);
310
        GClue3GPrivate *priv = g3g->priv;
311
312
        if (!gclue_mozilla_has_tower (priv->mozilla)) {
313
                g_debug ("3GPP location timeout, but no tower");
314
                priv->location_3gpp_timeout_id = 0;
315
                return G_SOURCE_REMOVE;
316
        }
317
318
        g_debug ("3GPP location timeout, re-sending existing location");
319
        gclue_web_source_refresh (GCLUE_WEB_SOURCE (g3g));
320
321
        return G_SOURCE_CONTINUE;
322
}
323
324
static void set_location_3gpp_timeout (GClue3G *g3g)
325
{
326
        GClue3GPrivate *priv = g3g->priv;
327
328
        g_debug ("Scheduling new 3GPP location timeout");
329
330
        cancel_location_3gpp_timeout (g3g);
331
        priv->location_3gpp_timeout_id = g_timeout_add_seconds (LOCATION_3GPP_TIMEOUT,
332
                                                                on_location_3gpp_timeout,
333
                                                                g3g);
334
}
335
252
static void
336
static void
253
on_fix_3g (GClueModem   *modem,
337
on_fix_3g (GClueModem   *modem,
254
           const gchar  *opc,
338
           const gchar  *opc,
Lines 257-271 Link Here
257
           GClueTowerTec tec,
341
           GClueTowerTec tec,
258
           gpointer    user_data)
342
           gpointer    user_data)
259
{
343
{
260
        GClue3GPrivate *priv = GCLUE_3G (user_data)->priv;
344
        GClue3G *g3g = GCLUE_3G (user_data);
345
        GClue3GPrivate *priv = g3g->priv;
346
347
        g_debug ("3GPP %s fix available",
348
                 tec == GCLUE_TOWER_TEC_NO_FIX ? "no" : "new");
261
349
262
        if (priv->tower == NULL)
350
        if (tec != GCLUE_TOWER_TEC_NO_FIX) {
263
                priv->tower = g_slice_new0 (GClue3GTower);
351
                GClue3GTower tower;
264
        g_strlcpy (priv->tower->opc, opc,
352
353
                g_strlcpy (tower.opc, opc,
265
                   GCLUE_3G_TOWER_OPERATOR_CODE_STR_LEN + 1);
354
                   GCLUE_3G_TOWER_OPERATOR_CODE_STR_LEN + 1);
266
        priv->tower->lac = lac;
355
                tower.lac = lac;
267
        priv->tower->cell_id = cell_id;
356
                tower.cell_id = cell_id;
268
        priv->tower->tec = tec;
357
                tower.tec = tec;
358
                set_location_3gpp_timeout (g3g);
359
                gclue_mozilla_set_tower (priv->mozilla, &tower);
360
        } else {
361
                cancel_location_3gpp_timeout (g3g);
362
                gclue_mozilla_set_tower (priv->mozilla, NULL);
363
        }
269
364
270
        gclue_web_source_refresh (GCLUE_WEB_SOURCE (user_data));
365
        gclue_web_source_refresh (GCLUE_WEB_SOURCE (user_data));
271
}
366
}
Lines 286-301 Link Here
286
        if (base_result != GCLUE_LOCATION_SOURCE_START_RESULT_OK)
381
        if (base_result != GCLUE_LOCATION_SOURCE_START_RESULT_OK)
287
                return base_result;
382
                return base_result;
288
383
289
        if (priv->tower != NULL) {
384
        if (gclue_3g_running == 0) {
290
                g_slice_free (GClue3GTower, priv->tower);
385
                g_debug ("First 3GPP source starting up");
291
                priv->tower = NULL;
292
        }
386
        }
387
        gclue_3g_running++;
293
388
294
        g_signal_connect (priv->modem,
389
        g_signal_connect (priv->modem,
295
                          "fix-3g",
390
                          "fix-3g",
296
                          G_CALLBACK (on_fix_3g),
391
                          G_CALLBACK (on_fix_3g),
297
                          source);
392
                          source);
298
393
394
        /* Emits fix-3g signal even if the location hasn't actually changed to prime us */
299
        if (gclue_modem_get_is_3g_available (priv->modem))
395
        if (gclue_modem_get_is_3g_available (priv->modem))
300
                gclue_modem_enable_3g (priv->modem,
396
                gclue_modem_enable_3g (priv->modem,
301
                                       priv->cancellable,
397
                                       priv->cancellable,
Lines 307-313 Link Here
307
static GClueLocationSourceStopResult
403
static GClueLocationSourceStopResult
308
gclue_3g_stop (GClueLocationSource *source)
404
gclue_3g_stop (GClueLocationSource *source)
309
{
405
{
310
        GClue3GPrivate *priv = GCLUE_3G (source)->priv;
406
        GClue3G *g3g = GCLUE_3G (source);
407
        GClue3GPrivate *priv = g3g->priv;
311
        GClueLocationSourceClass *base_class;
408
        GClueLocationSourceClass *base_class;
312
        GError *error = NULL;
409
        GError *error = NULL;
313
        GClueLocationSourceStopResult base_result;
410
        GClueLocationSourceStopResult base_result;
Lines 316-328 Link Here
316
413
317
        base_class = GCLUE_LOCATION_SOURCE_CLASS (gclue_3g_parent_class);
414
        base_class = GCLUE_LOCATION_SOURCE_CLASS (gclue_3g_parent_class);
318
        base_result = base_class->stop (source);
415
        base_result = base_class->stop (source);
319
        if (base_result == GCLUE_LOCATION_SOURCE_STOP_RESULT_STILL_USED)
416
        if (base_result != GCLUE_LOCATION_SOURCE_STOP_RESULT_OK)
320
                return base_result;
417
                return base_result;
321
418
322
        g_signal_handlers_disconnect_by_func (G_OBJECT (priv->modem),
419
        g_signal_handlers_disconnect_by_func (G_OBJECT (priv->modem),
323
                                              G_CALLBACK (on_fix_3g),
420
                                              G_CALLBACK (on_fix_3g),
324
                                              source);
421
                                              source);
325
422
423
        cancel_location_3gpp_timeout (g3g);
424
425
        g_assert (gclue_3g_running > 0);
426
        gclue_3g_running--;
427
        if (gclue_3g_running > 0) {
428
                return base_result;
429
        }
430
431
        g_debug ("Last 3GPP source stopping, disabling location gathering and invalidating existing tower");
432
326
        if (gclue_modem_get_is_3g_available (priv->modem))
433
        if (gclue_modem_get_is_3g_available (priv->modem))
327
                if (!gclue_modem_disable_3g (priv->modem,
434
                if (!gclue_modem_disable_3g (priv->modem,
328
                                             priv->cancellable,
435
                                             priv->cancellable,
Lines 332-336 Link Here
332
                        g_error_free (error);
439
                        g_error_free (error);
333
                }
440
                }
334
441
442
        gclue_mozilla_set_tower (priv->mozilla, NULL);
443
335
        return base_result;
444
        return base_result;
336
}
445
}
(-)geoclue-2.6.0/src/gclue-3g.h (-1 / +9 lines)
Lines 22-27 Link Here
22
#ifndef GCLUE_3G_H
22
#ifndef GCLUE_3G_H
23
#define GCLUE_3G_H
23
#define GCLUE_3G_H
24
24
25
#include "config.h"
26
25
#include <glib.h>
27
#include <glib.h>
26
#include <gio/gio.h>
28
#include <gio/gio.h>
27
#include "gclue-web-source.h"
29
#include "gclue-web-source.h"
Lines 62-68 Link Here
62
        GClueWebSourceClass parent_class;
64
        GClueWebSourceClass parent_class;
63
};
65
};
64
66
65
GClue3G * gclue_3g_get_singleton (void);
67
GClue3G * gclue_3g_get_singleton (GClueAccuracyLevel level);
68
69
#if GCLUE_USE_3G_SOURCE
70
gboolean gclue_3g_should_skip_tower (GClueAccuracyLevel level);
71
#else
72
static inline gboolean gclue_3g_should_skip_tower (GClueAccuracyLevel level) { return TRUE; }
73
#endif
66
74
67
G_END_DECLS
75
G_END_DECLS
68
76
(-)geoclue-2.6.0/src/gclue-cdma.c (-5 / +7 lines)
Lines 79-92 Link Here
79
                 GAsyncResult *result,
79
                 GAsyncResult *result,
80
                 gpointer      user_data)
80
                 gpointer      user_data)
81
{
81
{
82
        GClueCDMA *source = GCLUE_CDMA (user_data);
82
        g_autoptr(GError) error = NULL;
83
        GError *error = NULL;
84
83
85
        if (!gclue_modem_enable_cdma_finish (source->priv->modem,
84
        if (!gclue_modem_enable_cdma_finish (GCLUE_MODEM (source_object),
86
                                             result,
85
                                             result,
87
                                             &error)) {
86
                                             &error)) {
87
                if (error && !g_error_matches (error, G_IO_ERROR,
88
                                                G_IO_ERROR_CANCELLED)) {
88
                g_warning ("Failed to enable CDMA: %s", error->message);
89
                g_warning ("Failed to enable CDMA: %s", error->message);
89
                g_error_free (error);
90
                }
90
        }
91
        }
91
}
92
}
92
93
Lines 199-205 Link Here
199
200
200
        location = gclue_location_new (latitude,
201
        location = gclue_location_new (latitude,
201
                                       longitude,
202
                                       longitude,
202
                                       1000);     /* Assume 1 km accuracy */
203
                                       1000, /* Assume 1 km accuracy */
204
                                       "CDMA");
203
205
204
        gclue_location_source_set_location (GCLUE_LOCATION_SOURCE (user_data),
206
        gclue_location_source_set_location (GCLUE_LOCATION_SOURCE (user_data),
205
                                            location);
207
                                            location);
(-)geoclue-2.6.0/src/gclue-client-info.c (-2 / +5 lines)
Lines 356-370 Link Here
356
        GTask *task = G_TASK (user_data);
356
        GTask *task = G_TASK (user_data);
357
        gpointer *info = g_task_get_source_object (task);
357
        gpointer *info = g_task_get_source_object (task);
358
        GClueClientInfoPrivate *priv = GCLUE_CLIENT_INFO (info)->priv;
358
        GClueClientInfoPrivate *priv = GCLUE_CLIENT_INFO (info)->priv;
359
        GDBusProxy *dbus_proxy;
359
        GError *error = NULL;
360
        GError *error = NULL;
360
361
361
        priv->dbus_proxy = g_dbus_proxy_new_for_bus_finish (res, &error);
362
        dbus_proxy = g_dbus_proxy_new_for_bus_finish (res, &error);
362
        if (priv->dbus_proxy == NULL) {
363
        if (dbus_proxy == NULL) {
363
                g_task_return_error (task, error);
364
                g_task_return_error (task, error);
364
                g_object_unref (task);
365
                g_object_unref (task);
365
                return;
366
                return;
366
        }
367
        }
367
368
369
        priv->dbus_proxy = dbus_proxy;
370
368
        g_dbus_proxy_call (priv->dbus_proxy,
371
        g_dbus_proxy_call (priv->dbus_proxy,
369
                           "GetConnectionUnixUser",
372
                           "GetConnectionUnixUser",
370
                           g_variant_new ("(s)", priv->bus_name),
373
                           g_variant_new ("(s)", priv->bus_name),
(-)geoclue-2.6.0/src/gclue-compass.c (-7 / +9 lines)
Lines 141-155 Link Here
141
{
141
{
142
        GClueCompass *compass;
142
        GClueCompass *compass;
143
        Compass *proxy = COMPASS (source_object);
143
        Compass *proxy = COMPASS (source_object);
144
        GError *error = NULL;
144
        g_autoptr(GError) error = NULL;
145
145
146
        if (!compass_call_claim_compass_finish (proxy, res, &error)) {
146
        if (!compass_call_claim_compass_finish (proxy, res, &error)) {
147
                if (error->code != G_IO_ERROR_CANCELLED)
147
                if (error && !g_error_matches (error, G_IO_ERROR,
148
                                               G_IO_ERROR_CANCELLED)) {
148
                        g_debug ("Failed to claim IIO proxy compass: %s",
149
                        g_debug ("Failed to claim IIO proxy compass: %s",
149
                                 error->message);
150
                                 error->message);
150
                g_error_free (error);
151
                }
151
                g_object_unref (proxy);
152
152
153
                g_object_unref (proxy);
153
                return;
154
                return;
154
        }
155
        }
155
        g_debug ("IIO compass claimed");
156
        g_debug ("IIO compass claimed");
Lines 173-186 Link Here
173
{
174
{
174
        GClueCompass *compass;
175
        GClueCompass *compass;
175
        Compass *proxy;
176
        Compass *proxy;
176
        GError *error = NULL;
177
        g_autoptr(GError) error = NULL;
177
178
178
        proxy = compass_proxy_new_for_bus_finish (res, &error);
179
        proxy = compass_proxy_new_for_bus_finish (res, &error);
179
        if (proxy == NULL) {
180
        if (proxy == NULL) {
180
                if (error->code != G_IO_ERROR_CANCELLED)
181
                if (error && !g_error_matches (error, G_IO_ERROR,
182
                                               G_IO_ERROR_CANCELLED)) {
181
                        g_debug ("Failed to connect to IIO compass proxy: %s",
183
                        g_debug ("Failed to connect to IIO compass proxy: %s",
182
                                 error->message);
184
                                 error->message);
183
                g_error_free (error);
185
                }
184
186
185
                return;
187
                return;
186
        }
188
        }
(-)geoclue-2.6.0/src/gclue-config.c (-3 / +3 lines)
Lines 236-242 Link Here
236
                                                "url",
236
                                                "url",
237
                                                &error);
237
                                                &error);
238
        if (error != NULL) {
238
        if (error != NULL) {
239
                g_debug ("Failed to get config \"wifi/url\": %s",
239
                g_debug ("Using the default locate URL: %s",
240
                         error->message);
240
                         error->message);
241
                g_clear_error (&error);
241
                g_clear_error (&error);
242
                priv->wifi_url = g_strdup (DEFAULT_WIFI_URL);
242
                priv->wifi_url = g_strdup (DEFAULT_WIFI_URL);
Lines 259-265 Link Here
259
                                                       "submission-url",
259
                                                       "submission-url",
260
                                                       &error);
260
                                                       &error);
261
        if (error != NULL) {
261
        if (error != NULL) {
262
                g_debug ("Failed to get config \"wifi/submission-url\": %s",
262
                g_debug ("Using the default submit URL: %s",
263
                         error->message);
263
                         error->message);
264
                g_clear_error (&error);
264
                g_clear_error (&error);
265
                priv->wifi_submit_url = g_strdup (DEFAULT_WIFI_SUBMIT_URL);
265
                priv->wifi_submit_url = g_strdup (DEFAULT_WIFI_SUBMIT_URL);
Lines 270-276 Link Here
270
                                                        "submission-nick",
270
                                                        "submission-nick",
271
                                                        &error);
271
                                                        &error);
272
        if (error != NULL) {
272
        if (error != NULL) {
273
                g_debug ("Failed to get config \"wifi/submission-nick\": %s",
273
                g_debug ("Using the default submission nick: %s",
274
                         error->message);
274
                         error->message);
275
                g_error_free (error);
275
                g_error_free (error);
276
                priv->wifi_submit_nick = g_strdup (DEFAULT_WIFI_SUBMIT_NICK);
276
                priv->wifi_submit_nick = g_strdup (DEFAULT_WIFI_SUBMIT_NICK);
(-)geoclue-2.6.0/src/gclue-location-source.c (-4 / +13 lines)
Lines 419-445 Link Here
419
        priv->location = gclue_location_duplicate (location);
419
        priv->location = gclue_location_duplicate (location);
420
420
421
        if (priv->scramble_location) {
421
        if (priv->scramble_location) {
422
                gdouble latitude, distance, accuracy;
422
                gdouble latitude, distance, accuracy, scramble_range;
423
423
424
                latitude = gclue_location_get_latitude (priv->location);
424
                latitude = gclue_location_get_latitude (priv->location);
425
                accuracy = gclue_location_get_accuracy (priv->location);
425
                accuracy = gclue_location_get_accuracy (priv->location);
426
426
427
                scramble_range = GCLUE_LOCATION_ACCURACY_NEIGHBORHOOD;
428
                if (accuracy >= scramble_range) {
429
                        /* If the location source is already pretty inaccurate
430
                         * do just a limited range scrambling to be sure.
431
                         */
432
                        scramble_range /= 3;
433
                }
434
427
                /* Randomization is needed to stop apps from calculationg the
435
                /* Randomization is needed to stop apps from calculationg the
428
                 * actual location.
436
                 * actual location.
429
                 */
437
                 */
430
                distance = (gdouble) g_random_int_range (1, 3);
438
                distance = g_random_double_range (0, scramble_range);
439
                distance /= 1000;
431
440
432
                if (g_random_boolean ())
441
                if (g_random_boolean ())
433
                        latitude += distance * LATITUDE_IN_KM;
442
                        latitude += distance * LATITUDE_IN_KM;
434
                else
443
                else
435
                        latitude -= distance * LATITUDE_IN_KM;
444
                        latitude -= distance * LATITUDE_IN_KM;
436
                accuracy += 3000;
445
                accuracy += scramble_range;
437
446
438
                g_object_set (G_OBJECT (priv->location),
447
                g_object_set (G_OBJECT (priv->location),
439
                              "latitude", latitude,
448
                              "latitude", latitude,
440
                              "accuracy", accuracy,
449
                              "accuracy", accuracy,
441
                              NULL);
450
                              NULL);
442
                g_debug ("location scrambled");
451
                g_debug ("%s location scrambled", G_OBJECT_TYPE_NAME (source));
443
        }
452
        }
444
453
445
        speed = gclue_location_get_speed (location);
454
        speed = gclue_location_get_speed (location);
(-)geoclue-2.6.0/src/gclue-location.c (-2 / +33 lines)
Lines 546-551 Link Here
546
 * @latitude: a valid latitude
546
 * @latitude: a valid latitude
547
 * @longitude: a valid longitude
547
 * @longitude: a valid longitude
548
 * @accuracy: accuracy of location in meters
548
 * @accuracy: accuracy of location in meters
549
 * @description: a description for the location
549
 *
550
 *
550
 * Creates a new #GClueLocation object.
551
 * Creates a new #GClueLocation object.
551
 *
552
 *
Lines 554-565 Link Here
554
GClueLocation *
555
GClueLocation *
555
gclue_location_new (gdouble latitude,
556
gclue_location_new (gdouble latitude,
556
                    gdouble longitude,
557
                    gdouble longitude,
557
                    gdouble accuracy)
558
                    gdouble accuracy,
559
                    const char *description)
558
{
560
{
559
        return g_object_new (GCLUE_TYPE_LOCATION,
561
        return g_object_new (GCLUE_TYPE_LOCATION,
560
                             "latitude", latitude,
562
                             "latitude", latitude,
561
                             "longitude", longitude,
563
                             "longitude", longitude,
562
                             "accuracy", accuracy,
564
                             "accuracy", accuracy,
565
                             "description", description,
563
                             NULL);
566
                             NULL);
564
}
567
}
565
568
Lines 642-647 Link Here
642
                                 "longitude", longitude,
645
                                 "longitude", longitude,
643
                                 "accuracy", accuracy,
646
                                 "accuracy", accuracy,
644
                                 "timestamp", timestamp,
647
                                 "timestamp", timestamp,
648
                                 "description", "GPS GGA",
645
                                 NULL);
649
                                 NULL);
646
        if (altitude != GCLUE_LOCATION_ALTITUDE_UNKNOWN)
650
        if (altitude != GCLUE_LOCATION_ALTITUDE_UNKNOWN)
647
                g_object_set (location, "altitude", altitude, NULL);
651
                g_object_set (location, "altitude", altitude, NULL);
Lines 689-694 Link Here
689
                                 "timestamp", timestamp,
693
                                 "timestamp", timestamp,
690
                                 "speed", speed,
694
                                 "speed", speed,
691
                                 "heading", heading,
695
                                 "heading", heading,
696
                                 "description", "GPS RMC",
692
                                 NULL);
697
                                 NULL);
693
698
694
        if (prev_location != NULL) {
699
        if (prev_location != NULL) {
Lines 770-776 Link Here
770
 * gclue_location_duplicate:
775
 * gclue_location_duplicate:
771
 * @location: the #GClueLocation instance to duplicate.
776
 * @location: the #GClueLocation instance to duplicate.
772
 *
777
 *
773
 * Creates a new copy of @location object.
778
 * Creates a new copy of @location object (with the same timestamp).
774
 *
779
 *
775
 * Returns: a new #GClueLocation object. Use g_object_unref() when done.
780
 * Returns: a new #GClueLocation object. Use g_object_unref() when done.
776
 **/
781
 **/
Lines 788-793 Link Here
788
                 "timestamp", location->priv->timestamp,
793
                 "timestamp", location->priv->timestamp,
789
                 "speed", location->priv->speed,
794
                 "speed", location->priv->speed,
790
                 "heading", location->priv->heading,
795
                 "heading", location->priv->heading,
796
                 "description", location->priv->description,
797
                 NULL);
798
}
799
800
/**
801
 * gclue_location_duplicate_fresh:
802
 * @location: the #GClueLocation instance to duplicate.
803
 *
804
 * Creates a new copy of @location object with a refreshed timestamp.
805
 *
806
 * Returns: a new #GClueLocation object. Use g_object_unref() when done.
807
 **/
808
GClueLocation *
809
gclue_location_duplicate_fresh (GClueLocation *location)
810
{
811
        g_return_val_if_fail (GCLUE_IS_LOCATION (location), NULL);
812
813
        return g_object_new
814
                (GCLUE_TYPE_LOCATION,
815
                 "latitude", location->priv->latitude,
816
                 "longitude", location->priv->longitude,
817
                 "accuracy", location->priv->accuracy,
818
                 "altitude", location->priv->altitude,
819
                 "speed", location->priv->speed,
820
                 "heading", location->priv->heading,
821
                 "description", location->priv->description,
791
                 NULL);
822
                 NULL);
792
}
823
}
793
824
(-)geoclue-2.6.0/src/gclue-location.h (-1 / +22 lines)
Lines 77-82 Link Here
77
#define GCLUE_LOCATION_ACCURACY_UNKNOWN -1
77
#define GCLUE_LOCATION_ACCURACY_UNKNOWN -1
78
78
79
/**
79
/**
80
 * GCLUE_LOCATION_ACCURACY_EXACT:
81
 *
82
 * Constant representing exact-level accuracy.
83
 */
84
#define GCLUE_LOCATION_ACCURACY_EXACT 50 /* 50 m */
85
86
/**
80
 * GCLUE_LOCATION_ACCURACY_STREET:
87
 * GCLUE_LOCATION_ACCURACY_STREET:
81
 *
88
 *
82
 * Constant representing street-level accuracy.
89
 * Constant representing street-level accuracy.
Lines 84-89 Link Here
84
#define GCLUE_LOCATION_ACCURACY_STREET 1000 /* 1 km */
91
#define GCLUE_LOCATION_ACCURACY_STREET 1000 /* 1 km */
85
92
86
/**
93
/**
94
 * GCLUE_LOCATION_ACCURACY_NEIGHBORHOOD:
95
 *
96
 * Constant representing neighborhood-level accuracy.
97
 */
98
#define GCLUE_LOCATION_ACCURACY_NEIGHBORHOOD 3000 /* 3 km */
99
100
/**
87
 * GCLUE_LOCATION_ACCURACY_CITY:
101
 * GCLUE_LOCATION_ACCURACY_CITY:
88
 *
102
 *
89
 * Constant representing city-level accuracy.
103
 * Constant representing city-level accuracy.
Lines 94-99 Link Here
94
 * GCLUE_LOCATION_ACCURACY_REGION:
108
 * GCLUE_LOCATION_ACCURACY_REGION:
95
 *
109
 *
96
 * Constant representing region-level accuracy.
110
 * Constant representing region-level accuracy.
111
 *
112
 * Currently unused.
97
 */
113
 */
98
#define GCLUE_LOCATION_ACCURACY_REGION 50000 /* 50 km */
114
#define GCLUE_LOCATION_ACCURACY_REGION 50000 /* 50 km */
99
115
Lines 108-113 Link Here
108
 * GCLUE_LOCATION_ACCURACY_CONTINENT:
124
 * GCLUE_LOCATION_ACCURACY_CONTINENT:
109
 *
125
 *
110
 * Constant representing continent-level accuracy.
126
 * Constant representing continent-level accuracy.
127
 *
128
 * Currently unused.
111
 */
129
 */
112
#define GCLUE_LOCATION_ACCURACY_CONTINENT 3000000 /* 3000 km */
130
#define GCLUE_LOCATION_ACCURACY_CONTINENT 3000000 /* 3000 km */
113
131
Lines 127-133 Link Here
127
145
128
GClueLocation *gclue_location_new (gdouble latitude,
146
GClueLocation *gclue_location_new (gdouble latitude,
129
                                   gdouble longitude,
147
                                   gdouble longitude,
130
                                   gdouble accuracy);
148
                                   gdouble accuracy,
149
                                   const char *description);
131
150
132
GClueLocation *gclue_location_new_full
151
GClueLocation *gclue_location_new_full
133
                                  (gdouble     latitude,
152
                                  (gdouble     latitude,
Lines 146-151 Link Here
146
165
147
GClueLocation *gclue_location_duplicate
166
GClueLocation *gclue_location_duplicate
148
                                  (GClueLocation *location);
167
                                  (GClueLocation *location);
168
GClueLocation *gclue_location_duplicate_fresh
169
                                  (GClueLocation *location);
149
170
150
void gclue_location_set_description
171
void gclue_location_set_description
151
                                  (GClueLocation *loc,
172
                                  (GClueLocation *loc,
(-)geoclue-2.6.0/src/gclue-locator.c (-8 / +15 lines)
Lines 81-95 Link Here
81
81
82
static void
82
static void
83
set_location (GClueLocator  *locator,
83
set_location (GClueLocator  *locator,
84
              GClueLocation *location)
84
              GClueLocation *location,
85
              const char *src_name)
85
{
86
{
86
        GClueLocation *cur_location;
87
        GClueLocation *cur_location;
87
88
88
        cur_location = gclue_location_source_get_location
89
        cur_location = gclue_location_source_get_location
89
                        (GCLUE_LOCATION_SOURCE (locator));
90
                        (GCLUE_LOCATION_SOURCE (locator));
90
91
91
        g_debug ("New location available");
92
93
        if (cur_location != NULL) {
92
        if (cur_location != NULL) {
94
            guint64 cur_timestamp, new_timestamp;
93
            guint64 cur_timestamp, new_timestamp;
95
            double dist, speed;
94
            double dist, speed;
Lines 97-103 Link Here
97
            cur_timestamp = gclue_location_get_timestamp (cur_location);
96
            cur_timestamp = gclue_location_get_timestamp (cur_location);
98
            new_timestamp = gclue_location_get_timestamp (location);
97
            new_timestamp = gclue_location_get_timestamp (location);
99
            if (new_timestamp < cur_timestamp) {
98
            if (new_timestamp < cur_timestamp) {
100
                    g_debug ("New location older than current, ignoring.");
99
                    g_debug ("New %s location older than current, ignoring.",
100
                             src_name);
101
                    return;
101
                    return;
102
            }
102
            }
103
103
Lines 126-136 Link Here
126
                     * a reasonable speed, OR it is more or as accurate as
126
                     * a reasonable speed, OR it is more or as accurate as
127
                     * the previous one.
127
                     * the previous one.
128
                     */
128
                     */
129
                    g_debug ("Ignoring less accurate new location");
129
                    g_debug ("Ignoring less accurate new %s location", src_name);
130
                    return;
130
                    return;
131
            }
131
            }
132
        }
132
        }
133
133
134
        g_debug ("New location available from %s", src_name);
134
        gclue_location_source_set_location (GCLUE_LOCATION_SOURCE (locator),
135
        gclue_location_source_set_location (GCLUE_LOCATION_SOURCE (locator),
135
                                            location);
136
                                            location);
136
}
137
}
Lines 183-189 Link Here
183
        GClueLocation *location;
184
        GClueLocation *location;
184
185
185
        location = gclue_location_source_get_location (source);
186
        location = gclue_location_source_get_location (source);
186
        set_location (locator, location);
187
        set_location (locator, location, G_OBJECT_TYPE_NAME (source));
187
}
188
}
188
189
189
static gboolean
190
static gboolean
Lines 206-212 Link Here
206
207
207
        location = gclue_location_source_get_location (src);
208
        location = gclue_location_source_get_location (src);
208
        if (gclue_location_source_get_active (src) && location != NULL)
209
        if (gclue_location_source_get_active (src) && location != NULL)
209
                set_location (locator, location);
210
                set_location (locator, location, G_OBJECT_TYPE_NAME (src));
210
211
211
        gclue_location_source_start (src);
212
        gclue_location_source_start (src);
212
}
213
}
Lines 364-370 Link Here
364
365
365
#if GCLUE_USE_3G_SOURCE
366
#if GCLUE_USE_3G_SOURCE
366
        if (gclue_config_get_enable_3g_source (gconfig)) {
367
        if (gclue_config_get_enable_3g_source (gconfig)) {
367
                GClue3G *source = gclue_3g_get_singleton ();
368
                GClue3G *source = gclue_3g_get_singleton (locator->priv->accuracy_level);
368
                locator->priv->sources = g_list_append (locator->priv->sources,
369
                locator->priv->sources = g_list_append (locator->priv->sources,
369
                                                        source);
370
                                                        source);
370
        }
371
        }
Lines 387-400 Link Here
387
                GClueModemGPS *gps = gclue_modem_gps_get_singleton ();
388
                GClueModemGPS *gps = gclue_modem_gps_get_singleton ();
388
                locator->priv->sources = g_list_append (locator->priv->sources,
389
                locator->priv->sources = g_list_append (locator->priv->sources,
389
                                                        gps);
390
                                                        gps);
391
                if (!submit_source) {
390
                submit_source = GCLUE_LOCATION_SOURCE (gps);
392
                submit_source = GCLUE_LOCATION_SOURCE (gps);
391
        }
393
        }
394
        }
392
#endif
395
#endif
393
#if GCLUE_USE_NMEA_SOURCE
396
#if GCLUE_USE_NMEA_SOURCE
394
        if (gclue_config_get_enable_nmea_source (gconfig)) {
397
        if (gclue_config_get_enable_nmea_source (gconfig)) {
395
                GClueNMEASource *nmea = gclue_nmea_source_get_singleton ();
398
                GClueNMEASource *nmea = gclue_nmea_source_get_singleton ();
396
                locator->priv->sources = g_list_append (locator->priv->sources,
399
                locator->priv->sources = g_list_append (locator->priv->sources,
397
                                                        nmea);
400
                                                        nmea);
401
                if (!submit_source) {
402
                        submit_source = GCLUE_LOCATION_SOURCE (nmea);
403
                }
404
398
        }
405
        }
399
#endif
406
#endif
400
407
(-)geoclue-2.6.0/src/gclue-modem-gps.c (-6 / +7 lines)
Lines 80-93 Link Here
80
                GAsyncResult *result,
80
                GAsyncResult *result,
81
                gpointer      user_data)
81
                gpointer      user_data)
82
{
82
{
83
        GClueModemGPS *source = GCLUE_MODEM_GPS (user_data);
83
        g_autoptr(GError) error = NULL;
84
        GError *error = NULL;
85
84
86
        if (!gclue_modem_enable_gps_finish (source->priv->modem,
85
        if (!gclue_modem_enable_gps_finish (GCLUE_MODEM (source_object),
87
                                            result,
86
                                            result,
88
                                            &error)) {
87
                                            &error)) {
88
                if (error && !g_error_matches (error, G_IO_ERROR,
89
                                               G_IO_ERROR_CANCELLED)) {
89
                g_warning ("Failed to enable GPS: %s", error->message);
90
                g_warning ("Failed to enable GPS: %s", error->message);
90
                g_error_free (error);
91
                }
91
        }
92
        }
92
}
93
}
93
94
Lines 168-177 Link Here
168
                                          source);
169
                                          source);
169
        threshold = gclue_location_source_get_time_threshold
170
        threshold = gclue_location_source_get_time_threshold
170
                        (GCLUE_LOCATION_SOURCE (source));
171
                        (GCLUE_LOCATION_SOURCE (source));
171
        g_signal_connect (threshold,
172
        g_signal_connect_object (threshold,
172
                          "notify::value",
173
                          "notify::value",
173
                          G_CALLBACK (on_time_threshold_changed),
174
                          G_CALLBACK (on_time_threshold_changed),
174
                          source);
175
                                 source, 0);
175
}
176
}
176
177
177
static void
178
static void
(-)geoclue-2.6.0/src/gclue-modem-manager.c (-68 / +165 lines)
Lines 45-55 Link Here
45
        MMModem *modem;
45
        MMModem *modem;
46
        MMModemLocation *modem_location;
46
        MMModemLocation *modem_location;
47
        MMLocation3gpp *location_3gpp;
47
        MMLocation3gpp *location_3gpp;
48
        gboolean location_3gpp_ignore_previous;
48
        MMLocationGpsNmea *location_nmea;
49
        MMLocationGpsNmea *location_nmea;
49
50
50
        GCancellable *cancellable;
51
        GCancellable *cancellable;
51
52
52
        MMModemLocationSource caps; /* Caps we set or are going to set */
53
        MMModemLocationSource caps; /* Caps we set or are going to set */
54
        GClueTowerTec tec;
53
55
54
        guint time_threshold;
56
        guint time_threshold;
55
};
57
};
Lines 286-292 Link Here
286
is_location_3gpp_same (GClueModemManager *manager,
288
is_location_3gpp_same (GClueModemManager *manager,
287
                       const gchar       *new_opc,
289
                       const gchar       *new_opc,
288
                       gulong             new_lac,
290
                       gulong             new_lac,
289
                       gulong             new_cell_id)
291
                       gulong             new_cell_id,
292
                       GClueTowerTec      new_tec)
290
{
293
{
291
        GClueModemManagerPrivate *priv = manager->priv;
294
        GClueModemManagerPrivate *priv = manager->priv;
292
        const gchar *opc;
295
        const gchar *opc;
Lines 295-301 Link Here
295
        gchar opc_buf[GCLUE_3G_TOWER_OPERATOR_CODE_STR_LEN + 1];
298
        gchar opc_buf[GCLUE_3G_TOWER_OPERATOR_CODE_STR_LEN + 1];
296
#endif
299
#endif
297
300
298
        if (priv->location_3gpp == NULL)
301
        if (priv->location_3gpp == NULL || priv->location_3gpp_ignore_previous)
299
                return FALSE;
302
                return FALSE;
300
303
301
#if MM_CHECK_VERSION(1, 18, 0)
304
#if MM_CHECK_VERSION(1, 18, 0)
Lines 306-316 Link Here
306
#endif
309
#endif
307
        lac = mm_location_3gpp_get_location_area_code (priv->location_3gpp);
310
        lac = mm_location_3gpp_get_location_area_code (priv->location_3gpp);
308
311
309
        // Most likely this is an LTE connection and with the mozilla
312
        // Use the tracking area code in place of the
310
        // services they use the tracking area code in place of the
313
        // location area code for LTE.
311
        // location area code in this case.
312
        // https://ichnaea.readthedocs.io/en/latest/api/geolocate.html#cell-tower-fields
314
        // https://ichnaea.readthedocs.io/en/latest/api/geolocate.html#cell-tower-fields
313
        if (lac == 0x0 || lac == 0xFFFE) {
315
        if (priv->tec == GCLUE_TOWER_TEC_4G) {
314
                lac = mm_location_3gpp_get_tracking_area_code(priv->location_3gpp);
316
                lac = mm_location_3gpp_get_tracking_area_code(priv->location_3gpp);
315
        }
317
        }
316
318
Lines 318-324 Link Here
318
320
319
        return (g_strcmp0 (opc, new_opc) == 0 &&
321
        return (g_strcmp0 (opc, new_opc) == 0 &&
320
                lac == new_lac &&
322
                lac == new_lac &&
321
                cell_id == new_cell_id);
323
                cell_id == new_cell_id &&
324
                priv->tec == new_tec);
325
}
326
327
static void clear_3gpp_location (GClueModemManager *manager)
328
{
329
        GClueModemManagerPrivate *priv = manager->priv;
330
331
        if (!priv->location_3gpp && !priv->location_3gpp_ignore_previous) {
332
                return;
333
        }
334
335
        g_clear_object (&priv->location_3gpp);
336
        g_signal_emit (manager, signals[FIX_3G], 0, NULL, 0, 0, GCLUE_TOWER_TEC_NO_FIX);
322
}
337
}
323
338
324
static void
339
static void
Lines 326-355 Link Here
326
                   GAsyncResult *res,
341
                   GAsyncResult *res,
327
                   gpointer      user_data)
342
                   gpointer      user_data)
328
{
343
{
329
        GClueModemManager *manager = GCLUE_MODEM_MANAGER (user_data);
344
        GClueModemManager *manager;
330
        GClueModemManagerPrivate *priv = manager->priv;
345
        GClueModemManagerPrivate *priv;
331
        MMModemLocation *modem_location = MM_MODEM_LOCATION (source_object);
346
        MMModemLocation *modem_location = MM_MODEM_LOCATION (source_object);
347
        MMModemAccessTechnology modem_access_tec;
332
        g_autoptr(MMLocation3gpp) location_3gpp = NULL;
348
        g_autoptr(MMLocation3gpp) location_3gpp = NULL;
333
        GError *error = NULL;
334
        const gchar *opc;
349
        const gchar *opc;
335
        gulong lac, cell_id;
350
        gulong lac, cell_id;
336
        GClueTowerTec tec = GCLUE_TOWER_TEC_3G;
351
        GClueTowerTec tec;
337
#if !MM_CHECK_VERSION(1, 18, 0)
352
#if !MM_CHECK_VERSION(1, 18, 0)
353
        g_autoptr(GError) error = NULL;
338
        gchar opc_buf[GCLUE_3G_TOWER_OPERATOR_CODE_STR_LEN + 1];
354
        gchar opc_buf[GCLUE_3G_TOWER_OPERATOR_CODE_STR_LEN + 1];
339
#endif
340
355
341
        location_3gpp = mm_modem_location_get_3gpp_finish (modem_location,
356
        location_3gpp = mm_modem_location_get_3gpp_finish (modem_location,
342
                                                           res,
357
                                                           res,
343
                                                           &error);
358
                                                           &error);
344
        if (error != NULL) {
359
        if (error != NULL) {
360
                if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
345
                g_warning ("Failed to get location from 3GPP: %s",
361
                g_warning ("Failed to get location from 3GPP: %s",
346
                           error->message);
362
                           error->message);
347
                g_error_free (error);
363
                }
364
348
                return;
365
                return;
349
        }
366
        }
367
#else
368
        location_3gpp = mm_modem_location_get_signaled_3gpp (modem_location);
369
#endif
370
371
        manager = GCLUE_MODEM_MANAGER (user_data);
372
        priv = manager->priv;
350
373
351
        if (location_3gpp == NULL) {
374
        if (location_3gpp == NULL) {
352
                g_debug ("No 3GPP");
375
                g_debug ("No 3GPP");
376
                clear_3gpp_location (manager);
377
                priv->location_3gpp_ignore_previous = FALSE;
353
                return;
378
                return;
354
        }
379
        }
355
380
Lines 364-409 Link Here
364
389
365
        lac = mm_location_3gpp_get_location_area_code (location_3gpp);
390
        lac = mm_location_3gpp_get_location_area_code (location_3gpp);
366
391
367
        // Most likely this is an LTE connection and with the mozilla
392
        cell_id = mm_location_3gpp_get_cell_id (location_3gpp);
368
        // services they use the tracking area code in place of the
393
369
        // location area code in this case.
394
        modem_access_tec = mm_modem_get_access_technologies(priv->modem);
370
        // https://ichnaea.readthedocs.io/en/latest/api/geolocate.html#cell-tower-fields
395
371
        if (lac == 0x0 || lac == 0xFFFE) {
396
        if (modem_access_tec == MM_MODEM_ACCESS_TECHNOLOGY_GSM ||
397
            modem_access_tec == MM_MODEM_ACCESS_TECHNOLOGY_GPRS ||
398
            modem_access_tec == MM_MODEM_ACCESS_TECHNOLOGY_EDGE) {
399
                tec = GCLUE_TOWER_TEC_2G;
400
        } else if (modem_access_tec == MM_MODEM_ACCESS_TECHNOLOGY_UMTS ||
401
                   modem_access_tec == MM_MODEM_ACCESS_TECHNOLOGY_HSDPA ||
402
                   modem_access_tec == MM_MODEM_ACCESS_TECHNOLOGY_HSUPA ||
403
                   modem_access_tec == MM_MODEM_ACCESS_TECHNOLOGY_HSPA ||
404
                   modem_access_tec == MM_MODEM_ACCESS_TECHNOLOGY_HSPA_PLUS) {
405
                tec = GCLUE_TOWER_TEC_3G;
406
        } else if (modem_access_tec == MM_MODEM_ACCESS_TECHNOLOGY_LTE) {
372
                lac = mm_location_3gpp_get_tracking_area_code(location_3gpp);
407
                lac = mm_location_3gpp_get_tracking_area_code(location_3gpp);
373
                tec = GCLUE_TOWER_TEC_4G;
408
                tec = GCLUE_TOWER_TEC_4G;
409
        } else {
410
                tec = GCLUE_TOWER_TEC_UNKNOWN;
374
        }
411
        }
375
412
376
        cell_id = mm_location_3gpp_get_cell_id (location_3gpp);
413
        if (is_location_3gpp_same (manager, opc, lac, cell_id, tec)) {
377
378
        if (is_location_3gpp_same (manager, opc, lac, cell_id)) {
379
                g_debug ("New 3GPP location is same as last one");
414
                g_debug ("New 3GPP location is same as last one");
380
                return;
415
                return;
381
        }
416
        }
382
        g_clear_object (&priv->location_3gpp);
417
        g_clear_object (&priv->location_3gpp);
383
        priv->location_3gpp = g_steal_pointer (&location_3gpp);
418
        priv->location_3gpp = g_steal_pointer (&location_3gpp);
419
        priv->location_3gpp_ignore_previous = FALSE;
420
        priv->tec = tec;
384
421
385
        g_signal_emit (manager, signals[FIX_3G], 0, opc, lac, cell_id, tec);
422
        g_signal_emit (manager, signals[FIX_3G], 0, opc, lac, cell_id, tec);
386
}
423
}
387
424
388
static void
425
static void
426
on_location_changed_get_3gpp (GObject *modem_object,
427
                              GClueModemManager *manager)
428
{
429
#if MM_CHECK_VERSION(1, 18, 0)
430
	on_get_3gpp_ready(modem_object, NULL, manager);
431
#else
432
	mm_modem_location_get_3gpp (MM_MODEM_LOCATION (modem_object),
433
				    manager->priv->cancellable,
434
				    on_get_3gpp_ready,
435
				    manager);
436
#endif
437
}
438
439
static void
389
on_get_cdma_ready (GObject      *source_object,
440
on_get_cdma_ready (GObject      *source_object,
390
                   GAsyncResult *res,
441
                   GAsyncResult *res,
391
                   gpointer      user_data)
442
                   gpointer      user_data)
392
{
443
{
393
        GClueModemManager *manager = GCLUE_MODEM_MANAGER (user_data);
444
        GClueModemManager *manager;
394
        MMModemLocation *modem_location = MM_MODEM_LOCATION (source_object);
445
        MMModemLocation *modem_location = MM_MODEM_LOCATION (source_object);
395
        g_autoptr(MMLocationCdmaBs) location_cdma = NULL;
446
        g_autoptr(MMLocationCdmaBs) location_cdma = NULL;
396
        GError *error = NULL;
447
#if !MM_CHECK_VERSION(1, 18, 0)
448
        g_autoptr(GError) error = NULL;
397
449
398
        location_cdma = mm_modem_location_get_cdma_bs_finish (modem_location,
450
        location_cdma = mm_modem_location_get_cdma_bs_finish (modem_location,
399
                                                              res,
451
                                                              res,
400
                                                              &error);
452
                                                              &error);
401
        if (error != NULL) {
453
        if (error != NULL) {
402
                g_warning ("Failed to get location from 3GPP: %s",
454
                if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
455
                        g_warning ("Failed to get location from CDMA: %s",
403
                           error->message);
456
                           error->message);
404
                g_error_free (error);
457
                }
458
405
                return;
459
                return;
406
        }
460
        }
461
#else
462
        location_cdma = mm_modem_location_get_signaled_cdma_bs (modem_location);
463
#endif
464
465
        manager = GCLUE_MODEM_MANAGER (user_data);
407
466
408
        if (location_cdma == NULL) {
467
        if (location_cdma == NULL) {
409
                g_debug ("No CDMA");
468
                g_debug ("No CDMA");
Lines 417-422 Link Here
417
                       mm_location_cdma_bs_get_longitude (location_cdma));
476
                       mm_location_cdma_bs_get_longitude (location_cdma));
418
}
477
}
419
478
479
static void
480
on_location_changed_get_cdma (GObject *modem_object,
481
                              GClueModemManager *manager)
482
{
483
#if MM_CHECK_VERSION(1, 18, 0)
484
	on_get_cdma_ready(modem_object, NULL, manager);
485
#else
486
	mm_modem_location_get_cdma_bs (MM_MODEM_LOCATION (modem_object),
487
				manager->priv->cancellable,
488
				on_get_cdma_ready,
489
				manager);
490
#endif
491
}
492
420
static gboolean
493
static gboolean
421
is_location_gga_same (GClueModemManager *manager,
494
is_location_gga_same (GClueModemManager *manager,
422
                       const char       *new_gga)
495
                       const char       *new_gga)
Lines 436-459 Link Here
436
                       GAsyncResult *res,
509
                       GAsyncResult *res,
437
                       gpointer      user_data)
510
                       gpointer      user_data)
438
{
511
{
439
        GClueModemManager *manager = GCLUE_MODEM_MANAGER (user_data);
512
        GClueModemManager *manager;
440
        GClueModemManagerPrivate *priv = manager->priv;
513
        GClueModemManagerPrivate *priv;
441
        MMModemLocation *modem_location = MM_MODEM_LOCATION (source_object);
514
        MMModemLocation *modem_location = MM_MODEM_LOCATION (source_object);
442
        g_autoptr(MMLocationGpsNmea) location_nmea = NULL;
515
        g_autoptr(MMLocationGpsNmea) location_nmea = NULL;
443
        static const gchar *sentences[3];
516
        static const gchar *sentences[3];
444
        const gchar *gga, *rmc;
517
        const gchar *gga, *rmc;
445
        gint i = 0;
518
        gint i = 0;
446
        GError *error = NULL;
519
#if !MM_CHECK_VERSION(1, 18, 0)
520
        g_autoptr(GError) error = NULL;
447
521
448
        location_nmea = mm_modem_location_get_gps_nmea_finish (modem_location,
522
        location_nmea = mm_modem_location_get_gps_nmea_finish (modem_location,
449
                                                               res,
523
                                                               res,
450
                                                               &error);
524
                                                               &error);
451
        if (error != NULL) {
525
        if (error != NULL) {
526
                if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
452
                g_warning ("Failed to get location from NMEA information: %s",
527
                g_warning ("Failed to get location from NMEA information: %s",
453
                           error->message);
528
                           error->message);
454
                g_error_free (error);
529
                }
530
455
                return;
531
                return;
456
        }
532
        }
533
#else
534
	location_nmea = mm_modem_location_get_signaled_gps_nmea (modem_location);
535
#endif
536
537
        manager = GCLUE_MODEM_MANAGER (user_data);
538
        priv = manager->priv;
457
539
458
        if (location_nmea == NULL) {
540
        if (location_nmea == NULL) {
459
                g_debug ("No NMEA");
541
                g_debug ("No NMEA");
Lines 486-513 Link Here
486
}
568
}
487
569
488
static void
570
static void
571
on_location_changed_get_gps_nmea (GObject    *modem_object,
572
                                  GClueModemManager *manager)
573
{
574
#if MM_CHECK_VERSION(1, 18, 0)
575
	on_get_gps_nmea_ready(modem_object, NULL, manager);
576
#else
577
	mm_modem_location_get_gps_nmea (MM_MODEM_LOCATION (modem_object),
578
				manager->priv->cancellable,
579
				on_get_gps_nmea_ready,
580
				manager);
581
#endif
582
}
583
584
static void
489
on_location_changed (GObject    *modem_object,
585
on_location_changed (GObject    *modem_object,
490
                     GParamSpec *pspec,
586
                     GParamSpec *pspec,
491
                     gpointer    user_data)
587
                     gpointer    user_data)
492
{
588
{
493
        MMModemLocation *modem_location = MM_MODEM_LOCATION (modem_object);
494
        GClueModemManager *manager = GCLUE_MODEM_MANAGER (user_data);
589
        GClueModemManager *manager = GCLUE_MODEM_MANAGER (user_data);
495
590
496
        if ((manager->priv->caps & MM_MODEM_LOCATION_SOURCE_3GPP_LAC_CI) != 0)
591
        if ((manager->priv->caps & MM_MODEM_LOCATION_SOURCE_3GPP_LAC_CI) != 0)
497
                mm_modem_location_get_3gpp (modem_location,
592
		on_location_changed_get_3gpp (modem_object, manager);
498
                                            manager->priv->cancellable,
499
                                            on_get_3gpp_ready,
500
                                            manager);
501
        if ((manager->priv->caps & MM_MODEM_LOCATION_SOURCE_CDMA_BS) != 0)
593
        if ((manager->priv->caps & MM_MODEM_LOCATION_SOURCE_CDMA_BS) != 0)
502
                mm_modem_location_get_cdma_bs (modem_location,
594
		on_location_changed_get_cdma (modem_object, manager);
503
                                               manager->priv->cancellable,
504
                                               on_get_cdma_ready,
505
                                               manager);
506
        if ((manager->priv->caps & MM_MODEM_LOCATION_SOURCE_GPS_NMEA) != 0)
595
        if ((manager->priv->caps & MM_MODEM_LOCATION_SOURCE_GPS_NMEA) != 0)
507
                mm_modem_location_get_gps_nmea (modem_location,
596
		on_location_changed_get_gps_nmea (modem_object, manager);
508
                                                manager->priv->cancellable,
509
                                                on_get_gps_nmea_ready,
510
                                                manager);
511
}
597
}
512
598
513
static void
599
static void
Lines 516-523 Link Here
516
                         gpointer      user_data)
602
                         gpointer      user_data)
517
{
603
{
518
        GTask *task = G_TASK (user_data);
604
        GTask *task = G_TASK (user_data);
519
        GClueModemManager *manager;
605
        GClueModemManager *manager = GCLUE_MODEM_MANAGER
520
        GClueModemManagerPrivate *priv;
606
                (g_task_get_source_object (task));
607
        GClueModemManagerPrivate *priv = manager->priv;
521
        GError *error = NULL;
608
        GError *error = NULL;
522
609
523
        if (!mm_modem_location_setup_finish (MM_MODEM_LOCATION (modem_object),
610
        if (!mm_modem_location_setup_finish (MM_MODEM_LOCATION (modem_object),
Lines 527-536 Link Here
527
614
528
                goto out;
615
                goto out;
529
        }
616
        }
530
        manager = GCLUE_MODEM_MANAGER (g_task_get_source_object (task));
617
531
        priv = manager->priv;
532
        g_debug ("Modem '%s' setup.", mm_object_get_path (priv->mm_object));
618
        g_debug ("Modem '%s' setup.", mm_object_get_path (priv->mm_object));
533
619
620
        /* Make sure that we actually emit that signal */
621
        priv->location_3gpp_ignore_previous = TRUE;
534
        on_location_changed (modem_object, NULL, manager);
622
        on_location_changed (modem_object, NULL, manager);
535
623
536
        g_task_return_boolean (task, TRUE);
624
        g_task_return_boolean (task, TRUE);
Lines 551-558 Link Here
551
        priv->caps |= caps;
639
        priv->caps |= caps;
552
        task = g_task_new (manager, cancellable, callback, user_data);
640
        task = g_task_new (manager, cancellable, callback, user_data);
553
641
554
        priv = GCLUE_MODEM_MANAGER (g_task_get_source_object (task))->priv;
555
556
        caps = mm_modem_location_get_enabled (priv->modem_location) | priv->caps;
642
        caps = mm_modem_location_get_enabled (priv->modem_location) | priv->caps;
557
        mm_modem_location_setup (priv->modem_location,
643
        mm_modem_location_setup (priv->modem_location,
558
                                 caps,
644
                                 caps,
Lines 656-670 Link Here
656
                         GAsyncResult *res,
742
                         GAsyncResult *res,
657
                         gpointer      user_data)
743
                         gpointer      user_data)
658
{
744
{
659
        gboolean ret;
745
        g_autoptr(GError) error = NULL;
660
        GError *error = NULL;
661
746
662
        ret = mm_modem_location_set_gps_refresh_rate_finish
747
        mm_modem_location_set_gps_refresh_rate_finish
663
                (MM_MODEM_LOCATION (source_object), res, &error);
748
                (MM_MODEM_LOCATION (source_object), res, &error);
664
        if (!ret) {
749
        if (error && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
665
                g_warning ("Failed to set GPS refresh rate: %s",
750
                g_warning ("Failed to set GPS refresh rate: %s",
666
                           error->message);
751
                           error->message);
667
                g_error_free (error);
668
        }
752
        }
669
}
753
}
670
754
Lines 736-741 Link Here
736
                return;
820
                return;
737
        g_debug ("Modem '%s' removed.", mm_object_get_path (priv->mm_object));
821
        g_debug ("Modem '%s' removed.", mm_object_get_path (priv->mm_object));
738
822
823
        clear_3gpp_location (manager);
824
739
        g_signal_handlers_disconnect_by_func (G_OBJECT (priv->modem_location),
825
        g_signal_handlers_disconnect_by_func (G_OBJECT (priv->modem_location),
740
                                              G_CALLBACK (on_location_changed),
826
                                              G_CALLBACK (on_location_changed),
741
                                              user_data);
827
                                              user_data);
Lines 753-771 Link Here
753
                      GAsyncResult *res,
839
                      GAsyncResult *res,
754
                      gpointer      user_data)
840
                      gpointer      user_data)
755
{
841
{
756
        GClueModemManagerPrivate *priv = GCLUE_MODEM_MANAGER (user_data)->priv;
842
        MMManager *mmmanager;
843
        GClueModemManager *manager;
844
        GClueModemManagerPrivate *priv;
757
        GList *objects, *node;
845
        GList *objects, *node;
758
        GError *error = NULL;
846
        g_autoptr(GError) error = NULL;
759
847
760
        priv->manager = mm_manager_new_finish (res, &error);
848
        mmmanager = mm_manager_new_finish (res, &error);
761
        if (priv->manager == NULL) {
849
        if (mmmanager == NULL) {
850
                if (error && !g_error_matches (error, G_IO_ERROR,
851
                                               G_IO_ERROR_CANCELLED)) {
762
                g_warning ("Failed to connect to ModemManager: %s",
852
                g_warning ("Failed to connect to ModemManager: %s",
763
                           error->message);
853
                           error->message);
764
                g_error_free (error);
854
                }
765
855
766
                return;
856
                return;
767
        }
857
        }
768
858
859
        manager = GCLUE_MODEM_MANAGER (user_data);
860
        priv = manager->priv;
861
        priv->manager = mmmanager;
862
769
        objects = g_dbus_object_manager_get_objects
863
        objects = g_dbus_object_manager_get_objects
770
                        (G_DBUS_OBJECT_MANAGER (priv->manager));
864
                        (G_DBUS_OBJECT_MANAGER (priv->manager));
771
        for (node = objects; node != NULL; node = node->next) {
865
        for (node = objects; node != NULL; node = node->next) {
Lines 779-793 Link Here
779
        }
873
        }
780
        g_list_free_full (objects, g_object_unref);
874
        g_list_free_full (objects, g_object_unref);
781
875
782
        g_signal_connect (G_OBJECT (priv->manager),
876
        g_signal_connect_object (G_OBJECT (priv->manager),
783
                          "object-added",
877
                          "object-added",
784
                          G_CALLBACK (on_mm_object_added),
878
                          G_CALLBACK (on_mm_object_added),
785
                          user_data);
879
                                 manager, 0);
786
880
787
        g_signal_connect (G_OBJECT (priv->manager),
881
        g_signal_connect_object (G_OBJECT (priv->manager),
788
                          "object-removed",
882
                          "object-removed",
789
                          G_CALLBACK (on_mm_object_removed),
883
                          G_CALLBACK (on_mm_object_removed),
790
                          user_data);
884
                                 manager, 0);
791
}
885
}
792
886
793
static void
887
static void
Lines 795-813 Link Here
795
                  GAsyncResult *res,
889
                  GAsyncResult *res,
796
                  gpointer      user_data)
890
                  gpointer      user_data)
797
{
891
{
798
        GClueModemManagerPrivate *priv = GCLUE_MODEM_MANAGER (user_data)->priv;
892
        GClueModemManagerPrivate *priv;
799
        GDBusConnection *connection;
893
        g_autoptr(GDBusConnection) connection = NULL;
800
        GError *error = NULL;
894
        g_autoptr(GError) error = NULL;
801
895
802
        connection = g_bus_get_finish (res, &error);
896
        connection = g_bus_get_finish (res, &error);
803
        if (connection == NULL) {
897
        if (connection == NULL) {
898
                if (error && !g_error_matches (error, G_IO_ERROR,
899
                                               G_IO_ERROR_CANCELLED)) {
804
                g_warning ("Failed to connect to system D-Bus: %s",
900
                g_warning ("Failed to connect to system D-Bus: %s",
805
                           error->message);
901
                           error->message);
806
                g_error_free (error);
902
                }
807
903
808
                return;
904
                return;
809
        }
905
        }
810
906
907
        priv = GCLUE_MODEM_MANAGER (user_data)->priv;
811
        mm_manager_new (connection,
908
        mm_manager_new (connection,
812
                        0,
909
                        0,
813
                        priv->cancellable,
910
                        priv->cancellable,
Lines 1043-1049 Link Here
1043
        g_return_val_if_fail (gclue_modem_manager_get_is_3g_available (modem), FALSE);
1140
        g_return_val_if_fail (gclue_modem_manager_get_is_3g_available (modem), FALSE);
1044
        manager = GCLUE_MODEM_MANAGER (modem);
1141
        manager = GCLUE_MODEM_MANAGER (modem);
1045
1142
1046
        g_clear_object (&manager->priv->location_3gpp);
1143
        clear_3gpp_location (manager);
1047
        g_debug ("Clearing 3GPP location caps from modem");
1144
        g_debug ("Clearing 3GPP location caps from modem");
1048
        return clear_caps (manager,
1145
        return clear_caps (manager,
1049
                           MM_MODEM_LOCATION_SOURCE_3GPP_LAC_CI,
1146
                           MM_MODEM_LOCATION_SOURCE_3GPP_LAC_CI,
Lines 1062-1068 Link Here
1062
        g_return_val_if_fail (gclue_modem_manager_get_is_cdma_available (modem), FALSE);
1159
        g_return_val_if_fail (gclue_modem_manager_get_is_cdma_available (modem), FALSE);
1063
        manager = GCLUE_MODEM_MANAGER (modem);
1160
        manager = GCLUE_MODEM_MANAGER (modem);
1064
1161
1065
        g_clear_object (&manager->priv->location_3gpp);
1162
        clear_3gpp_location (manager);
1066
        g_debug ("Clearing CDMA location caps from modem");
1163
        g_debug ("Clearing CDMA location caps from modem");
1067
        return clear_caps (manager,
1164
        return clear_caps (manager,
1068
                           MM_MODEM_LOCATION_SOURCE_CDMA_BS,
1165
                           MM_MODEM_LOCATION_SOURCE_CDMA_BS,
(-)geoclue-2.6.0/src/gclue-mozilla.c (-54 / +282 lines)
Lines 25-32 Link Here
25
#include <string.h>
25
#include <string.h>
26
#include <config.h>
26
#include <config.h>
27
#include "gclue-mozilla.h"
27
#include "gclue-mozilla.h"
28
#include "gclue-3g-tower.h"
28
#include "gclue-config.h"
29
#include "gclue-config.h"
29
#include "gclue-error.h"
30
#include "gclue-error.h"
31
#include "gclue-wifi.h"
30
32
31
/**
33
/**
32
 * SECTION:gclue-mozilla
34
 * SECTION:gclue-mozilla
Lines 40-45 Link Here
40
 * its easy to switch to Google's API.
42
 * its easy to switch to Google's API.
41
 **/
43
 **/
42
44
45
struct _GClueMozillaPrivate
46
{
47
        GClueWifi *wifi;
48
49
        GClue3GTower tower;
50
        gboolean tower_valid;
51
        gboolean tower_submitted;
52
53
        gboolean bss_submitted;
54
};
55
56
G_DEFINE_TYPE_WITH_CODE (GClueMozilla,
57
                         gclue_mozilla,
58
                         G_TYPE_OBJECT,
59
                         G_ADD_PRIVATE (GClueMozilla))
60
43
#define BSSID_LEN 6
61
#define BSSID_LEN 6
44
#define BSSID_STR_LEN 17
62
#define BSSID_STR_LEN 17
45
#define MAX_SSID_LEN 32
63
#define MAX_SSID_LEN 32
Lines 102-113 Link Here
102
        return TRUE;
120
        return TRUE;
103
}
121
}
104
122
105
static const char *
123
const char *
106
get_url (void)
124
gclue_mozilla_get_locate_url (GClueMozilla *mozilla)
107
{
125
{
108
        GClueConfig *config;
126
        GClueConfig *config = gclue_config_get_singleton ();
109
110
        config = gclue_config_get_singleton ();
111
127
112
        return gclue_config_get_wifi_url (config);
128
        return gclue_config_get_wifi_url (config);
113
}
129
}
Lines 136-160 Link Here
136
        return FALSE;
152
        return FALSE;
137
}
153
}
138
154
155
static gboolean
156
towertec_to_radiotype (GClueTowerTec tec,
157
                       const char **radiotype_p)
158
{
159
        switch (tec) {
160
        case GCLUE_TOWER_TEC_2G:
161
            *radiotype_p = "gsm";
162
            break;
163
        case GCLUE_TOWER_TEC_3G:
164
            *radiotype_p = "wcdma";
165
            break;
166
        case GCLUE_TOWER_TEC_4G:
167
            *radiotype_p = "lte";
168
            break;
169
        default:
170
            *radiotype_p = NULL;
171
            return FALSE;
172
        }
173
174
        return TRUE;
175
}
176
139
SoupMessage *
177
SoupMessage *
140
gclue_mozilla_create_query (GList        *bss_list, /* As in Access Points */
178
gclue_mozilla_create_query (GClueMozilla  *mozilla,
141
                            GClue3GTower *tower,
179
                            gboolean skip_tower,
180
                            gboolean skip_bss,
181
                            const char **query_data_description,
142
                            GError      **error)
182
                            GError      **error)
143
{
183
{
184
        gboolean has_tower = FALSE, has_bss = FALSE;
144
        SoupMessage *ret = NULL;
185
        SoupMessage *ret = NULL;
145
        JsonBuilder *builder;
186
        JsonBuilder *builder;
187
        g_autoptr(GList) bss_list = NULL;
146
        JsonGenerator *generator;
188
        JsonGenerator *generator;
147
        JsonNode *root_node;
189
        JsonNode *root_node;
148
        char *data;
190
        char *data;
149
        gsize data_len;
191
        gsize data_len;
150
        const char *uri;
192
        const char *uri, *radiotype;
151
        guint n_non_ignored_bsss;
193
        guint n_non_ignored_bsss;
152
        GList *iter;
194
        GList *iter;
153
        gint64 mcc, mnc;
195
        gint64 mcc, mnc;
196
        g_autoptr(GBytes) body = NULL;
154
197
155
        builder = json_builder_new ();
198
        builder = json_builder_new ();
156
        json_builder_begin_object (builder);
199
        json_builder_begin_object (builder);
157
200
201
        if (mozilla->priv->wifi && !skip_bss) {
202
                bss_list = gclue_wifi_get_bss_list (mozilla->priv->wifi);
203
        }
158
        /* We send pure geoip query using empty object if both bss_list and
204
        /* We send pure geoip query using empty object if both bss_list and
159
         * tower are NULL.
205
         * tower are NULL.
160
         *
206
         *
Lines 172-182 Link Here
172
                n_non_ignored_bsss++;
218
                n_non_ignored_bsss++;
173
        }
219
        }
174
220
175
        if (tower != NULL &&
221
        if (mozilla->priv->tower_valid && !skip_tower &&
176
            operator_code_to_mcc_mnc (tower->opc, &mcc, &mnc)) {
222
            towertec_to_radiotype (mozilla->priv->tower.tec, &radiotype) &&
177
223
            operator_code_to_mcc_mnc (mozilla->priv->tower.opc, &mcc, &mnc)) {
178
                json_builder_set_member_name (builder, "radioType");
224
                json_builder_set_member_name (builder, "radioType");
179
                json_builder_add_string_value (builder, "gsm");
225
                json_builder_add_string_value (builder, radiotype);
180
226
181
                json_builder_set_member_name (builder, "cellTowers");
227
                json_builder_set_member_name (builder, "cellTowers");
182
                json_builder_begin_array (builder);
228
                json_builder_begin_array (builder);
Lines 184-204 Link Here
184
                json_builder_begin_object (builder);
230
                json_builder_begin_object (builder);
185
231
186
                json_builder_set_member_name (builder, "cellId");
232
                json_builder_set_member_name (builder, "cellId");
187
                json_builder_add_int_value (builder, tower->cell_id);
233
                json_builder_add_int_value (builder, mozilla->priv->tower.cell_id);
188
                json_builder_set_member_name (builder, "mobileCountryCode");
234
                json_builder_set_member_name (builder, "mobileCountryCode");
189
                json_builder_add_int_value (builder, mcc);
235
                json_builder_add_int_value (builder, mcc);
190
                json_builder_set_member_name (builder, "mobileNetworkCode");
236
                json_builder_set_member_name (builder, "mobileNetworkCode");
191
                json_builder_add_int_value (builder, mnc);
237
                json_builder_add_int_value (builder, mnc);
192
                json_builder_set_member_name (builder, "locationAreaCode");
238
                json_builder_set_member_name (builder, "locationAreaCode");
193
                json_builder_add_int_value (builder, tower->lac);
239
                json_builder_add_int_value (builder, mozilla->priv->tower.lac);
194
                if (tower->tec == GCLUE_TOWER_TEC_4G) {
195
                        json_builder_set_member_name (builder, "radioType");
240
                        json_builder_set_member_name (builder, "radioType");
196
                        json_builder_add_string_value (builder, "lte");
241
                json_builder_add_string_value (builder, radiotype);
197
		}
198
242
199
                json_builder_end_object (builder);
243
                json_builder_end_object (builder);
200
244
201
                json_builder_end_array (builder);
245
                json_builder_end_array (builder);
246
247
                has_tower = TRUE;
202
        }
248
        }
203
249
204
        if (n_non_ignored_bsss >= 2) {
250
        if (n_non_ignored_bsss >= 2) {
Lines 222-227 Link Here
222
                        strength_dbm = wpa_bss_get_signal (bss);
268
                        strength_dbm = wpa_bss_get_signal (bss);
223
                        json_builder_add_int_value (builder, strength_dbm);
269
                        json_builder_add_int_value (builder, strength_dbm);
224
                        json_builder_end_object (builder);
270
                        json_builder_end_object (builder);
271
272
                        has_bss = TRUE;
225
                }
273
                }
226
                json_builder_end_array (builder);
274
                json_builder_end_array (builder);
227
        }
275
        }
Lines 236-250 Link Here
236
        g_object_unref (builder);
284
        g_object_unref (builder);
237
        g_object_unref (generator);
285
        g_object_unref (generator);
238
286
239
        uri = get_url ();
287
        uri = gclue_mozilla_get_locate_url (mozilla);
240
        ret = soup_message_new ("POST", uri);
288
        ret = soup_message_new ("POST", uri);
241
        soup_message_set_request (ret,
289
        body = g_bytes_new_take (data, data_len);
242
                                  "application/json",
290
        soup_message_set_request_body_from_bytes (ret, "application/json", body);
243
                                  SOUP_MEMORY_TAKE,
244
                                  data,
245
                                  data_len);
246
        g_debug ("Sending following request to '%s':\n%s", uri, data);
291
        g_debug ("Sending following request to '%s':\n%s", uri, data);
247
292
293
        if (query_data_description) {
294
                if (has_tower && has_bss) {
295
                        *query_data_description = "3GPP + WiFi";
296
                } else if (has_tower) {
297
                        *query_data_description = "3GPP";
298
                } else if (has_bss) {
299
                        *query_data_description = "WiFi";
300
                } else {
301
                        *query_data_description = "GeoIP";
302
                }
303
        }
304
248
        return ret;
305
        return ret;
249
}
306
}
250
307
Lines 252-279 Link Here
252
parse_server_error (JsonObject *object, GError **error)
309
parse_server_error (JsonObject *object, GError **error)
253
{
310
{
254
        JsonObject *error_obj;
311
        JsonObject *error_obj;
255
        int code;
256
        const char *message;
312
        const char *message;
257
313
258
        if (!json_object_has_member (object, "error"))
314
        if (!json_object_has_member (object, "error"))
259
            return FALSE;
315
            return FALSE;
260
316
261
        error_obj = json_object_get_object_member (object, "error");
317
        error_obj = json_object_get_object_member (object, "error");
262
        code = json_object_get_int_member (error_obj, "code");
318
        if (json_object_has_member (error_obj, "message")) {
263
        message = json_object_get_string_member (error_obj, "message");
319
        message = json_object_get_string_member (error_obj, "message");
320
        } else {
321
                message = "Unknown error";
322
        }
264
323
265
        g_set_error_literal (error, G_IO_ERROR, code, message);
324
        g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, message);
266
325
267
        return TRUE;
326
        return TRUE;
268
}
327
}
269
328
270
GClueLocation *
329
GClueLocation *
271
gclue_mozilla_parse_response (const char *json,
330
gclue_mozilla_parse_response (const char *json,
331
                              const char *location_description,
272
                              GError    **error)
332
                              GError    **error)
273
{
333
{
274
        JsonParser *parser;
334
        g_autoptr(JsonParser) parser = NULL;
275
        JsonNode *node;
335
        JsonNode *node;
276
        JsonObject *object, *loc_object;
336
        JsonObject *object, *loc_object;
337
        g_autofree char *desc_new = NULL;
277
        GClueLocation *location;
338
        GClueLocation *location;
278
        gdouble latitude, longitude, accuracy;
339
        gdouble latitude, longitude, accuracy;
279
340
Lines 288-341 Link Here
288
        if (parse_server_error (object, error))
349
        if (parse_server_error (object, error))
289
                return NULL;
350
                return NULL;
290
351
352
        if (json_object_has_member (object, "fallback")) {
353
                const char *fallback;
354
355
                fallback = json_object_get_string_member (object, "fallback");
356
                if (fallback && strlen (fallback)) {
357
                        desc_new = g_strdup_printf ("%s fallback (from %s data)",
358
                                                    fallback, location_description);
359
                        location_description = desc_new;
360
                }
361
        }
362
291
        loc_object = json_object_get_object_member (object, "location");
363
        loc_object = json_object_get_object_member (object, "location");
292
        latitude = json_object_get_double_member (loc_object, "lat");
364
        latitude = json_object_get_double_member (loc_object, "lat");
293
        longitude = json_object_get_double_member (loc_object, "lng");
365
        longitude = json_object_get_double_member (loc_object, "lng");
294
366
295
        accuracy = json_object_get_double_member (object, "accuracy");
367
        accuracy = json_object_get_double_member (object, "accuracy");
296
368
297
        location = gclue_location_new (latitude, longitude, accuracy);
369
        location = gclue_location_new (latitude, longitude, accuracy,
298
370
                                       location_description);
299
        g_object_unref (parser);
300
371
301
        return location;
372
        return location;
302
}
373
}
303
374
304
static const char *
375
const char *
305
get_submit_config (const char **nick)
376
gclue_mozilla_get_submit_url (GClueMozilla *mozilla)
306
{
377
{
307
        GClueConfig *config;
378
        GClueConfig *config = gclue_config_get_singleton ();
308
309
        config = gclue_config_get_singleton ();
310
        if (!gclue_config_get_wifi_submit_data (config))
311
                return NULL;
312
313
        *nick = gclue_config_get_wifi_submit_nick (config);
314
379
380
        if (gclue_config_get_wifi_submit_data (config))
315
        return gclue_config_get_wifi_submit_url (config);
381
        return gclue_config_get_wifi_submit_url (config);
382
        else
383
                return NULL;
316
}
384
}
317
385
318
SoupMessage *
386
SoupMessage *
319
gclue_mozilla_create_submit_query (GClueLocation   *location,
387
gclue_mozilla_create_submit_query (GClueMozilla  *mozilla,
320
                                   GList           *bss_list, /* As in Access Points */
388
                                   GClueLocation   *location,
321
                                   GClue3GTower    *tower,
322
                                   GError         **error)
389
                                   GError         **error)
323
{
390
{
324
        SoupMessage *ret = NULL;
391
        SoupMessage *ret = NULL;
392
        SoupMessageHeaders *request_headers;
325
        JsonBuilder *builder;
393
        JsonBuilder *builder;
326
        JsonGenerator *generator;
394
        JsonGenerator *generator;
327
        JsonNode *root_node;
395
        JsonNode *root_node;
328
        char *data, *timestr;
396
        char *data, *timestr;
397
        g_autoptr(GList) bss_list = NULL;
329
        const char *url, *nick;
398
        const char *url, *nick;
330
        gsize data_len;
399
        gsize data_len;
331
        GList *iter;
400
        GList *iter;
332
        gdouble lat, lon, accuracy, altitude;
401
        gdouble lat, lon, accuracy, altitude;
333
        GDateTime *datetime;
402
        GDateTime *datetime;
334
        gint64 mcc, mnc;
403
        gint64 mcc, mnc;
404
        GClueConfig *config;
405
        g_autoptr(GBytes) body = NULL;
406
407
        if (mozilla->priv->bss_submitted &&
408
            (!mozilla->priv->tower_valid ||
409
             mozilla->priv->tower_submitted))
410
        {
411
                g_debug ("Already created submit req for this data (bss submitted %d; tower: valid %d submitted %d)",
412
                         (int)mozilla->priv->bss_submitted,
413
                         (int)mozilla->priv->tower_valid,
414
                         (int)mozilla->priv->tower_submitted);
415
                goto out;
416
        }
335
417
336
        url = get_submit_config (&nick);
418
419
        url = gclue_mozilla_get_submit_url (mozilla);
337
        if (url == NULL)
420
        if (url == NULL)
338
                goto out;
421
                goto out;
422
        config = gclue_config_get_singleton ();
423
        nick = gclue_config_get_wifi_submit_nick (config);
339
424
340
        builder = json_builder_new ();
425
        builder = json_builder_new ();
341
        json_builder_begin_object (builder);
426
        json_builder_begin_object (builder);
Lines 379-384 Link Here
379
        json_builder_set_member_name (builder, "radioType");
464
        json_builder_set_member_name (builder, "radioType");
380
        json_builder_add_string_value (builder, "gsm");
465
        json_builder_add_string_value (builder, "gsm");
381
466
467
        if (mozilla->priv->wifi) {
468
                bss_list = gclue_wifi_get_bss_list (mozilla->priv->wifi);
469
        }
382
        if (bss_list != NULL) {
470
        if (bss_list != NULL) {
383
                json_builder_set_member_name (builder, "wifi");
471
                json_builder_set_member_name (builder, "wifi");
384
                json_builder_begin_array (builder);
472
                json_builder_begin_array (builder);
Lines 410-433 Link Here
410
                json_builder_end_array (builder); /* wifi */
498
                json_builder_end_array (builder); /* wifi */
411
        }
499
        }
412
500
413
        if (tower != NULL &&
501
        if (mozilla->priv->tower_valid &&
414
            operator_code_to_mcc_mnc (tower->opc, &mcc, &mnc)) {
502
            operator_code_to_mcc_mnc (mozilla->priv->tower.opc, &mcc, &mnc)) {
415
416
                json_builder_set_member_name (builder, "cell");
503
                json_builder_set_member_name (builder, "cell");
417
                json_builder_begin_array (builder);
504
                json_builder_begin_array (builder);
418
505
419
                json_builder_begin_object (builder);
506
                json_builder_begin_object (builder);
420
507
508
                if (mozilla->priv->tower.tec == GCLUE_TOWER_TEC_4G) {
509
                        json_builder_set_member_name (builder, "radio");
510
                        json_builder_add_string_value (builder, "lte");
511
                } else if (mozilla->priv->tower.tec == GCLUE_TOWER_TEC_3G) {
512
                        json_builder_set_member_name (builder, "radio");
513
                        json_builder_add_string_value (builder, "umts");
514
                } else if (mozilla->priv->tower.tec == GCLUE_TOWER_TEC_2G) {
421
                json_builder_set_member_name (builder, "radio");
515
                json_builder_set_member_name (builder, "radio");
422
                json_builder_add_string_value (builder, "gsm");
516
                json_builder_add_string_value (builder, "gsm");
517
                }
518
423
                json_builder_set_member_name (builder, "cid");
519
                json_builder_set_member_name (builder, "cid");
424
                json_builder_add_int_value (builder, tower->cell_id);
520
                json_builder_add_int_value (builder, mozilla->priv->tower.cell_id);
425
                json_builder_set_member_name (builder, "mcc");
521
                json_builder_set_member_name (builder, "mcc");
426
                json_builder_add_int_value (builder, mcc);
522
                json_builder_add_int_value (builder, mcc);
427
                json_builder_set_member_name (builder, "mnc");
523
                json_builder_set_member_name (builder, "mnc");
428
                json_builder_add_int_value (builder, mnc);
524
                json_builder_add_int_value (builder, mnc);
429
                json_builder_set_member_name (builder, "lac");
525
                json_builder_set_member_name (builder, "lac");
430
                json_builder_add_int_value (builder, tower->lac);
526
                json_builder_add_int_value (builder, mozilla->priv->tower.lac);
431
527
432
                json_builder_end_object (builder);
528
                json_builder_end_object (builder);
433
529
Lines 448-464 Link Here
448
        g_object_unref (generator);
544
        g_object_unref (generator);
449
545
450
        ret = soup_message_new ("POST", url);
546
        ret = soup_message_new ("POST", url);
547
        request_headers = soup_message_get_request_headers (ret);
451
        if (nick != NULL && nick[0] != '\0')
548
        if (nick != NULL && nick[0] != '\0')
452
                soup_message_headers_append (ret->request_headers,
549
                soup_message_headers_append (request_headers,
453
                                             "X-Nickname",
550
                                             "X-Nickname",
454
                                             nick);
551
                                             nick);
455
        soup_message_set_request (ret,
552
        body = g_bytes_new_take (data, data_len);
456
                                  "application/json",
553
        soup_message_set_request_body_from_bytes (ret, "application/json", body);
457
                                  SOUP_MEMORY_TAKE,
458
                                  data,
459
                                  data_len);
460
        g_debug ("Sending following request to '%s':\n%s", url, data);
554
        g_debug ("Sending following request to '%s':\n%s", url, data);
461
555
556
        mozilla->priv->bss_submitted = TRUE;
557
        mozilla->priv->tower_submitted = TRUE;
558
462
out:
559
out:
463
        return ret;
560
        return ret;
464
}
561
}
Lines 485-487 Link Here
485
582
486
        return FALSE;
583
        return FALSE;
487
}
584
}
585
586
static void
587
gclue_mozilla_finalize (GObject *object)
588
{
589
        GClueMozilla *mozilla = GCLUE_MOZILLA (object);
590
591
        g_clear_weak_pointer (&mozilla->priv->wifi);
592
593
        G_OBJECT_CLASS (gclue_mozilla_parent_class)->finalize (object);
594
}
595
596
static void
597
gclue_mozilla_init (GClueMozilla *mozilla)
598
{
599
        mozilla->priv = gclue_mozilla_get_instance_private (mozilla);
600
        mozilla->priv->wifi = NULL;
601
        mozilla->priv->tower_valid = FALSE;
602
        mozilla->priv->bss_submitted = FALSE;
603
}
604
605
static void
606
gclue_mozilla_class_init (GClueMozillaClass *klass)
607
{
608
        GObjectClass *object_class = G_OBJECT_CLASS (klass);
609
610
        object_class->finalize = gclue_mozilla_finalize;
611
}
612
613
GClueMozilla *
614
gclue_mozilla_get_singleton (void)
615
{
616
        static GClueMozilla *mozilla = NULL;
617
618
        if (!mozilla) {
619
                mozilla = g_object_new (GCLUE_TYPE_MOZILLA, NULL);
620
                g_object_add_weak_pointer (G_OBJECT (mozilla), (gpointer) &mozilla);
621
        } else
622
                g_object_ref (mozilla);
623
624
        return mozilla;
625
}
626
627
void
628
gclue_mozilla_set_wifi (GClueMozilla *mozilla,
629
                        GClueWifi *wifi)
630
{
631
        g_return_if_fail (GCLUE_IS_MOZILLA (mozilla));
632
633
        if (mozilla->priv->wifi == wifi)
634
                return;
635
636
        g_clear_weak_pointer (&mozilla->priv->wifi);
637
638
        if (!wifi) {
639
                return;
640
        }
641
642
        mozilla->priv->wifi = wifi;
643
        g_object_add_weak_pointer (G_OBJECT (mozilla->priv->wifi),
644
                                   (gpointer) &mozilla->priv->wifi);
645
}
646
647
gboolean
648
gclue_mozilla_test_set_wifi (GClueMozilla *mozilla,
649
                             GClueWifi *old, GClueWifi *new)
650
{
651
        if (mozilla->priv->wifi != old)
652
                return FALSE;
653
654
        gclue_mozilla_set_wifi (mozilla, new);
655
        return TRUE;
656
}
657
658
void
659
gclue_mozilla_set_bss_dirty (GClueMozilla *mozilla)
660
{
661
        g_return_if_fail (GCLUE_IS_MOZILLA (mozilla));
662
663
        mozilla->priv->bss_submitted = FALSE;
664
}
665
666
static gboolean gclue_mozilla_tower_identical (const GClue3GTower *t1,
667
                                               const GClue3GTower *t2)
668
{
669
        return g_strcmp0 (t1->opc, t2->opc) == 0 && t1->lac == t2->lac &&
670
                t1->cell_id == t2->cell_id && t1->tec == t2->tec;
671
}
672
673
void
674
gclue_mozilla_set_tower (GClueMozilla *mozilla,
675
                         const GClue3GTower *tower)
676
{
677
        g_return_if_fail (GCLUE_IS_MOZILLA (mozilla));
678
679
        if (!tower ||
680
            !(tower->tec > GCLUE_TOWER_TEC_UNKNOWN
681
              && tower->tec <= GCLUE_TOWER_TEC_MAX_VALID)) {
682
                mozilla->priv->tower_valid = FALSE;
683
                return;
684
        }
685
686
        if (mozilla->priv->tower_valid &&
687
            mozilla->priv->tower_submitted) {
688
                mozilla->priv->tower_submitted =
689
                        gclue_mozilla_tower_identical (&mozilla->priv->tower,
690
                                                       tower);
691
        } else
692
                mozilla->priv->tower_submitted = FALSE;
693
694
        mozilla->priv->tower = *tower;
695
        mozilla->priv->tower_valid = TRUE;
696
}
697
698
gboolean
699
gclue_mozilla_has_tower (GClueMozilla *mozilla)
700
{
701
        g_return_val_if_fail (GCLUE_IS_MOZILLA (mozilla), FALSE);
702
703
        return mozilla->priv->tower_valid;
704
}
705
706
GClue3GTower *
707
gclue_mozilla_get_tower (GClueMozilla *mozilla)
708
{
709
        g_return_val_if_fail (GCLUE_IS_MOZILLA (mozilla), NULL);
710
711
        if (!mozilla->priv->tower_valid)
712
                return NULL;
713
714
        return &mozilla->priv->tower;
715
}
(-)geoclue-2.6.0/src/gclue-mozilla.h (-5 / +56 lines)
Lines 30-50 Link Here
30
30
31
G_BEGIN_DECLS
31
G_BEGIN_DECLS
32
32
33
#define GCLUE_TYPE_MOZILLA            (gclue_mozilla_get_type())
34
#define GCLUE_MOZILLA(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCLUE_TYPE_MOZILLA, GClueMozilla))
35
#define GCLUE_MOZILLA_CONST(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCLUE_TYPE_MOZILLA, GClueMozilla const))
36
#define GCLUE_MOZILLA_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  GCLUE_TYPE_MOZILLA, GClueMozillaClass))
37
#define GCLUE_IS_MOZILLA(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCLUE_TYPE_MOZILLA))
38
#define GCLUE_IS_MOZILLA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  GCLUE_TYPE_MOZILLA))
39
#define GCLUE_MOZILLA_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  GCLUE_TYPE_MOZILLA, GClueMozillaClass))
40
41
typedef struct _GClueMozilla        GClueMozilla;
42
typedef struct _GClueMozillaClass   GClueMozillaClass;
43
typedef struct _GClueMozillaPrivate GClueMozillaPrivate;
44
45
struct _GClueMozilla
46
{
47
        GObject parent;
48
49
        /*< private >*/
50
        GClueMozillaPrivate *priv;
51
};
52
53
struct _GClueMozillaClass
54
{
55
        GObjectClass parent_class;
56
};
57
58
struct GClueWifi;
59
typedef struct _GClueWifi GClueWifi;
60
61
GType gclue_mozilla_get_type (void) G_GNUC_CONST;
62
63
GClueMozilla *gclue_mozilla_get_singleton (void);
64
65
void gclue_mozilla_set_wifi (GClueMozilla *mozilla,
66
                             GClueWifi *wifi);
67
gboolean
68
gclue_mozilla_test_set_wifi (GClueMozilla *mozilla,
69
                             GClueWifi *old, GClueWifi *new);
70
void gclue_mozilla_set_bss_dirty (GClueMozilla *mozilla);
71
72
void gclue_mozilla_set_tower (GClueMozilla *mozilla,
73
                              const GClue3GTower *tower);
74
gboolean
75
gclue_mozilla_has_tower (GClueMozilla *mozilla);
76
GClue3GTower *
77
gclue_mozilla_get_tower (GClueMozilla *mozilla);
78
33
SoupMessage *
79
SoupMessage *
34
gclue_mozilla_create_query (GList        *bss_list, /* As in Access Points */
80
gclue_mozilla_create_query (GClueMozilla  *mozilla,
35
                            GClue3GTower *tower,
81
                            gboolean skip_tower,
82
                            gboolean skip_bss,
83
                            const char **query_data_description,
36
                            GError      **error);
84
                            GError      **error);
37
GClueLocation *
85
GClueLocation *
38
gclue_mozilla_parse_response (const char *json,
86
gclue_mozilla_parse_response (const char *json,
87
                              const char *location_description,
39
                              GError    **error);
88
                              GError    **error);
40
SoupMessage *
89
SoupMessage *
41
gclue_mozilla_create_submit_query (GClueLocation   *location,
90
gclue_mozilla_create_submit_query (GClueMozilla  *mozilla,
42
                                   GList           *bss_list, /* As in Access Points */
91
                                   GClueLocation   *location,
43
                                   GClue3GTower    *tower,
44
                                   GError         **error);
92
                                   GError         **error);
45
gboolean
93
gboolean
46
gclue_mozilla_should_ignore_bss (WPABSS *bss);
94
gclue_mozilla_should_ignore_bss (WPABSS *bss);
47
95
96
const char *gclue_mozilla_get_locate_url (GClueMozilla *mozilla);
97
const char *gclue_mozilla_get_submit_url (GClueMozilla *mozilla);
98
48
G_END_DECLS
99
G_END_DECLS
49
100
50
#endif /* GCLUE_MOZILLA_H */
101
#endif /* GCLUE_MOZILLA_H */
(-)geoclue-2.6.0/src/gclue-nmea-source.c (-158 / +485 lines)
Lines 22-32 Link Here
22
 */
22
 */
23
23
24
#include <stdlib.h>
24
#include <stdlib.h>
25
#include <string.h>
25
#include <glib.h>
26
#include <glib.h>
26
#include "gclue-config.h"
27
#include "gclue-config.h"
28
#include "gclue-location.h"
27
#include "gclue-nmea-utils.h"
29
#include "gclue-nmea-utils.h"
28
#include "gclue-nmea-source.h"
30
#include "gclue-nmea-source.h"
29
#include "gclue-location.h"
31
#include "gclue-utils.h"
30
#include "config.h"
32
#include "config.h"
31
#include "gclue-enum-types.h"
33
#include "gclue-enum-types.h"
32
34
Lines 37-57 Link Here
37
#include <avahi-glib/glib-watch.h>
39
#include <avahi-glib/glib-watch.h>
38
#include <gio/gunixsocketaddress.h>
40
#include <gio/gunixsocketaddress.h>
39
41
42
/* Once we run out of NMEA services to try how long to wait
43
 * until retrying all of them.
44
 * In seconds.
45
 */
46
#define SERVICE_UNBREAK_TIME 5
47
40
typedef struct AvahiServiceInfo AvahiServiceInfo;
48
typedef struct AvahiServiceInfo AvahiServiceInfo;
41
49
42
struct _GClueNMEASourcePrivate {
50
struct _GClueNMEASourcePrivate {
43
        GSocketConnection *connection;
51
        GSocketConnection *connection;
52
        GDataInputStream *input_stream;
44
53
45
        GSocketClient *client;
54
        GSocketClient *client;
46
55
47
        GCancellable *cancellable;
56
        GCancellable *cancellable;
48
57
58
        AvahiGLibPoll *glib_poll;
59
49
        AvahiClient *avahi_client;
60
        AvahiClient *avahi_client;
50
61
51
        AvahiServiceInfo *active_service;
62
        AvahiServiceInfo *active_service;
52
63
53
        /* List of all services but only the most accurate one is used. */
64
        /* List of services to try but only the most accurate one is used. */
54
        GList *all_services;
65
        GList *try_services;
66
67
        /* List of known-broken services. */
68
        GList *broken_services;
69
70
        guint accuracy_refresh_source, unbreak_timer;
55
};
71
};
56
72
57
G_DEFINE_TYPE_WITH_CODE (GClueNMEASource,
73
G_DEFINE_TYPE_WITH_CODE (GClueNMEASource,
Lines 65-80 Link Here
65
gclue_nmea_source_stop (GClueLocationSource *source);
81
gclue_nmea_source_stop (GClueLocationSource *source);
66
82
67
static void
83
static void
68
connect_to_service (GClueNMEASource *source);
84
try_connect_to_service (GClueNMEASource *source);
69
static void
70
disconnect_from_service (GClueNMEASource *source);
71
85
72
struct AvahiServiceInfo {
86
struct AvahiServiceInfo {
73
    char *identifier;
87
    char *identifier;
74
    char *host_name;
88
    char *host_name;
89
    gboolean is_socket;
75
    guint16 port;
90
    guint16 port;
76
    GClueAccuracyLevel accuracy;
91
    GClueAccuracyLevel accuracy;
77
    guint64 timestamp;
92
    gint64 timestamp_add;
78
};
93
};
79
94
80
static void
95
static void
Lines 99-105 Link Here
99
        service->host_name = g_strdup (host_name);
114
        service->host_name = g_strdup (host_name);
100
        service->port = port;
115
        service->port = port;
101
        service->accuracy = accuracy;
116
        service->accuracy = accuracy;
102
        service->timestamp = g_get_real_time () / G_USEC_PER_SEC;
117
        service->timestamp_add = g_get_monotonic_time ();
103
118
104
        return service;
119
        return service;
105
}
120
}
Lines 122-137 Link Here
122
{
137
{
123
        AvahiServiceInfo *first, *second;
138
        AvahiServiceInfo *first, *second;
124
        gint diff;
139
        gint diff;
140
        gint64 tdiff;
125
141
126
        first = (AvahiServiceInfo *) a;
142
        first = (AvahiServiceInfo *) a;
127
        second = (AvahiServiceInfo *) b;
143
        second = (AvahiServiceInfo *) b;
128
144
129
        diff = second->accuracy - first->accuracy;
145
        diff = second->accuracy - first->accuracy;
146
        if (diff)
147
                return diff;
130
148
131
        if (diff == 0)
149
        g_assert (first->timestamp_add >= 0);
132
                return first->timestamp - second->timestamp;
150
        g_assert (second->timestamp_add >= 0);
151
        tdiff = first->timestamp_add - second->timestamp_add;
152
        if (tdiff < 0)
153
                return -1;
154
        else if (tdiff > 0)
155
                return 1;
156
        else
157
                return 0;
158
}
133
159
134
        return diff;
160
static void
161
disconnect_from_service (GClueNMEASource *source)
162
{
163
        GClueNMEASourcePrivate *priv = source->priv;
164
165
        if (!priv->active_service)
166
                return;
167
168
        g_cancellable_cancel (priv->cancellable);
169
170
        g_clear_object (&priv->input_stream);
171
        g_clear_object (&priv->connection);
172
        g_clear_object (&priv->client);
173
        g_clear_object (&priv->cancellable);
174
        priv->active_service = NULL;
135
}
175
}
136
176
137
static gboolean
177
static gboolean
Lines 145-153 Link Here
145
         * 2. a more accurate service than one currently in use, is now
185
         * 2. a more accurate service than one currently in use, is now
146
         *    available.
186
         *    available.
147
         */
187
         */
148
        return (priv->active_service != NULL &&
188
        return priv->active_service == NULL ||
149
                (priv->all_services == NULL ||
189
                priv->try_services == NULL ||
150
                 priv->active_service != priv->all_services->data));
190
                priv->active_service != priv->try_services->data;
151
}
191
}
152
192
153
static void
193
static void
Lines 157-181 Link Here
157
                return;
197
                return;
158
198
159
        disconnect_from_service (source);
199
        disconnect_from_service (source);
160
        connect_to_service (source);
200
        try_connect_to_service (source);
161
}
201
}
162
202
163
static void
203
static GClueAccuracyLevel get_head_accuracy (GList *list)
164
refresh_accuracy_level (GClueNMEASource *source)
204
{
205
        AvahiServiceInfo *service;
206
207
        if (!list)
208
                return GCLUE_ACCURACY_LEVEL_NONE;
209
210
        service = (AvahiServiceInfo *) list->data;
211
        return service->accuracy;
212
}
213
214
static gboolean
215
on_refresh_accuracy_level (gpointer user_data)
165
{
216
{
166
        GClueAccuracyLevel new, existing;
217
        GClueNMEASource *source = GCLUE_NMEA_SOURCE (user_data);
218
        GClueNMEASourcePrivate *priv = source->priv;
219
        GClueAccuracyLevel new_try, new_broken, new, existing;
220
221
        priv->accuracy_refresh_source = 0;
167
222
168
        existing = gclue_location_source_get_available_accuracy_level
223
        existing = gclue_location_source_get_available_accuracy_level
169
                        (GCLUE_LOCATION_SOURCE (source));
224
                        (GCLUE_LOCATION_SOURCE (source));
170
225
171
        if (source->priv->all_services != NULL) {
226
        new_try = get_head_accuracy (priv->try_services);
172
                AvahiServiceInfo *service;
227
        new_broken = get_head_accuracy (priv->broken_services);
173
228
        new = MAX (new_try, new_broken);
174
                service = (AvahiServiceInfo *) source->priv->all_services->data;
175
                new = service->accuracy;
176
        } else {
177
                new = GCLUE_ACCURACY_LEVEL_NONE;
178
        }
179
229
180
        if (new != existing) {
230
        if (new != existing) {
181
                g_debug ("Available accuracy level from %s: %u",
231
                g_debug ("Available accuracy level from %s: %u",
Lines 184-189 Link Here
184
                              "available-accuracy-level", new,
234
                              "available-accuracy-level", new,
185
                              NULL);
235
                              NULL);
186
        }
236
        }
237
238
        return G_SOURCE_REMOVE;
239
}
240
241
static void
242
refresh_accuracy_level (GClueNMEASource *source)
243
{
244
        GClueNMEASourcePrivate *priv = source->priv;
245
246
        if (priv->accuracy_refresh_source) {
247
                return;
248
        }
249
250
        g_debug ("Scheduling NMEA accuracy level refresh");
251
        priv->accuracy_refresh_source = g_idle_add (on_refresh_accuracy_level,
252
                                                    source);
253
}
254
255
static gboolean
256
on_service_unbreak_time (gpointer source)
257
{
258
        GClueNMEASourcePrivate *priv = GCLUE_NMEA_SOURCE (source)->priv;
259
260
        priv->unbreak_timer = 0;
261
262
        if (!priv->try_services && priv->broken_services) {
263
                g_debug ("Unbreaking existing NMEA services");
264
265
                priv->try_services = priv->broken_services;
266
                priv->broken_services = NULL;
267
268
                reconnect_service (source);
269
        }
270
271
        return G_SOURCE_REMOVE;
272
}
273
274
static void
275
check_unbreak_timer (GClueNMEASource *source)
276
{
277
        GClueNMEASourcePrivate *priv = source->priv;
278
279
        if (priv->try_services || !priv->broken_services) {
280
                if (priv->unbreak_timer) {
281
                        g_debug ("Removing unnecessary NMEA unbreaking timer");
282
283
                        g_source_remove (priv->unbreak_timer);
284
                        priv->unbreak_timer = 0;
285
                }
286
287
                return;
288
        }
289
290
        if (priv->unbreak_timer) {
291
                return;
292
        }
293
294
        g_debug ("Scheduling NMEA unbreaking timer");
295
        priv->unbreak_timer = g_timeout_add_seconds (SERVICE_UNBREAK_TIME,
296
                                                     on_service_unbreak_time,
297
                                                     source);
298
}
299
300
static void
301
service_lists_changed (GClueNMEASource *source)
302
{
303
        check_unbreak_timer (source);
304
        reconnect_service (source);
305
        refresh_accuracy_level (source);
306
}
307
308
static gboolean
309
check_service_exists (GClueNMEASource *source,
310
                      const char *name)
311
{
312
        GClueNMEASourcePrivate *priv = source->priv;
313
        AvahiServiceInfo *service;
314
        GList *item;
315
        gboolean ret = FALSE;
316
317
        /* only `name` is required here */
318
        service = avahi_service_new (name,
319
                                     NULL,
320
                                     0,
321
                                     GCLUE_ACCURACY_LEVEL_NONE);
322
323
        item = g_list_find_custom (priv->try_services,
324
                                   service,
325
                                   compare_avahi_service_by_identifier);
326
        if (item) {
327
                ret = TRUE;
328
        } else {
329
                item = g_list_find_custom (priv->broken_services,
330
                                           service,
331
                                           compare_avahi_service_by_identifier);
332
                if (item) {
333
                        ret = TRUE;
334
                }
335
        }
336
337
        g_clear_pointer (&service, avahi_service_free);
338
339
        return ret;
187
}
340
}
188
341
189
static void
342
static void
Lines 191-196 Link Here
191
                 const char *name,
344
                 const char *name,
192
                 const char *host_name,
345
                 const char *host_name,
193
                 uint16_t port,
346
                 uint16_t port,
347
                 gboolean is_socket,
194
                 AvahiStringList *txt)
348
                 AvahiStringList *txt)
195
{
349
{
196
        GClueAccuracyLevel accuracy = GCLUE_ACCURACY_LEVEL_NONE;
350
        GClueAccuracyLevel accuracy = GCLUE_ACCURACY_LEVEL_NONE;
Lines 201-207 Link Here
201
        GEnumClass *enum_class;
355
        GEnumClass *enum_class;
202
        GEnumValue *enum_value;
356
        GEnumValue *enum_value;
203
357
204
        if (port == 0) {
358
        if (check_service_exists (source, name)) {
359
                g_debug ("NMEA service %s already exists", name);
360
                return;
361
        }
362
363
        if (!txt) {
205
	        accuracy = GCLUE_ACCURACY_LEVEL_EXACT;
364
	        accuracy = GCLUE_ACCURACY_LEVEL_EXACT;
206
365
207
	        goto CREATE_SERVICE;
366
	        goto CREATE_SERVICE;
Lines 242-284 Link Here
242
401
243
CREATE_SERVICE:
402
CREATE_SERVICE:
244
        service = avahi_service_new (name, host_name, port, accuracy);
403
        service = avahi_service_new (name, host_name, port, accuracy);
404
        service->is_socket = is_socket;
245
405
246
        source->priv->all_services = g_list_insert_sorted
406
        source->priv->try_services = g_list_insert_sorted
247
                (source->priv->all_services,
407
                (source->priv->try_services,
248
                 service,
408
                 service,
249
                 compare_avahi_service_by_accuracy_n_time);
409
                 compare_avahi_service_by_accuracy_n_time);
250
410
251
        refresh_accuracy_level (source);
411
        n_services = g_list_length (source->priv->try_services);
252
        reconnect_service (source);
412
        g_debug ("No. of _nmea-0183._tcp services %u", n_services);
253
413
254
        n_services = g_list_length (source->priv->all_services);
414
        service_lists_changed (source);
415
}
255
416
256
        g_debug ("No. of _nmea-0183._tcp services %u", n_services);
417
static void
418
add_new_service_avahi (GClueNMEASource *source,
419
                       const char *name,
420
                       const char *host_name,
421
                       uint16_t port,
422
                       AvahiStringList *txt)
423
{
424
        add_new_service (source, name, host_name, port, FALSE, txt);
257
}
425
}
258
426
259
static void
427
static void
260
remove_service (GClueNMEASource *source,
428
add_new_service_socket (GClueNMEASource *source,
261
                AvahiServiceInfo *service)
429
                       const char *name,
430
                       const char *socket_path)
262
{
431
{
263
        guint n_services = 0;
432
        add_new_service (source, name, socket_path, 0, TRUE, NULL);
433
}
264
434
265
        avahi_service_free (service);
435
static void
266
        source->priv->all_services = g_list_remove
436
service_broken (GClueNMEASource *source)
267
                (source->priv->all_services, service);
437
{
438
        GClueNMEASourcePrivate *priv = source->priv;
439
        AvahiServiceInfo *service = priv->active_service;
268
440
269
        n_services = g_list_length (source->priv->all_services);
441
        g_assert (service);
270
442
271
        g_debug ("No. of _nmea-0183._tcp services %u",
443
        disconnect_from_service (source);
272
                 n_services);
273
444
274
        refresh_accuracy_level (source);
445
        priv->try_services = g_list_remove (priv->try_services,
275
        reconnect_service (source);
446
                                            service);
447
        priv->broken_services = g_list_insert_sorted
448
                (priv->broken_services,
449
                 service,
450
                compare_avahi_service_by_accuracy_n_time);
451
452
        service_lists_changed (source);
453
}
454
455
static void
456
remove_service_from_list (GList **list,
457
                          GList *item)
458
{
459
        AvahiServiceInfo *service = item->data;
460
461
        *list = g_list_delete_link (*list, item);
462
        avahi_service_free (service);
276
}
463
}
277
464
278
static void
465
static void
279
remove_service_by_name (GClueNMEASource *source,
466
remove_service_by_name (GClueNMEASource *source,
280
                        const char      *name)
467
                        const char      *name)
281
{
468
{
469
        GClueNMEASourcePrivate *priv = source->priv;
282
        AvahiServiceInfo *service;
470
        AvahiServiceInfo *service;
283
        GList *item;
471
        GList *item;
284
472
Lines 288-302 Link Here
288
                                     0,
476
                                     0,
289
                                     GCLUE_ACCURACY_LEVEL_NONE);
477
                                     GCLUE_ACCURACY_LEVEL_NONE);
290
478
291
        item = g_list_find_custom (source->priv->all_services,
479
        item = g_list_find_custom (priv->try_services,
292
                                   service,
480
                                   service,
293
                                   compare_avahi_service_by_identifier);
481
                                   compare_avahi_service_by_identifier);
294
        avahi_service_free (service);
482
        if (item) {
483
                if (item->data == priv->active_service) {
484
                        g_debug ("Active NMEA service removed, disconnecting.");
485
                        disconnect_from_service (source);
486
                }
295
487
296
        if (item == NULL)
488
                remove_service_from_list (&priv->try_services,
297
                return;
489
                                          item);
490
        } else {
491
                item = g_list_find_custom (priv->broken_services,
492
                                           service,
493
                                           compare_avahi_service_by_identifier);
494
                if (item) {
495
                        g_assert (item->data != priv->active_service);
496
                        remove_service_from_list (&priv->broken_services,
497
                                                  item);
498
                }
499
        }
500
501
        g_clear_pointer (&service, avahi_service_free);
298
502
299
        remove_service (source, item->data);
503
        service_lists_changed (source);
300
}
504
}
301
505
302
static void
506
static void
Lines 337-347 Link Here
337
        }
541
        }
338
542
339
        case AVAHI_RESOLVER_FOUND:
543
        case AVAHI_RESOLVER_FOUND:
340
                g_debug ("Service %s:%u resolved",
544
                g_debug ("Service '%s' of type '%s' in domain '%s' resolved to %s:%u",
545
                         name,
546
                         type,
547
                         domain,
341
                         host_name,
548
                         host_name,
342
                         port);
549
                         (unsigned int)port);
343
550
344
                add_new_service (GCLUE_NMEA_SOURCE (user_data),
551
                add_new_service_avahi (GCLUE_NMEA_SOURCE (user_data),
345
                                 name,
552
                                 name,
346
                                 host_name,
553
                                 host_name,
347
                                 port,
554
                                 port,
Lines 358-369 Link Here
358
                 AvahiClientState state,
565
                 AvahiClientState state,
359
                 void            *user_data)
566
                 void            *user_data)
360
{
567
{
361
        GClueNMEASourcePrivate *priv = GCLUE_NMEA_SOURCE (user_data)->priv;
362
363
        g_return_if_fail (avahi_client != NULL);
568
        g_return_if_fail (avahi_client != NULL);
364
569
365
        priv->avahi_client = avahi_client;
366
367
        if (state == AVAHI_CLIENT_FAILURE) {
570
        if (state == AVAHI_CLIENT_FAILURE) {
368
                const char *errorstr = avahi_strerror
571
                const char *errorstr = avahi_strerror
369
                        (avahi_client_errno (avahi_client));
572
                        (avahi_client_errno (avahi_client));
Lines 448-499 Link Here
448
        }
651
        }
449
}
652
}
450
653
654
#define NMEA_LINE_END "\r\n"
655
#define NMEA_LINE_END_CTR (sizeof (NMEA_LINE_END) - 1)
656
657
static void nmea_skip_delim (GBufferedInputStream *stream,
658
                             GCancellable *cancellable)
659
{
660
        const char *buf;
661
        gsize buf_size;
662
        size_t delim_skip;
663
        g_autoptr(GError) error = NULL;
664
665
        buf = (const char *) g_buffered_input_stream_peek_buffer (stream,
666
                                                                  &buf_size);
667
668
        delim_skip = strnspn (buf, NMEA_LINE_END, buf_size);
669
        for (size_t ctr = 0; ctr < delim_skip; ctr++) {
670
                if (g_buffered_input_stream_read_byte (stream, cancellable, &error) < 0) {
671
                        if (error && !g_error_matches (error, G_IO_ERROR,
672
                                                       G_IO_ERROR_CANCELLED)) {
673
                                g_warning ("Failed to skip %zu / %zu NMEA delimiter: %s",
674
                                           ctr, delim_skip, error->message);
675
                        }
676
                        break;
677
                }
678
        }
679
}
680
681
static gboolean nmea_check_delim (GBufferedInputStream *stream)
682
{
683
        const char *buf;
684
        gsize buf_size;
685
686
        buf = (const char *) g_buffered_input_stream_peek_buffer (stream,
687
                                                                  &buf_size);
688
689
        return strnpbrk (buf, NMEA_LINE_END, buf_size) != NULL;
690
}
691
451
#define NMEA_STR_LEN 128
692
#define NMEA_STR_LEN 128
452
static void
693
static void
453
on_read_nmea_sentence (GObject      *object,
694
on_read_nmea_sentence (GObject      *object,
454
                       GAsyncResult *result,
695
                       GAsyncResult *result,
455
                       gpointer      user_data)
696
                       gpointer      user_data)
456
{
697
{
457
        GClueNMEASource *source = GCLUE_NMEA_SOURCE (user_data);
698
        GClueNMEASource *source = NULL;
458
        GDataInputStream *data_input_stream = G_DATA_INPUT_STREAM (object);
699
        GDataInputStream *data_input_stream = G_DATA_INPUT_STREAM (object);
459
        GError *error = NULL;
700
        g_autoptr(GError) error = NULL;
460
        GClueLocation *prev_location;
701
        GClueLocation *prev_location;
461
        g_autoptr(GClueLocation) location = NULL;
702
        g_autoptr(GClueLocation) location = NULL;
462
        gsize data_size = 0 ;
703
        gsize data_size = 0 ;
463
        char *message;
704
        g_autofree char *message = NULL;
464
        gint i;
705
        gint i;
465
        static const gchar *sentences[3] = { 0 };
706
        const gchar *sentences[3];
466
        static gchar gga[NMEA_STR_LEN] = { 0 };
707
        gchar gga[NMEA_STR_LEN];
467
        static gchar rmc[NMEA_STR_LEN] = { 0 };
708
        gchar rmc[NMEA_STR_LEN];
468
709
469
710
        message = g_data_input_stream_read_upto_finish (data_input_stream,
470
        message = g_data_input_stream_read_line_finish (data_input_stream,
471
                                                        result,
711
                                                        result,
472
                                                        &data_size,
712
                                                        &data_size,
473
                                                        &error);
713
                                                        &error);
474
714
715
        gga[0] = '\0';
716
        rmc[0] = '\0';
717
475
        do {
718
        do {
719
                if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
720
                        return;
721
722
                if (!source)
723
                        source = GCLUE_NMEA_SOURCE (user_data);
724
476
                if (message == NULL) {
725
                if (message == NULL) {
477
                        if (error != NULL) {
726
                        if (error != NULL) {
478
                                if (error->code == G_IO_ERROR_CLOSED)
727
                                if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CLOSED)) {
479
                                        g_debug ("Socket closed.");
728
                                        g_debug ("NMEA socket closed.");
480
                                else if (error->code != G_IO_ERROR_CANCELLED)
729
                                } else {
481
                                        g_warning ("Error when receiving message: %s",
730
                                        g_warning ("Error when receiving message: %s",
482
                                                   error->message);
731
                                                   error->message);
483
                                g_error_free (error);
732
                                }
484
                        } else {
733
                        } else {
485
                                g_debug ("Nothing to read");
734
                                g_debug ("NMEA nothing to read");
486
                        }
735
                        }
487
                        g_object_unref (data_input_stream);
488
736
489
                        if (source->priv->active_service != NULL)
737
                        service_broken (source);
490
                                /* In case service did not advertise it exiting
491
                                 * or we failed to receive it's notification.
492
                                 */
493
                                remove_service (source, source->priv->active_service);
494
738
495
                        gga[0] = '\0';
496
                        rmc[0] = '\0';
497
                        return;
739
                        return;
498
                }
740
                }
499
                g_debug ("Network source sent: \"%s\"", message);
741
                g_debug ("Network source sent: \"%s\"", message);
Lines 506-517 Link Here
506
                        g_debug ("Ignoring NMEA sentence, as it's neither GGA or RMC: %s", message);
748
                        g_debug ("Ignoring NMEA sentence, as it's neither GGA or RMC: %s", message);
507
                }
749
                }
508
750
509
                message = (char *) g_buffered_input_stream_peek_buffer
751
                nmea_skip_delim (G_BUFFERED_INPUT_STREAM (data_input_stream),
510
                        (G_BUFFERED_INPUT_STREAM (data_input_stream),
752
                                 source->priv->cancellable);
511
                         &data_size);
753
512
                if (g_strstr_len (message, data_size, "\n")) {
754
                if (nmea_check_delim (G_BUFFERED_INPUT_STREAM (data_input_stream))) {
513
                    message = g_data_input_stream_read_line
755
                    g_clear_pointer (&message, g_free);
514
                            (data_input_stream, &data_size, NULL, &error);
756
                    message = g_data_input_stream_read_upto
757
                            (data_input_stream,
758
                             NMEA_LINE_END, NMEA_LINE_END_CTR,
759
                             &data_size, NULL, &error);
515
                } else {
760
                } else {
516
                    break;
761
                    break;
517
                }
762
                }
Lines 524-529 Link Here
524
                sentences[i++] = rmc;
769
                sentences[i++] = rmc;
525
        sentences[i] = NULL;
770
        sentences[i] = NULL;
526
771
772
        if (i > 0) {
527
        prev_location = gclue_location_source_get_location
773
        prev_location = gclue_location_source_get_location
528
                (GCLUE_LOCATION_SOURCE (source));
774
                (GCLUE_LOCATION_SOURCE (source));
529
        location = gclue_location_create_from_nmeas (sentences,
775
        location = gclue_location_create_from_nmeas (sentences,
Lines 532-548 Link Here
532
778
533
        if (error != NULL) {
779
        if (error != NULL) {
534
                g_warning ("Error: %s", error->message);
780
                g_warning ("Error: %s", error->message);
535
                g_clear_error (&error);
536
        } else {
781
        } else {
537
                gclue_location_source_set_location
782
                gclue_location_source_set_location
538
                        (GCLUE_LOCATION_SOURCE (source), location);
783
                        (GCLUE_LOCATION_SOURCE (source), location);
539
        }
784
        }
785
        }
540
786
541
        gga[0] = '\0';
787
        g_data_input_stream_read_upto_async (data_input_stream,
542
        rmc[0] = '\0';
788
                                             NMEA_LINE_END,
543
        sentences[0] = NULL;
789
                                             NMEA_LINE_END_CTR,
544
545
        g_data_input_stream_read_line_async (data_input_stream,
546
                                             G_PRIORITY_DEFAULT,
790
                                             G_PRIORITY_DEFAULT,
547
                                             source->priv->cancellable,
791
                                             source->priv->cancellable,
548
                                             on_read_nmea_sentence,
792
                                             on_read_nmea_sentence,
Lines 554-583 Link Here
554
                                  GAsyncResult *result,
798
                                  GAsyncResult *result,
555
                                  gpointer      user_data)
799
                                  gpointer      user_data)
556
{
800
{
557
        GClueNMEASource *source = GCLUE_NMEA_SOURCE (user_data);
558
        GSocketClient *client = G_SOCKET_CLIENT (object);
801
        GSocketClient *client = G_SOCKET_CLIENT (object);
559
        GError *error = NULL;
802
        GClueNMEASource *source;
560
        GDataInputStream *data_input_stream;
803
        g_autoptr(GSocketConnection) connection = NULL;
561
        GInputStream *input_stream;
804
        g_autoptr(GError) error = NULL;
562
805
563
        source->priv->connection = g_socket_client_connect_to_host_finish
806
        connection = g_socket_client_connect_to_host_finish
564
                (client,
807
                (client,
565
                 result,
808
                 result,
566
                 &error);
809
                 &error);
567
810
811
        if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
812
                return;
813
        }
814
815
        source = GCLUE_NMEA_SOURCE (user_data);
816
568
        if (error != NULL) {
817
        if (error != NULL) {
569
                if (error->code != G_IO_ERROR_CANCELLED)
570
                        g_warning ("Failed to connect to NMEA service: %s", error->message);
818
                        g_warning ("Failed to connect to NMEA service: %s", error->message);
571
                g_clear_error (&error);
819
                service_broken (source);
572
573
                return;
820
                return;
574
        }
821
        }
575
822
576
        input_stream = g_io_stream_get_input_stream
823
        g_assert (connection);
577
                (G_IO_STREAM (source->priv->connection));
824
        g_debug ("NMEA service connected.");
578
        data_input_stream = g_data_input_stream_new (input_stream);
579
825
580
        g_data_input_stream_read_line_async (data_input_stream,
826
        g_assert (!source->priv->connection);
827
        source->priv->connection = g_steal_pointer (&connection);
828
829
        g_assert (!source->priv->input_stream);
830
        source->priv->input_stream = g_data_input_stream_new
831
                (g_io_stream_get_input_stream (G_IO_STREAM (source->priv->connection)));
832
833
        g_data_input_stream_read_upto_async (source->priv->input_stream,
834
                                             NMEA_LINE_END,
835
                                             NMEA_LINE_END_CTR,
581
                                             G_PRIORITY_DEFAULT,
836
                                             G_PRIORITY_DEFAULT,
582
                                             source->priv->cancellable,
837
                                             source->priv->cancellable,
583
                                             on_read_nmea_sentence,
838
                                             on_read_nmea_sentence,
Lines 585-608 Link Here
585
}
840
}
586
841
587
static void
842
static void
588
connect_to_service (GClueNMEASource *source)
843
try_connect_to_service (GClueNMEASource *source)
589
{
844
{
590
        GClueNMEASourcePrivate *priv = source->priv;
845
        GClueNMEASourcePrivate *priv = source->priv;
591
        GSocketAddress *addr;
592
        GSocketConnectable *connectable;
593
846
594
        if (priv->all_services == NULL)
847
        if (!gclue_location_source_get_active (GCLUE_LOCATION_SOURCE (source))) {
848
                g_warn_if_fail (!priv->active_service);
849
850
                return;
851
        }
852
853
        if (priv->active_service)
854
                return;
855
856
        if (priv->try_services == NULL)
595
                return;
857
                return;
596
858
859
        g_assert (!priv->cancellable);
860
        priv->cancellable = g_cancellable_new ();
861
862
        g_assert (!priv->client);
597
        priv->client = g_socket_client_new ();
863
        priv->client = g_socket_client_new ();
598
        g_cancellable_reset (priv->cancellable);
599
864
600
        /* The service with the highest accuracy will be stored in the beginning
865
        /* The service with the highest accuracy will be stored in the beginning
601
         * of the list.
866
         * of the list.
602
         */
867
         */
603
        priv->active_service = (AvahiServiceInfo *) priv->all_services->data;
868
        priv->active_service = (AvahiServiceInfo *) priv->try_services->data;
604
869
605
        if ( priv->active_service->port != 0 )
870
        g_debug ("Trying to connect to NMEA %sservice %s:%u.",
871
                 priv->active_service->is_socket ? "socket " : "",
872
                 priv->active_service->host_name,
873
                 (unsigned int) priv->active_service->port);
874
875
        if (!priv->active_service->is_socket) {
606
		g_socket_client_connect_to_host_async
876
		g_socket_client_connect_to_host_async
607
			(priv->client,
877
			(priv->client,
608
			 priv->active_service->host_name,
878
			 priv->active_service->host_name,
Lines 610-661 Link Here
610
			 priv->cancellable,
880
			 priv->cancellable,
611
			 on_connection_to_location_server,
881
			 on_connection_to_location_server,
612
			 source);
882
			 source);
613
        else {
883
        } else {
884
                g_autoptr(GSocketAddress) addr = NULL;
885
614
		addr = g_unix_socket_address_new(priv->active_service->host_name);
886
		addr = g_unix_socket_address_new(priv->active_service->host_name);
615
		connectable = G_SOCKET_CONNECTABLE (addr);
616
		g_socket_client_connect_async (priv->client,
887
		g_socket_client_connect_async (priv->client,
617
                               connectable,
888
                               G_SOCKET_CONNECTABLE (addr),
618
                               priv->cancellable,
889
                               priv->cancellable,
619
                               on_connection_to_location_server,
890
                               on_connection_to_location_server,
620
                               source);
891
                               source);
621
        }
892
        }
622
}
893
}
623
894
624
static void
895
static gboolean
625
disconnect_from_service (GClueNMEASource *source)
896
remove_avahi_services_from_list (GClueNMEASource *source, GList **list)
626
{
897
{
627
        GClueNMEASourcePrivate *priv = source->priv;
898
        GClueNMEASourcePrivate *priv = source->priv;
899
        gboolean removed_active = FALSE;
900
        GList *l = *list;
628
901
629
        g_cancellable_cancel (priv->cancellable);
902
        while (l != NULL) {
903
                GList *next = l->next;
904
                AvahiServiceInfo *service = l->data;
905
906
                if (!service->is_socket) {
907
                        if (service == priv->active_service) {
908
                                g_debug ("Active NMEA service was Avahi-provided, disconnecting.");
909
                                disconnect_from_service (source);
910
                                removed_active = TRUE;
911
                        }
630
912
631
        if (priv->connection != NULL) {
913
                        remove_service_from_list (list, l);
632
                GError *error = NULL;
914
                }
633
915
634
                g_io_stream_close (G_IO_STREAM (priv->connection),
916
                l = next;
635
                                   NULL,
636
                                   &error);
637
                if (error != NULL)
638
                        g_warning ("Error in closing socket connection: %s", error->message);
639
        }
917
        }
640
918
641
        g_clear_object (&priv->connection);
919
        return removed_active;
642
        g_clear_object (&priv->client);
920
}
643
        priv->active_service = NULL;
921
922
static void
923
disconnect_avahi_client (GClueNMEASource *source)
924
{
925
        GClueNMEASourcePrivate *priv = source->priv;
926
927
        remove_avahi_services_from_list (source, &priv->try_services);
928
        if (remove_avahi_services_from_list (source, &priv->broken_services)) {
929
                g_warn_if_reached ();
930
        }
931
932
        g_clear_pointer (&priv->avahi_client, avahi_client_free);
933
934
        service_lists_changed (source);
644
}
935
}
645
936
646
static void
937
static void
647
gclue_nmea_source_finalize (GObject *gnmea)
938
gclue_nmea_source_finalize (GObject *gnmea)
648
{
939
{
649
        GClueNMEASourcePrivate *priv = GCLUE_NMEA_SOURCE (gnmea)->priv;
940
        GClueNMEASource *source = GCLUE_NMEA_SOURCE (gnmea);
941
        GClueNMEASourcePrivate *priv = source->priv;
650
942
651
        G_OBJECT_CLASS (gclue_nmea_source_parent_class)->finalize (gnmea);
943
        G_OBJECT_CLASS (gclue_nmea_source_parent_class)->finalize (gnmea);
652
944
653
        g_clear_object (&priv->connection);
945
        disconnect_avahi_client (source);
654
        g_clear_object (&priv->client);
946
        disconnect_from_service (source);
655
        g_clear_object (&priv->cancellable);
947
656
        if (priv->avahi_client)
948
        if (priv->accuracy_refresh_source) {
657
                avahi_client_free (priv->avahi_client);
949
                g_source_remove (priv->accuracy_refresh_source);
658
        g_list_free_full (priv->all_services,
950
                priv->accuracy_refresh_source = 0;
951
        }
952
953
        if (priv->unbreak_timer) {
954
                g_source_remove (priv->unbreak_timer);
955
                priv->unbreak_timer = 0;
956
        }
957
958
        g_clear_pointer (&priv->glib_poll, avahi_glib_poll_free);
959
960
        g_list_free_full (g_steal_pointer (&priv->try_services),
961
                          avahi_service_free);
962
        g_list_free_full (g_steal_pointer (&priv->broken_services),
659
                          avahi_service_free);
963
                          avahi_service_free);
660
}
964
}
661
965
Lines 672-712 Link Here
672
}
976
}
673
977
674
static void
978
static void
675
gclue_nmea_source_init (GClueNMEASource *source)
979
try_connect_avahi_client (GClueNMEASource *source)
676
{
980
{
677
        GClueNMEASourcePrivate *priv;
678
        AvahiServiceBrowser *service_browser;
981
        AvahiServiceBrowser *service_browser;
982
        GClueNMEASourcePrivate *priv = source->priv;
679
        const AvahiPoll *poll_api;
983
        const AvahiPoll *poll_api;
680
        AvahiGLibPoll *glib_poll;
681
        const char *nmea_socket;
682
        GClueConfig *config;
683
        int error;
984
        int error;
684
985
685
        source->priv = gclue_nmea_source_get_instance_private (source);
986
        if (priv->avahi_client) {
686
        priv = source->priv;
987
                AvahiClientState avahi_state;
687
988
688
        glib_poll = avahi_glib_poll_new (NULL, G_PRIORITY_DEFAULT);
989
                avahi_state = avahi_client_get_state (priv->avahi_client);
689
        poll_api = avahi_glib_poll_get (glib_poll);
990
                if (avahi_state != AVAHI_CLIENT_FAILURE) {
690
991
                        return;
691
        priv->cancellable = g_cancellable_new ();
992
                }
692
693
        config = gclue_config_get_singleton ();
694
993
695
        nmea_socket = gclue_config_get_nmea_socket (config);
994
                g_debug ("Avahi client in failure state, trying to reinit.");
696
        if (nmea_socket != NULL) {
995
                disconnect_avahi_client (source);
697
                add_new_service (source,
698
                                 "nmea-socket",
699
                                 nmea_socket,
700
                                 0,
701
                                 NULL);
702
        }
996
        }
703
997
704
        avahi_client_new (poll_api,
998
        g_assert (priv->glib_poll);
999
        poll_api = avahi_glib_poll_get (priv->glib_poll);
1000
1001
        priv->avahi_client = avahi_client_new (poll_api,
705
                          0,
1002
                          0,
706
                          client_callback,
1003
                          client_callback,
707
                          source,
1004
                          source,
708
                          &error);
1005
                          &error);
709
710
        if (priv->avahi_client == NULL) {
1006
        if (priv->avahi_client == NULL) {
711
                g_warning ("Failed to connect to avahi service: %s",
1007
                g_warning ("Failed to connect to avahi service: %s",
712
                           avahi_strerror (error));
1008
                           avahi_strerror (error));
Lines 722-736 Link Here
722
                 0,
1018
                 0,
723
                 browse_callback,
1019
                 browse_callback,
724
                 source);
1020
                 source);
725
726
727
        if (service_browser == NULL) {
1021
        if (service_browser == NULL) {
728
                const char *errorstr;
1022
                const char *errorstr;
729
1023
730
                error = avahi_client_errno (priv->avahi_client);
1024
                error = avahi_client_errno (priv->avahi_client);
731
                errorstr = avahi_strerror (error);
1025
                errorstr = avahi_strerror (error);
732
                g_warning ("Failed to browse avahi services: %s", errorstr);
1026
                g_warning ("Failed to browse avahi services: %s", errorstr);
1027
                goto fail_client;
1028
        }
1029
1030
        return;
1031
1032
fail_client:
1033
        disconnect_avahi_client (source);
1034
}
1035
1036
static void
1037
gclue_nmea_source_init (GClueNMEASource *source)
1038
{
1039
        GClueNMEASourcePrivate *priv;
1040
        const char *nmea_socket;
1041
        GClueConfig *config;
1042
1043
        source->priv = gclue_nmea_source_get_instance_private (source);
1044
        priv = source->priv;
1045
1046
        priv->glib_poll = avahi_glib_poll_new (NULL, G_PRIORITY_DEFAULT);
1047
1048
        config = gclue_config_get_singleton ();
1049
1050
        nmea_socket = gclue_config_get_nmea_socket (config);
1051
        if (nmea_socket != NULL) {
1052
                add_new_service_socket (source,
1053
                                        "nmea-socket",
1054
                                        nmea_socket);
733
        }
1055
        }
1056
1057
        try_connect_avahi_client (source);
734
}
1058
}
735
1059
736
/**
1060
/**
Lines 750-757 Link Here
750
                source = g_object_new (GCLUE_TYPE_NMEA_SOURCE, NULL);
1074
                source = g_object_new (GCLUE_TYPE_NMEA_SOURCE, NULL);
751
                g_object_add_weak_pointer (G_OBJECT (source),
1075
                g_object_add_weak_pointer (G_OBJECT (source),
752
                                           (gpointer) &source);
1076
                                           (gpointer) &source);
753
        } else
1077
        } else {
754
                g_object_ref (source);
1078
                g_object_ref (source);
1079
                try_connect_avahi_client (source);
1080
        }
755
1081
756
        return source;
1082
        return source;
757
}
1083
}
Lines 767-776 Link Here
767
1093
768
        base_class = GCLUE_LOCATION_SOURCE_CLASS (gclue_nmea_source_parent_class);
1094
        base_class = GCLUE_LOCATION_SOURCE_CLASS (gclue_nmea_source_parent_class);
769
        base_result = base_class->start (source);
1095
        base_result = base_class->start (source);
770
        if (base_result != GCLUE_LOCATION_SOURCE_START_RESULT_OK)
1096
        if (base_result == GCLUE_LOCATION_SOURCE_START_RESULT_FAILED)
771
                return base_result;
1097
                return base_result;
772
1098
773
        connect_to_service (GCLUE_NMEA_SOURCE (source));
1099
        try_connect_avahi_client (GCLUE_NMEA_SOURCE (source));
1100
        reconnect_service (GCLUE_NMEA_SOURCE (source));
774
1101
775
        return base_result;
1102
        return base_result;
776
}
1103
}
(-)geoclue-2.6.0/src/gclue-service-client.c (-2 / +2 lines)
Lines 262-271 Link Here
262
        gclue_dbus_client_set_active (GCLUE_DBUS_CLIENT (client), TRUE);
262
        gclue_dbus_client_set_active (GCLUE_DBUS_CLIENT (client), TRUE);
263
        priv->locator = gclue_locator_new (accuracy_level);
263
        priv->locator = gclue_locator_new (accuracy_level);
264
        gclue_locator_set_time_threshold (priv->locator, priv->time_threshold);
264
        gclue_locator_set_time_threshold (priv->locator, priv->time_threshold);
265
        g_signal_connect (priv->locator,
265
        g_signal_connect_object (priv->locator,
266
                          "notify::location",
266
                          "notify::location",
267
                          G_CALLBACK (on_locator_location_changed),
267
                          G_CALLBACK (on_locator_location_changed),
268
                          client);
268
                                 client, 0);
269
269
270
        gclue_location_source_start (GCLUE_LOCATION_SOURCE (priv->locator));
270
        gclue_location_source_start (GCLUE_LOCATION_SOURCE (priv->locator));
271
}
271
}
(-)geoclue-2.6.0/src/gclue-service-manager.c (-9 / +10 lines)
Lines 228-242 Link Here
228
        }
228
        }
229
        g_debug ("Number of connected clients: %u", priv->num_clients);
229
        g_debug ("Number of connected clients: %u", priv->num_clients);
230
230
231
        g_signal_connect (client,
231
        g_signal_connect_object (client,
232
                          "notify::active",
232
                          "notify::active",
233
                          G_CALLBACK (on_client_notify_active),
233
                          G_CALLBACK (on_client_notify_active),
234
                          data->manager);
234
                                 data->manager, 0);
235
235
236
        g_signal_connect (info,
236
        g_signal_connect_object (info,
237
                          "peer-vanished",
237
                          "peer-vanished",
238
                          G_CALLBACK (on_peer_vanished),
238
                          G_CALLBACK (on_peer_vanished),
239
                          data->manager);
239
                                 data->manager, 0);
240
240
241
client_created:
241
client_created:
242
        if (data->reuse_client)
242
        if (data->reuse_client)
Lines 434-439 Link Here
434
add_agent_data_free (AddAgentData *data)
434
add_agent_data_free (AddAgentData *data)
435
{
435
{
436
        g_clear_pointer (&data->desktop_id, g_free);
436
        g_clear_pointer (&data->desktop_id, g_free);
437
        g_clear_object (&data->manager);
437
        g_slice_free (AddAgentData, data);
438
        g_slice_free (AddAgentData, data);
438
}
439
}
439
440
Lines 470-479 Link Here
470
        g_debug ("New agent for user ID '%u'", user_id);
471
        g_debug ("New agent for user ID '%u'", user_id);
471
        g_hash_table_replace (priv->agents, GINT_TO_POINTER (user_id), agent);
472
        g_hash_table_replace (priv->agents, GINT_TO_POINTER (user_id), agent);
472
473
473
        g_signal_connect (data->info,
474
        g_signal_connect_object (data->info,
474
                          "peer-vanished",
475
                          "peer-vanished",
475
                          G_CALLBACK (on_agent_vanished),
476
                          G_CALLBACK (on_agent_vanished),
476
                          data->manager);
477
                                 data->manager, 0);
477
478
478
        gclue_dbus_manager_complete_add_agent (data->manager, data->invocation);
479
        gclue_dbus_manager_complete_add_agent (data->manager, data->invocation);
479
480
Lines 564-570 Link Here
564
        peer = g_dbus_method_invocation_get_sender (invocation);
565
        peer = g_dbus_method_invocation_get_sender (invocation);
565
566
566
        data = g_slice_new0 (AddAgentData);
567
        data = g_slice_new0 (AddAgentData);
567
        data->manager = manager;
568
        data->manager = g_object_ref (manager);
568
        data->invocation = invocation;
569
        data->invocation = invocation;
569
        data->desktop_id = g_strdup (id);
570
        data->desktop_id = g_strdup (id);
570
        gclue_client_info_new_async (peer,
571
        gclue_client_info_new_async (peer,
Lines 659-668 Link Here
659
        G_OBJECT_CLASS (gclue_service_manager_parent_class)->constructed (object);
660
        G_OBJECT_CLASS (gclue_service_manager_parent_class)->constructed (object);
660
661
661
        priv->locator = gclue_locator_new (GCLUE_ACCURACY_LEVEL_EXACT);
662
        priv->locator = gclue_locator_new (GCLUE_ACCURACY_LEVEL_EXACT);
662
        g_signal_connect (G_OBJECT (priv->locator),
663
        g_signal_connect_object (G_OBJECT (priv->locator),
663
                          "notify::available-accuracy-level",
664
                          "notify::available-accuracy-level",
664
                          G_CALLBACK (on_avail_accuracy_level_changed),
665
                          G_CALLBACK (on_avail_accuracy_level_changed),
665
                          object);
666
                                 object, 0);
666
        on_avail_accuracy_level_changed (G_OBJECT (priv->locator),
667
        on_avail_accuracy_level_changed (G_OBJECT (priv->locator),
667
                                         NULL,
668
                                         NULL,
668
                                         object);
669
                                         object);
(-)geoclue-2.6.0/src/gclue-utils.h (+61 lines)
Line 0 Link Here
1
/* vim: set et ts=8 sw=8: */
2
/*
3
 * Geoclue is free software; you can redistribute it and/or modify it under
4
 * the terms of the GNU General Public License as published by the Free
5
 * Software Foundation; either version 2 of the License, or (at your option)
6
 * any later version.
7
 *
8
 * Geoclue is distributed in the hope that it will be useful, but WITHOUT ANY
9
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
10
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
11
 * details.
12
 *
13
 * You should have received a copy of the GNU General Public License along
14
 * with Geoclue; if not, write to the Free Software Foundation, Inc.,
15
 * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
16
 *
17
 */
18
19
#ifndef GCLUE_UTILS_H
20
#define GCLUE_UTILS_H
21
22
#include <glib.h>
23
#include <string.h>
24
25
G_BEGIN_DECLS
26
27
#ifndef strnpbrk
28
inline static const char *
29
strnpbrk (const char *s, const char *accept, size_t n)
30
{
31
        const char *end;
32
33
        for (end = s + n; s < end && *s != '\0'; s++) {
34
                if (strchr (accept, *s)) {
35
                        return s;
36
                }
37
        }
38
39
        return NULL;
40
}
41
#endif
42
43
#ifndef strnspn
44
inline static size_t
45
strnspn (const char *s, const char *accept, size_t n)
46
{
47
        const char *cur, *end;
48
49
        for (cur = s, end = s + n; cur < end && *cur != '\0'; cur++) {
50
                if (!strchr (accept, *cur)) {
51
                        break;
52
                }
53
        }
54
55
        return cur - s;
56
}
57
#endif
58
59
G_END_DECLS
60
61
#endif /* GCLUE_UTILS_H */
(-)geoclue-2.6.0/src/gclue-web-source.c (-75 / +251 lines)
Lines 27-32 Link Here
27
#include "gclue-web-source.h"
27
#include "gclue-web-source.h"
28
#include "gclue-error.h"
28
#include "gclue-error.h"
29
#include "gclue-location.h"
29
#include "gclue-location.h"
30
#include "gclue-mozilla.h"
30
31
31
/**
32
/**
32
 * SECTION:gclue-web-source
33
 * SECTION:gclue-web-source
Lines 36-58 Link Here
36
 * Baseclass for all sources that solely use a web resource for geolocation.
37
 * Baseclass for all sources that solely use a web resource for geolocation.
37
 **/
38
 **/
38
39
39
static gboolean
40
get_internet_available (void);
41
static void
40
static void
42
refresh_accuracy_level (GClueWebSource *web);
41
refresh_accuracy_level (GClueWebSource *web);
43
42
44
struct _GClueWebSourcePrivate {
43
struct _GClueWebSourcePrivate {
44
        GCancellable *cancellable;
45
46
        GClueAccuracyLevel accuracy_level;
47
45
        SoupSession *soup_session;
48
        SoupSession *soup_session;
46
49
47
        SoupMessage *query;
50
        SoupMessage *query;
51
        const char *query_data_description;
48
52
49
        gulong network_changed_id;
53
        gulong network_changed_id;
50
        gulong connectivity_changed_id;
54
        gulong connectivity_changed_id;
51
55
52
        guint64 last_submitted;
56
        guint64 last_submitted;
53
57
54
        gboolean internet_available;
58
        const char *locate_url;
59
        const char *submit_url;
60
        gboolean locate_url_reachable;
61
        gboolean submit_url_reachable;
62
};
63
64
enum
65
{
66
        PROP_0,
67
        PROP_ACCURACY_LEVEL,
68
        LAST_PROP
55
};
69
};
70
static GParamSpec *gParamSpecs[LAST_PROP];
56
71
57
G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GClueWebSource,
72
G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GClueWebSource,
58
                                  gclue_web_source,
73
                                  gclue_web_source,
Lines 60-66 Link Here
60
                                  G_ADD_PRIVATE (GClueWebSource))
75
                                  G_ADD_PRIVATE (GClueWebSource))
61
76
62
static void refresh_callback (SoupSession *session,
77
static void refresh_callback (SoupSession *session,
63
                              SoupMessage *query,
78
                              GAsyncResult *result,
64
                              gpointer     user_data);
79
                              gpointer     user_data);
65
80
66
static void
81
static void
Lines 83-94 Link Here
83
                return;
98
                return;
84
        }
99
        }
85
100
86
        if (!get_internet_available ()) {
101
        if (!source->priv->locate_url_reachable) {
87
                g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NETWORK_UNREACHABLE,
102
                g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NETWORK_UNREACHABLE,
88
                                         "Network unavailable");
103
                                         "Cannot reach locate URL");
89
                return;
104
                return;
90
        }
105
        }
91
        g_debug ("Network available");
92
106
93
        if (source->priv->query != NULL) {
107
        if (source->priv->query != NULL) {
94
                g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_PENDING,
108
                g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_PENDING,
Lines 96-148 Link Here
96
                return;
110
                return;
97
        }
111
        }
98
112
99
        source->priv->query = GCLUE_WEB_SOURCE_GET_CLASS (source)->create_query (source, &local_error);
113
        source->priv->query = GCLUE_WEB_SOURCE_GET_CLASS (source)->create_query
100
114
                (source, &source->priv->query_data_description, &local_error);
101
        if (source->priv->query == NULL) {
115
        if (source->priv->query == NULL) {
102
                g_task_return_error (task, g_steal_pointer (&local_error));
116
                g_task_return_error (task, g_steal_pointer (&local_error));
103
                return;
117
                return;
104
        }
118
        }
105
119
106
        /* TODO handle cancellation */
120
        soup_session_send_and_read_async (source->priv->soup_session,
107
        soup_session_queue_message (source->priv->soup_session,
108
                                    source->priv->query,
121
                                    source->priv->query,
109
                                    refresh_callback,
122
                                          G_PRIORITY_DEFAULT,
123
                                          cancellable,
124
                                          (GAsyncReadyCallback)refresh_callback,
110
                                    g_steal_pointer (&task));
125
                                    g_steal_pointer (&task));
111
}
126
}
112
127
113
static void
128
static void
114
refresh_callback (SoupSession *session,
129
refresh_callback (SoupSession *session,
115
                  SoupMessage *query,
130
                  GAsyncResult *result,
116
                  gpointer     user_data)
131
                  gpointer     user_data)
117
{
132
{
118
        g_autoptr(GTask) task = g_steal_pointer (&user_data);
133
        g_autoptr(GTask) task = g_steal_pointer (&user_data);
119
        GClueWebSource *web;
134
        GClueWebSource *web;
135
        g_autoptr(SoupMessage) query = NULL;
136
        g_autoptr(GBytes) body = NULL;
120
        g_autoptr(GError) local_error = NULL;
137
        g_autoptr(GError) local_error = NULL;
121
        g_autofree char *contents = NULL;
138
        g_autofree char *contents = NULL;
122
        g_autofree char *str = NULL;
139
        g_autofree char *str = NULL;
123
        g_autoptr(GClueLocation) location = NULL;
140
        g_autoptr(GClueLocation) location = NULL;
124
        SoupURI *uri;
141
        GUri *uri;
142
143
        web = GCLUE_WEB_SOURCE (g_task_get_source_object (task));
144
        query = g_steal_pointer (&web->priv->query);
125
145
126
        if (query->status_code == SOUP_STATUS_CANCELLED) {
146
        body = soup_session_send_and_read_finish (session, result, &local_error);
127
                g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_CANCELLED,
147
        if (!body) {
128
                                         "Operation cancelled");
148
                g_task_return_error (task, g_steal_pointer (&local_error));
129
                return;
149
                return;
130
        }
150
        }
131
151
132
        web = GCLUE_WEB_SOURCE (g_task_get_source_object (task));
152
        if (soup_message_get_status (query) != SOUP_STATUS_OK) {
133
        web->priv->query = NULL;
134
135
        if (query->status_code != SOUP_STATUS_OK) {
136
                g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED,
153
                g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED,
137
                                         "Failed to query location: %s", query->reason_phrase);
154
                                         "Query location SOUP error: %s",
155
                                         soup_message_get_reason_phrase (query));
138
                return;
156
                return;
139
        }
157
        }
140
158
141
        contents = g_strndup (query->response_body->data, query->response_body->length);
159
        contents = g_strndup (g_bytes_get_data (body, NULL), g_bytes_get_size (body));
142
        uri = soup_message_get_uri (query);
160
        uri = soup_message_get_uri (query);
143
        str = soup_uri_to_string (uri, FALSE);
161
        str = g_uri_to_string (uri);
144
        g_debug ("Got following response from '%s':\n%s", str, contents);
162
        g_debug ("Got following response from '%s':\n%s", str, contents);
145
        location = GCLUE_WEB_SOURCE_GET_CLASS (web)->parse_response (web, contents, &local_error);
163
        location = gclue_mozilla_parse_response (contents,
164
                                                 web->priv->query_data_description,
165
                                                 &local_error);
146
        if (local_error != NULL) {
166
        if (local_error != NULL) {
147
                g_task_return_error (task, g_steal_pointer (&local_error));
167
                g_task_return_error (task, g_steal_pointer (&local_error));
148
                return;
168
                return;
Lines 177-198 Link Here
177
        location = GCLUE_WEB_SOURCE_GET_CLASS (web)->refresh_finish (web, result, &local_error);
197
        location = GCLUE_WEB_SOURCE_GET_CLASS (web)->refresh_finish (web, result, &local_error);
178
198
179
        if (local_error != NULL &&
199
        if (local_error != NULL &&
180
            !g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_INITIALIZED)) {
200
            !g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
181
                g_warning ("Failed to query location: %s", local_error->message);
201
                if (!g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_INITIALIZED) &&
182
                return;
202
                    !g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_PENDING)) {
203
                        g_warning ("Failed to query location: %s",
204
                                   local_error->message);
205
                } else {
206
                        g_debug ("Failed to query location: %s",
207
                                 local_error->message);
183
        }
208
        }
184
}
209
}
185
186
static gboolean
187
get_internet_available (void)
188
{
189
        GNetworkMonitor *monitor = g_network_monitor_get_default ();
190
        gboolean available;
191
192
        available = (g_network_monitor_get_connectivity (monitor) ==
193
                     G_NETWORK_CONNECTIVITY_FULL);
194
195
        return available;
196
}
210
}
197
211
198
static void
212
static void
Lines 203-209 Link Here
203
        existing = gclue_location_source_get_available_accuracy_level
217
        existing = gclue_location_source_get_available_accuracy_level
204
                        (GCLUE_LOCATION_SOURCE (web));
218
                        (GCLUE_LOCATION_SOURCE (web));
205
        new = GCLUE_WEB_SOURCE_GET_CLASS (web)->get_available_accuracy_level
219
        new = GCLUE_WEB_SOURCE_GET_CLASS (web)->get_available_accuracy_level
206
                        (web, web->priv->internet_available);
220
                        (web, web->priv->locate_url_reachable);
207
        if (new != existing) {
221
        if (new != existing) {
208
                g_debug ("Available accuracy level from %s: %u",
222
                g_debug ("Available accuracy level from %s: %u",
209
                         G_OBJECT_TYPE_NAME (web), new);
223
                         G_OBJECT_TYPE_NAME (web), new);
Lines 214-231 Link Here
214
}
228
}
215
229
216
static void
230
static void
217
on_network_changed (GNetworkMonitor *monitor G_GNUC_UNUSED,
231
locate_url_checked_cb (GObject      *source_object,
218
                    gboolean         available G_GNUC_UNUSED,
232
                       GAsyncResult *result,
219
                    gpointer         user_data)
233
                    gpointer         user_data)
220
{
234
{
221
        GClueWebSource *web = GCLUE_WEB_SOURCE (user_data);
235
        GNetworkMonitor *mon = G_NETWORK_MONITOR (source_object);
222
        gboolean last_available = web->priv->internet_available;
236
        GClueWebSource *web;
237
        gboolean reachable, last_reachable;
238
        g_autoptr(GError) error = NULL;
223
239
224
        web->priv->internet_available = get_internet_available ();
240
        reachable = g_network_monitor_can_reach_finish (mon, result, &error);
225
        if (last_available == web->priv->internet_available)
241
        if (error && g_error_matches (error, G_IO_ERROR,
242
                                      G_IO_ERROR_CANCELLED)) {
243
                return; /* WebSource instance is finalized */
244
        }
245
246
        web = GCLUE_WEB_SOURCE (user_data);
247
        last_reachable = web->priv->locate_url_reachable;
248
        web->priv->locate_url_reachable = reachable;
249
        if (last_reachable == reachable)
226
                return; /* We already reacted to network change */
250
                return; /* We already reacted to network change */
227
251
228
        GCLUE_WEB_SOURCE_GET_CLASS (web)->refresh_async (web, NULL, query_callback, NULL);
252
        g_debug ("Network changed: %s",
253
                 reachable ? "Enabling locate URL queries" :
254
                             "Disabling locate URL queries");
255
        if (reachable) {
256
                GCLUE_WEB_SOURCE_GET_CLASS (web)->refresh_async
257
                        (web, NULL, query_callback, NULL);
258
        }
259
}
260
261
static void
262
submit_url_checked_cb (GObject      *source_object,
263
                       GAsyncResult *result,
264
                       gpointer      user_data)
265
{
266
        GNetworkMonitor *mon = G_NETWORK_MONITOR (source_object);
267
        GClueWebSource *web;
268
        gboolean reachable, last_reachable;
269
        g_autoptr(GError) error = NULL;
270
271
        reachable = g_network_monitor_can_reach_finish (mon, result, &error);
272
        if (error && g_error_matches (error, G_IO_ERROR,
273
                                      G_IO_ERROR_CANCELLED)) {
274
                return; /* WebSource instance is finalized */
275
        }
276
277
        web = GCLUE_WEB_SOURCE (user_data);
278
        last_reachable = web->priv->submit_url_reachable;
279
        web->priv->submit_url_reachable = reachable;
280
        if (last_reachable == reachable) {
281
                return;
282
        }
283
        g_debug ("Network changed: %s",
284
                 reachable ? "Enabling submit URL queries" :
285
                             "Disabling submit URL queries");
286
}
287
288
static void
289
on_network_changed (GNetworkMonitor *unused_monitor G_GNUC_UNUSED,
290
                    gboolean         available G_GNUC_UNUSED,
291
                    gpointer         user_data)
292
{
293
        GNetworkMonitor *monitor = g_network_monitor_get_default ();
294
        GClueWebSource *web = GCLUE_WEB_SOURCE (user_data);
295
        g_autoptr(GSocketConnectable) submit_addr = NULL;
296
        g_autoptr(GSocketConnectable) locate_addr = NULL;
297
298
        if (web->priv->submit_url) {
299
                submit_addr = g_network_address_parse_uri (web->priv->submit_url,
300
                                                           80, NULL);
301
                if (submit_addr) {
302
                        g_network_monitor_can_reach_async (monitor,
303
                                                           submit_addr,
304
                                                           web->priv->cancellable,
305
                                                           submit_url_checked_cb,
306
                                                           web);
307
                } else {
308
                        g_warning ("Could not parse submit URL '%s'",
309
                                   web->priv->submit_url);
310
                        web->priv->submit_url_reachable = FALSE;
311
                }
312
        } else {
313
                web->priv->submit_url_reachable = FALSE;
314
        }
315
316
        if (web->priv->locate_url) {
317
                locate_addr = g_network_address_parse_uri (web->priv->locate_url,
318
                                                           80, NULL);
319
                if (locate_addr) {
320
                        g_network_monitor_can_reach_async (monitor,
321
                                                           locate_addr,
322
                                                           web->priv->cancellable,
323
                                                           locate_url_checked_cb,
324
                                                           web);
325
                } else {
326
                        g_warning ("Could not parse locate URL '%s'",
327
                                   web->priv->locate_url);
328
                        web->priv->locate_url_reachable = FALSE;
329
                }
330
        } else {
331
                web->priv->locate_url_reachable = FALSE;
332
        }
229
}
333
}
230
334
231
static void
335
static void
Lines 241-246 Link Here
241
{
345
{
242
        GClueWebSourcePrivate *priv = GCLUE_WEB_SOURCE (gsource)->priv;
346
        GClueWebSourcePrivate *priv = GCLUE_WEB_SOURCE (gsource)->priv;
243
347
348
        g_cancellable_cancel (priv->cancellable);
349
244
        if (priv->network_changed_id) {
350
        if (priv->network_changed_id) {
245
                g_signal_handler_disconnect (g_network_monitor_get_default (),
351
                g_signal_handler_disconnect (g_network_monitor_get_default (),
246
                                             priv->network_changed_id);
352
                                             priv->network_changed_id);
Lines 253-267 Link Here
253
                priv->connectivity_changed_id = 0;
359
                priv->connectivity_changed_id = 0;
254
        }
360
        }
255
361
256
        if (priv->query != NULL) {
362
        if (priv->soup_session) {
257
                g_debug ("Cancelling query");
363
                soup_session_abort (priv->soup_session);
258
                soup_session_cancel_message (priv->soup_session,
364
                g_clear_object (&priv->soup_session);
259
                                             priv->query,
260
                                             SOUP_STATUS_CANCELLED);
261
                priv->query = NULL;
262
        }
365
        }
263
366
264
        g_clear_object (&priv->soup_session);
367
        g_clear_object (&priv->query);
368
        g_clear_object (&priv->cancellable);
265
369
266
        G_OBJECT_CLASS (gclue_web_source_parent_class)->finalize (gsource);
370
        G_OBJECT_CLASS (gclue_web_source_parent_class)->finalize (gsource);
267
}
371
}
Lines 274-283 Link Here
274
378
275
        G_OBJECT_CLASS (gclue_web_source_parent_class)->constructed (object);
379
        G_OBJECT_CLASS (gclue_web_source_parent_class)->constructed (object);
276
380
277
        priv->soup_session = soup_session_new_with_options
381
        priv->soup_session = soup_session_new ();
278
                        (SOUP_SESSION_REMOVE_FEATURE_BY_TYPE,
382
        soup_session_remove_feature_by_type (priv->soup_session, G_TYPE_PROXY_RESOLVER);
279
                         SOUP_TYPE_PROXY_RESOLVER_DEFAULT,
280
                         NULL);
281
383
282
        monitor = g_network_monitor_get_default ();
384
        monitor = g_network_monitor_get_default ();
283
        priv->network_changed_id =
385
        priv->network_changed_id =
Lines 296-301 Link Here
296
}
398
}
297
399
298
static void
400
static void
401
gclue_web_source_get_property (GObject    *object,
402
                               guint       prop_id,
403
                               GValue     *value,
404
                               GParamSpec *pspec)
405
{
406
        GClueWebSource *web = GCLUE_WEB_SOURCE (object);
407
408
        switch (prop_id) {
409
        case PROP_ACCURACY_LEVEL:
410
                g_value_set_enum (value, web->priv->accuracy_level);
411
                break;
412
413
        default:
414
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
415
        }
416
}
417
418
static void
419
gclue_web_source_set_property (GObject      *object,
420
                               guint         prop_id,
421
                               const GValue *value,
422
                               GParamSpec   *pspec)
423
{
424
        GClueWebSource *web = GCLUE_WEB_SOURCE (object);
425
426
        switch (prop_id) {
427
        case PROP_ACCURACY_LEVEL:
428
                web->priv->accuracy_level = g_value_get_enum (value);
429
                break;
430
431
        default:
432
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
433
        }
434
}
435
436
static void
299
gclue_web_source_class_init (GClueWebSourceClass *klass)
437
gclue_web_source_class_init (GClueWebSourceClass *klass)
300
{
438
{
301
        GObjectClass *gsource_class = G_OBJECT_CLASS (klass);
439
        GObjectClass *gsource_class = G_OBJECT_CLASS (klass);
Lines 303-316 Link Here
303
        klass->refresh_async = gclue_web_source_real_refresh_async;
441
        klass->refresh_async = gclue_web_source_real_refresh_async;
304
        klass->refresh_finish = gclue_web_source_real_refresh_finish;
442
        klass->refresh_finish = gclue_web_source_real_refresh_finish;
305
443
444
        gsource_class->get_property = gclue_web_source_get_property;
445
        gsource_class->set_property = gclue_web_source_set_property;
306
        gsource_class->finalize = gclue_web_source_finalize;
446
        gsource_class->finalize = gclue_web_source_finalize;
307
        gsource_class->constructed = gclue_web_source_constructed;
447
        gsource_class->constructed = gclue_web_source_constructed;
448
449
        gParamSpecs[PROP_ACCURACY_LEVEL] = g_param_spec_enum ("accuracy-level",
450
                                                              "AccuracyLevel",
451
                                                              "Max accuracy level",
452
                                                              GCLUE_TYPE_ACCURACY_LEVEL,
453
                                                              GCLUE_ACCURACY_LEVEL_CITY,
454
                                                              G_PARAM_READWRITE |
455
                                                              G_PARAM_CONSTRUCT_ONLY);
456
        g_object_class_install_property (gsource_class,
457
                                         PROP_ACCURACY_LEVEL,
458
                                         gParamSpecs[PROP_ACCURACY_LEVEL]);
308
}
459
}
309
460
310
static void
461
static void
311
gclue_web_source_init (GClueWebSource *web)
462
gclue_web_source_init (GClueWebSource *web)
312
{
463
{
313
        web->priv = gclue_web_source_get_instance_private (web);
464
        web->priv = gclue_web_source_get_instance_private (web);
465
        web->priv->cancellable = g_cancellable_new ();
314
}
466
}
315
467
316
/**
468
/**
Lines 331-354 Link Here
331
483
332
static void
484
static void
333
submit_query_callback (SoupSession *session,
485
submit_query_callback (SoupSession *session,
334
                       SoupMessage *query,
486
                       GAsyncResult *result,
335
                       gpointer     user_data)
487
                       gpointer     user_data)
336
{
488
{
337
        SoupURI *uri;
489
        g_autoptr(GBytes) body = NULL;
338
        g_autofree char *str = NULL;
490
        g_autoptr(GError) local_error = NULL;
491
        SoupMessage *query;
492
        g_autofree char *uri_str = NULL;
493
        gint status_code;
339
494
340
        uri = soup_message_get_uri (query);
495
        query = soup_session_get_async_result_message (session, result);
341
        str = soup_uri_to_string (uri, FALSE);
496
        uri_str = g_uri_to_string (soup_message_get_uri (query));
342
        if (query->status_code != SOUP_STATUS_OK &&
497
343
            query->status_code != SOUP_STATUS_NO_CONTENT) {
498
        body = soup_session_send_and_read_finish (session, result, &local_error);
499
        if (!body) {
500
                g_warning ("Failed to submit location data to '%s': %s",
501
                           uri_str, local_error->message);
502
                return;
503
        }
504
505
        status_code = soup_message_get_status (query);
506
        if (status_code != SOUP_STATUS_OK && status_code != SOUP_STATUS_NO_CONTENT) {
344
                g_warning ("Failed to submit location data to '%s': %s",
507
                g_warning ("Failed to submit location data to '%s': %s",
345
                           str,
508
                           uri_str, soup_message_get_reason_phrase (query));
346
                           query->reason_phrase);
347
		return;
509
		return;
348
	}
510
	}
349
511
350
        g_debug ("Successfully submitted location data to '%s'",
512
        g_debug ("Successfully submitted location data to '%s'", uri_str);
351
                 str);
352
}
513
}
353
514
354
#define SUBMISSION_ACCURACY_THRESHOLD 100
515
#define SUBMISSION_ACCURACY_THRESHOLD 100
Lines 362-369 Link Here
362
        GClueLocationSource *source = GCLUE_LOCATION_SOURCE (source_object);
523
        GClueLocationSource *source = GCLUE_LOCATION_SOURCE (source_object);
363
        GClueWebSource *web = GCLUE_WEB_SOURCE (user_data);
524
        GClueWebSource *web = GCLUE_WEB_SOURCE (user_data);
364
        GClueLocation *location;
525
        GClueLocation *location;
365
        SoupMessage *query;
526
        g_autoptr(SoupMessage) query = NULL;
366
        GError *error = NULL;
527
        g_autoptr(GError) error = NULL;
367
528
368
        location = gclue_location_source_get_location (source);
529
        location = gclue_location_source_get_location (source);
369
        if (location == NULL ||
530
        if (location == NULL ||
Lines 375-381 Link Here
375
536
376
        web->priv->last_submitted = gclue_location_get_timestamp (location);
537
        web->priv->last_submitted = gclue_location_get_timestamp (location);
377
538
378
        if (!get_internet_available ())
539
        if (!web->priv->submit_url_reachable)
379
                return;
540
                return;
380
541
381
        query = GCLUE_WEB_SOURCE_GET_CLASS (web)->create_submit_query
542
        query = GCLUE_WEB_SOURCE_GET_CLASS (web)->create_submit_query
Lines 386-400 Link Here
386
                if (error != NULL) {
547
                if (error != NULL) {
387
                        g_warning ("Failed to create submission query: %s",
548
                        g_warning ("Failed to create submission query: %s",
388
                                   error->message);
549
                                   error->message);
389
                        g_error_free (error);
390
                }
550
                }
391
551
392
                return;
552
                return;
393
        }
553
        }
394
554
395
        soup_session_queue_message (web->priv->soup_session,
555
        soup_session_send_and_read_async (web->priv->soup_session,
396
                                    query,
556
                                    query,
397
                                    submit_query_callback,
557
                                          G_PRIORITY_DEFAULT,
558
                                          NULL,
559
                                          (GAsyncReadyCallback)submit_query_callback,
398
                                    web);
560
                                    web);
399
}
561
}
400
562
Lines 423-425 Link Here
423
585
424
        on_submit_source_location_notify (G_OBJECT (submit_source), NULL, web);
586
        on_submit_source_location_notify (G_OBJECT (submit_source), NULL, web);
425
}
587
}
588
589
void
590
gclue_web_source_set_locate_url (GClueWebSource *source,
591
                                 const char     *url)
592
{
593
        source->priv->locate_url = url;
594
}
595
596
void
597
gclue_web_source_set_submit_url (GClueWebSource *source,
598
                                 const char     *url)
599
{
600
        source->priv->submit_url = url;
601
}
(-)geoclue-2.6.0/src/gclue-web-source.h (-3 / +5 lines)
Lines 71-83 Link Here
71
                                                  GError              **error);
71
                                                  GError              **error);
72
72
73
        SoupMessage *     (*create_query)        (GClueWebSource *source,
73
        SoupMessage *     (*create_query)        (GClueWebSource *source,
74
                                                  const char **query_data_description,
74
                                                  GError        **error);
75
                                                  GError        **error);
75
        SoupMessage *     (*create_submit_query) (GClueWebSource  *source,
76
        SoupMessage *     (*create_submit_query) (GClueWebSource  *source,
76
                                                  GClueLocation   *location,
77
                                                  GClueLocation   *location,
77
                                                  GError         **error);
78
                                                  GError         **error);
78
        GClueLocation * (*parse_response)        (GClueWebSource *source,
79
                                                  const char     *response,
80
                                                  GError        **error);
81
        GClueAccuracyLevel (*get_available_accuracy_level)
79
        GClueAccuracyLevel (*get_available_accuracy_level)
82
                                                 (GClueWebSource *source,
80
                                                 (GClueWebSource *source,
83
                                                  gboolean        network_available);
81
                                                  gboolean        network_available);
Lines 86-91 Link Here
86
void gclue_web_source_refresh           (GClueWebSource      *source);
84
void gclue_web_source_refresh           (GClueWebSource      *source);
87
void gclue_web_source_set_submit_source (GClueWebSource      *source,
85
void gclue_web_source_set_submit_source (GClueWebSource      *source,
88
                                         GClueLocationSource *submit_source);
86
                                         GClueLocationSource *submit_source);
87
void gclue_web_source_set_locate_url    (GClueWebSource      *source,
88
                                         const char          *url);
89
void gclue_web_source_set_submit_url    (GClueWebSource      *source,
90
                                         const char          *url);
89
91
90
G_END_DECLS
92
G_END_DECLS
91
93
(-)geoclue-2.6.0/src/gclue-wifi.c (-185 / +412 lines)
Lines 24-29 Link Here
24
#include <string.h>
24
#include <string.h>
25
#include <config.h>
25
#include <config.h>
26
#include "gclue-wifi.h"
26
#include "gclue-wifi.h"
27
#include "gclue-3g.h"
27
#include "gclue-config.h"
28
#include "gclue-config.h"
28
#include "gclue-error.h"
29
#include "gclue-error.h"
29
#include "gclue-mozilla.h"
30
#include "gclue-mozilla.h"
Lines 49-54 Link Here
49
 * full cache (excluding overheads). */
50
 * full cache (excluding overheads). */
50
#define CACHE_ENTRY_MAX_AGE_SECONDS (48 * 60 * 60)
51
#define CACHE_ENTRY_MAX_AGE_SECONDS (48 * 60 * 60)
51
52
53
/* The signal strength can typically vary by ±5 for a stationary laptop, so
54
 * match cache entries with that tolerance.
55
 * In dBm units.
56
 */
57
#define CACHE_ENTRY_MATCH_SIGNAL_WINDOW 10
58
52
/**
59
/**
53
 * SECTION:gclue-wifi
60
 * SECTION:gclue-wifi
54
 * @short_description: WiFi-based geolocation
61
 * @short_description: WiFi-based geolocation
Lines 78-84 Link Here
78
static void
85
static void
79
disconnect_cache_prune_timeout (GClueWifi *wifi);
86
disconnect_cache_prune_timeout (GClueWifi *wifi);
80
87
88
typedef struct {
89
        GArray *signals;
90
        GClueLocation *location;
91
} LocationCacheElement;
92
93
static LocationCacheElement *
94
location_cache_element_new (GArray *signals,
95
                            GClueLocation *location)
96
{
97
        LocationCacheElement *element;
98
99
        element = g_slice_new (LocationCacheElement);
100
        element->signals = signals;
101
        element->location = g_object_ref (location);
102
        return element;
103
}
104
105
static void location_cache_element_free (gpointer data)
106
{
107
        LocationCacheElement *element = data;
108
109
        if (element->signals)
110
                g_array_free (element->signals, TRUE);
111
        g_clear_object (&element->location);
112
        g_slice_free (LocationCacheElement, element);
113
}
114
115
typedef struct {
116
        GList *elements;
117
} LocationCacheValue;
118
119
static LocationCacheValue *
120
location_cache_value_new (void)
121
{
122
        LocationCacheValue *value;
123
124
        value = g_slice_new (LocationCacheValue);
125
        value->elements = NULL;
126
        return value;
127
}
128
129
static void location_cache_value_free (gpointer data)
130
{
131
        LocationCacheValue *value = data;
132
133
        g_list_free_full (value->elements, location_cache_element_free);
134
        g_slice_free (LocationCacheValue, value);
135
}
136
81
struct _GClueWifiPrivate {
137
struct _GClueWifiPrivate {
138
        GCancellable *intf_cancellable, *bss_cancellable;
139
        GClueMozilla *mozilla;
82
        WPASupplicant *supplicant;
140
        WPASupplicant *supplicant;
83
        WPAInterface *interface;
141
        WPAInterface *interface;
84
        GHashTable *bss_proxies;
142
        GHashTable *bss_proxies;
Lines 92-100 Link Here
92
150
93
        guint scan_timeout;
151
        guint scan_timeout;
94
152
95
        GClueAccuracyLevel accuracy_level;
153
        GHashTable *location_cache;  /* (element-type GVariant LocationCacheValue) (owned) */
96
97
        GHashTable *location_cache;  /* (element-type GVariant GClueLocation) (owned) */
98
        guint cache_prune_timeout_id;
154
        guint cache_prune_timeout_id;
99
        guint cache_hits, cache_misses;
155
        guint cache_hits, cache_misses;
100
156
Lines 104-128 Link Here
104
#endif
160
#endif
105
};
161
};
106
162
107
enum
108
{
109
        PROP_0,
110
        PROP_ACCURACY_LEVEL,
111
        LAST_PROP
112
};
113
static GParamSpec *gParamSpecs[LAST_PROP];
114
115
static SoupMessage *
163
static SoupMessage *
116
gclue_wifi_create_query (GClueWebSource *source,
164
gclue_wifi_create_query (GClueWebSource *source,
165
                         const char **query_data_description,
117
                         GError        **error);
166
                         GError        **error);
118
static SoupMessage *
167
static SoupMessage *
119
gclue_wifi_create_submit_query (GClueWebSource  *source,
168
gclue_wifi_create_submit_query (GClueWebSource  *source,
120
                                GClueLocation   *location,
169
                                GClueLocation   *location,
121
                                GError         **error);
170
                                GError         **error);
122
static GClueLocation *
123
gclue_wifi_parse_response (GClueWebSource *source,
124
                           const char     *json,
125
                           GError        **error);
126
static GClueAccuracyLevel
171
static GClueAccuracyLevel
127
gclue_wifi_get_available_accuracy_level (GClueWebSource *source,
172
gclue_wifi_get_available_accuracy_level (GClueWebSource *source,
128
                                         gboolean        net_available);
173
                                         gboolean        net_available);
Lines 150-155 Link Here
150
195
151
        G_OBJECT_CLASS (gclue_wifi_parent_class)->finalize (gwifi);
196
        G_OBJECT_CLASS (gclue_wifi_parent_class)->finalize (gwifi);
152
197
198
        g_cancellable_cancel (wifi->priv->intf_cancellable);
199
153
        disconnect_bss_signals (wifi);
200
        disconnect_bss_signals (wifi);
154
        disconnect_cache_prune_timeout (wifi);
201
        disconnect_cache_prune_timeout (wifi);
155
202
Lines 158-205 Link Here
158
        g_clear_pointer (&wifi->priv->bss_proxies, g_hash_table_unref);
205
        g_clear_pointer (&wifi->priv->bss_proxies, g_hash_table_unref);
159
        g_clear_pointer (&wifi->priv->ignored_bss_proxies, g_hash_table_unref);
206
        g_clear_pointer (&wifi->priv->ignored_bss_proxies, g_hash_table_unref);
160
        g_clear_pointer (&wifi->priv->location_cache, g_hash_table_unref);
207
        g_clear_pointer (&wifi->priv->location_cache, g_hash_table_unref);
208
        g_clear_object (&wifi->priv->mozilla);
209
        g_clear_object (&wifi->priv->intf_cancellable);
161
}
210
}
162
211
163
static void
212
static void
164
gclue_wifi_constructed (GObject *object);
213
gclue_wifi_constructed (GObject *object);
165
214
166
static void
215
static void
167
gclue_wifi_get_property (GObject    *object,
168
                         guint       prop_id,
169
                         GValue     *value,
170
                         GParamSpec *pspec)
171
{
172
        GClueWifi *wifi = GCLUE_WIFI (object);
173
174
        switch (prop_id) {
175
        case PROP_ACCURACY_LEVEL:
176
                g_value_set_enum (value, wifi->priv->accuracy_level);
177
                break;
178
179
        default:
180
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
181
        }
182
}
183
184
static void
185
gclue_wifi_set_property (GObject      *object,
186
                         guint         prop_id,
187
                         const GValue *value,
188
                         GParamSpec   *pspec)
189
{
190
        GClueWifi *wifi = GCLUE_WIFI (object);
191
192
        switch (prop_id) {
193
        case PROP_ACCURACY_LEVEL:
194
                wifi->priv->accuracy_level = g_value_get_enum (value);
195
                break;
196
197
        default:
198
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
199
        }
200
}
201
202
static void
203
gclue_wifi_class_init (GClueWifiClass *klass)
216
gclue_wifi_class_init (GClueWifiClass *klass)
204
{
217
{
205
        GClueWebSourceClass *web_class = GCLUE_WEB_SOURCE_CLASS (klass);
218
        GClueWebSourceClass *web_class = GCLUE_WEB_SOURCE_CLASS (klass);
Lines 212-235 Link Here
212
        web_class->refresh_finish = gclue_wifi_refresh_finish;
225
        web_class->refresh_finish = gclue_wifi_refresh_finish;
213
        web_class->create_submit_query = gclue_wifi_create_submit_query;
226
        web_class->create_submit_query = gclue_wifi_create_submit_query;
214
        web_class->create_query = gclue_wifi_create_query;
227
        web_class->create_query = gclue_wifi_create_query;
215
        web_class->parse_response = gclue_wifi_parse_response;
216
        web_class->get_available_accuracy_level =
228
        web_class->get_available_accuracy_level =
217
                gclue_wifi_get_available_accuracy_level;
229
                gclue_wifi_get_available_accuracy_level;
218
        gwifi_class->get_property = gclue_wifi_get_property;
219
        gwifi_class->set_property = gclue_wifi_set_property;
220
        gwifi_class->finalize = gclue_wifi_finalize;
230
        gwifi_class->finalize = gclue_wifi_finalize;
221
        gwifi_class->constructed = gclue_wifi_constructed;
231
        gwifi_class->constructed = gclue_wifi_constructed;
222
223
        gParamSpecs[PROP_ACCURACY_LEVEL] = g_param_spec_enum ("accuracy-level",
224
                                                              "AccuracyLevel",
225
                                                              "Max accuracy level",
226
                                                              GCLUE_TYPE_ACCURACY_LEVEL,
227
                                                              GCLUE_ACCURACY_LEVEL_CITY,
228
                                                              G_PARAM_READWRITE |
229
                                                              G_PARAM_CONSTRUCT_ONLY);
230
        g_object_class_install_property (gwifi_class,
231
                                         PROP_ACCURACY_LEVEL,
232
                                         gParamSpecs[PROP_ACCURACY_LEVEL]);
233
}
232
}
234
233
235
static void
234
static void
Lines 345-363 Link Here
345
                    GAsyncResult *res,
344
                    GAsyncResult *res,
346
                    gpointer      user_data)
345
                    gpointer      user_data)
347
{
346
{
348
        GClueWifi *wifi = GCLUE_WIFI (user_data);
347
        GClueWifi *wifi;
349
        WPABSS *bss;
348
        WPABSS *bss;
350
        GError *error = NULL;
349
        g_autoptr(GError) error = NULL;
351
        char ssid[MAX_SSID_LEN + 1] = { 0 };
350
        char ssid[MAX_SSID_LEN + 1] = { 0 };
352
351
353
        bss = wpa_bss_proxy_new_for_bus_finish (res, &error);
352
        bss = wpa_bss_proxy_new_for_bus_finish (res, &error);
354
        if (bss == NULL) {
353
        if (bss == NULL) {
355
                g_debug ("%s", error->message);
354
                if (error && !g_error_matches (error, G_IO_ERROR,
356
                g_error_free (error);
355
                                               G_IO_ERROR_CANCELLED)) {
356
                        g_warning ("BSS proxy setup failed: %s",
357
                                   error->message);
358
                }
357
359
358
                return;
360
                return;
359
        }
361
        }
360
362
363
        wifi = GCLUE_WIFI (user_data);
364
361
        if (gclue_mozilla_should_ignore_bss (bss)) {
365
        if (gclue_mozilla_should_ignore_bss (bss)) {
362
                g_object_unref (bss);
366
                g_object_unref (bss);
363
367
Lines 365-371 Link Here
365
        }
369
        }
366
370
367
        get_ssid_from_bss (bss, ssid);
371
        get_ssid_from_bss (bss, ssid);
368
        g_debug ("WiFi AP '%s' added.", ssid);
372
        g_debug ("Got WiFi AP '%s'", ssid);
369
373
370
        if (wpa_bss_get_signal (bss) <= WIFI_SCAN_BSS_NOISE_LEVEL) {
374
        if (wpa_bss_get_signal (bss) <= WIFI_SCAN_BSS_NOISE_LEVEL) {
371
                const char *path;
375
                const char *path;
Lines 396-408 Link Here
396
              GVariant     *properties,
400
              GVariant     *properties,
397
              gpointer      user_data)
401
              gpointer      user_data)
398
{
402
{
403
        GClueWifi *wifi = GCLUE_WIFI (user_data);
404
399
        wpa_bss_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
405
        wpa_bss_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
400
                                   G_DBUS_PROXY_FLAGS_NONE,
406
                                   G_DBUS_PROXY_FLAGS_NONE,
401
                                   "fi.w1.wpa_supplicant1",
407
                                   "fi.w1.wpa_supplicant1",
402
                                   path,
408
                                   path,
403
                                   NULL,
409
                                   wifi->priv->bss_cancellable,
404
                                   on_bss_proxy_ready,
410
                                   on_bss_proxy_ready,
405
                                   user_data);
411
                                   wifi);
406
}
412
}
407
413
408
static gboolean
414
static gboolean
Lines 459-465 Link Here
459
465
460
        wpa_interface_call_scan (WPA_INTERFACE (priv->interface),
466
        wpa_interface_call_scan (WPA_INTERFACE (priv->interface),
461
                                 args,
467
                                 args,
462
                                 NULL,
468
                                 priv->bss_cancellable,
463
                                 on_scan_call_done,
469
                                 on_scan_call_done,
464
                                 wifi);
470
                                 wifi);
465
}
471
}
Lines 492-498 Link Here
492
        GClueWifi *wifi = GCLUE_WIFI (user_data);
498
        GClueWifi *wifi = GCLUE_WIFI (user_data);
493
        GClueWifiPrivate *priv = wifi->priv;
499
        GClueWifiPrivate *priv = wifi->priv;
494
500
495
        g_debug ("WiFi scan timeout.");
496
        priv->scan_timeout = 0;
501
        priv->scan_timeout = 0;
497
502
498
        if (priv->interface == NULL)
503
        if (priv->interface == NULL)
Lines 503-508 Link Here
503
        return G_SOURCE_REMOVE;
508
        return G_SOURCE_REMOVE;
504
}
509
}
505
510
511
gboolean gclue_wifi_should_skip_bsss (GClueAccuracyLevel level)
512
{
513
        return level < GCLUE_ACCURACY_LEVEL_STREET;
514
}
515
506
static gboolean
516
static gboolean
507
on_scan_wait_done (gpointer wifi)
517
on_scan_wait_done (gpointer wifi)
508
{
518
{
Lines 511-519 Link Here
511
        g_return_val_if_fail (GCLUE_IS_WIFI (wifi), G_SOURCE_REMOVE);
521
        g_return_val_if_fail (GCLUE_IS_WIFI (wifi), G_SOURCE_REMOVE);
512
        priv = GCLUE_WIFI(wifi)->priv;
522
        priv = GCLUE_WIFI(wifi)->priv;
513
523
524
        /* We have the latest scan result */
525
        gclue_mozilla_set_wifi (priv->mozilla, wifi);
526
514
        if (priv->bss_list_changed) {
527
        if (priv->bss_list_changed) {
515
                priv->bss_list_changed = FALSE;
528
                priv->bss_list_changed = FALSE;
516
                g_debug ("Refreshing location…");
529
                g_debug ("WiFi BSS list changed, refreshing location…");
530
                gclue_mozilla_set_bss_dirty (priv->mozilla);
517
                gclue_web_source_refresh (GCLUE_WEB_SOURCE (wifi));
531
                gclue_web_source_refresh (GCLUE_WEB_SOURCE (wifi));
518
        }
532
        }
519
        priv->scan_wait_id = 0;
533
        priv->scan_wait_id = 0;
Lines 521-526 Link Here
521
        return G_SOURCE_REMOVE;
535
        return G_SOURCE_REMOVE;
522
}
536
}
523
537
538
static GClueAccuracyLevel
539
get_accuracy_level (GClueWifi *wifi)
540
{
541
        GClueAccuracyLevel level;
542
543
        g_object_get (G_OBJECT (wifi), "accuracy-level", &level, NULL);
544
        return level;
545
}
546
524
static void
547
static void
525
on_scan_done (WPAInterface *object,
548
on_scan_done (WPAInterface *object,
526
              gboolean      success,
549
              gboolean      success,
Lines 535-541 Link Here
535
558
536
                return;
559
                return;
537
        }
560
        }
538
        g_debug ("WiFi scan completed");
539
561
540
        if (priv->interface == NULL)
562
        if (priv->interface == NULL)
541
                return;
563
                return;
Lines 558-571 Link Here
558
         * user's location can change quickly. With low accuracy, we don't since
580
         * user's location can change quickly. With low accuracy, we don't since
559
         * we wouldn't want to drain power unnecessarily.
581
         * we wouldn't want to drain power unnecessarily.
560
         */
582
         */
561
        if (priv->accuracy_level >= GCLUE_ACCURACY_LEVEL_STREET)
583
        if (get_accuracy_level (wifi) >= GCLUE_ACCURACY_LEVEL_STREET)
562
                timeout = WIFI_SCAN_TIMEOUT_HIGH_ACCURACY;
584
                timeout = WIFI_SCAN_TIMEOUT_HIGH_ACCURACY;
563
        else
585
        else
564
                timeout = WIFI_SCAN_TIMEOUT_LOW_ACCURACY;
586
                timeout = WIFI_SCAN_TIMEOUT_LOW_ACCURACY;
565
        priv->scan_timeout = g_timeout_add_seconds (timeout,
587
        priv->scan_timeout = g_timeout_add_seconds (timeout,
566
                                                    on_scan_timeout,
588
                                                    on_scan_timeout,
567
                                                    wifi);
589
                                                    wifi);
568
        g_debug ("Next scan scheduled in %u seconds", timeout);
590
        g_debug ("WiFi scan done, next scheduled in %u seconds", timeout);
569
}
591
}
570
592
571
static void
593
static void
Lines 573-592 Link Here
573
                   GAsyncResult *res,
595
                   GAsyncResult *res,
574
                   gpointer      user_data)
596
                   gpointer      user_data)
575
{
597
{
576
        GClueWifi *wifi = GCLUE_WIFI (user_data);
598
        g_autoptr(GError) error = NULL;
577
        GError *error = NULL;
578
599
579
        if (!wpa_interface_call_scan_finish
600
        if (!wpa_interface_call_scan_finish (WPA_INTERFACE (source_object),
580
                (WPA_INTERFACE (source_object),
601
                                             res, &error)) {
581
                 res,
602
                GClueWifi *wifi;
582
                 &error)) {
603
604
                if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
605
                        return;
606
                }
607
608
                wifi = GCLUE_WIFI (user_data);
609
610
                if (error) {
583
                g_warning ("Scanning of WiFi networks failed: %s",
611
                g_warning ("Scanning of WiFi networks failed: %s",
584
                           error->message);
612
                           error->message);
585
                g_error_free (error);
613
                }
586
614
587
                cancel_wifi_scan (wifi);
615
                cancel_wifi_scan (wifi);
588
589
                return;
590
        }
616
        }
591
}
617
}
592
618
Lines 605-610 Link Here
605
                return;
631
                return;
606
        }
632
        }
607
633
634
        g_assert (!priv->bss_cancellable);
635
        priv->bss_cancellable = g_cancellable_new ();
636
608
        start_wifi_scan (wifi);
637
        start_wifi_scan (wifi);
609
638
610
        priv->bss_list_changed = TRUE;
639
        priv->bss_list_changed = TRUE;
Lines 633-638 Link Here
633
{
662
{
634
        GClueWifiPrivate *priv = wifi->priv;
663
        GClueWifiPrivate *priv = wifi->priv;
635
664
665
        if (priv->bss_cancellable) {
666
                g_debug ("Cancelling WiFi requests");
667
                g_cancellable_cancel (priv->bss_cancellable);
668
                g_clear_object (&priv->bss_cancellable);
669
        }
670
636
        cancel_wifi_scan (wifi);
671
        cancel_wifi_scan (wifi);
637
672
638
        if (priv->bss_added_id != 0) {
673
        if (priv->bss_added_id != 0) {
Lines 657-678 Link Here
657
        GHashTableIter iter;
692
        GHashTableIter iter;
658
        gpointer value;
693
        gpointer value;
659
        guint64 cutoff_seconds;
694
        guint64 cutoff_seconds;
660
        guint old_cache_size;
695
        guint old_cache_size, removed_elements = 0;
661
696
662
        old_cache_size = g_hash_table_size (priv->location_cache);
697
        old_cache_size = g_hash_table_size (priv->location_cache);
663
        cutoff_seconds = g_get_real_time () / G_USEC_PER_SEC - CACHE_ENTRY_MAX_AGE_SECONDS;
698
        cutoff_seconds = g_get_real_time () / G_USEC_PER_SEC - CACHE_ENTRY_MAX_AGE_SECONDS;
664
699
665
        g_hash_table_iter_init (&iter, priv->location_cache);
700
        g_hash_table_iter_init (&iter, priv->location_cache);
666
        while (g_hash_table_iter_next (&iter, NULL, &value)) {
701
        while (g_hash_table_iter_next (&iter, NULL, &value)) {
667
                GClueLocation *location = GCLUE_LOCATION (value);
702
                LocationCacheValue *lcvalue = (LocationCacheValue *)value;
668
                guint64 timestamp_seconds = gclue_location_get_timestamp (location);
703
                GList *l = lcvalue->elements;
704
705
                g_assert (l);
706
                while (l) {
707
                        LocationCacheElement *element = (LocationCacheElement *)l->data;
708
                        GList *lnext = l->next;
709
710
                        /* Keep this location? */
711
                        if (gclue_location_get_timestamp (element->location) >
712
                            cutoff_seconds)
713
                                goto next_el;
714
715
                        location_cache_element_free (element);
716
                        lcvalue->elements = g_list_delete_link (lcvalue->elements, l);
717
                        removed_elements++;
669
718
670
                if (timestamp_seconds <= cutoff_seconds)
719
                        /* Deleted the last entry (element) in this hash bucket?
720
                         * Remove this hash table entry then.
721
                         */
722
                        if (!lcvalue->elements) {
723
                                g_assert (!lnext);
671
                        g_hash_table_iter_remove (&iter);
724
                        g_hash_table_iter_remove (&iter);
672
        }
725
        }
673
726
674
        g_debug ("Pruned cache (old size: %u, new size: %u)",
727
                next_el:
675
                 old_cache_size, g_hash_table_size (priv->location_cache));
728
                        l = lnext;
729
                }
730
        }
731
732
        g_debug ("Pruned cache (old size: %u, new size: %u, removed elements: %u)",
733
                 old_cache_size, g_hash_table_size (priv->location_cache),
734
                 removed_elements);
676
}
735
}
677
736
678
#if GLIB_CHECK_VERSION(2, 64, 0)
737
#if GLIB_CHECK_VERSION(2, 64, 0)
Lines 782-787 Link Here
782
static GClueLocationSourceStopResult
841
static GClueLocationSourceStopResult
783
gclue_wifi_stop (GClueLocationSource *source)
842
gclue_wifi_stop (GClueLocationSource *source)
784
{
843
{
844
        GClueWifi *wifi = GCLUE_WIFI (source);
845
        GClueWifiPrivate *priv = wifi->priv;
785
        GClueLocationSourceClass *base_class;
846
        GClueLocationSourceClass *base_class;
786
        GClueLocationSourceStopResult base_result;
847
        GClueLocationSourceStopResult base_result;
787
848
Lines 795-800 Link Here
795
        disconnect_bss_signals (GCLUE_WIFI (source));
856
        disconnect_bss_signals (GCLUE_WIFI (source));
796
        disconnect_cache_prune_timeout (GCLUE_WIFI (source));
857
        disconnect_cache_prune_timeout (GCLUE_WIFI (source));
797
858
859
        if (gclue_mozilla_test_set_wifi (priv->mozilla, wifi, NULL)) {
860
                g_debug ("Removed us as the WiFi source on stop");
861
        }
862
798
        return base_result;
863
        return base_result;
799
}
864
}
800
865
Lines 802-816 Link Here
802
gclue_wifi_get_available_accuracy_level (GClueWebSource *source,
867
gclue_wifi_get_available_accuracy_level (GClueWebSource *source,
803
                                         gboolean        net_available)
868
                                         gboolean        net_available)
804
{
869
{
805
        GClueWifiPrivate *priv = GCLUE_WIFI (source)->priv;
870
        GClueWifi *wifi = GCLUE_WIFI (source);
871
        GClueWifiPrivate *priv = wifi->priv;
806
872
807
        if (!net_available)
873
        if (!net_available)
808
                return GCLUE_ACCURACY_LEVEL_NONE;
874
                return GCLUE_ACCURACY_LEVEL_NONE;
809
        else if (priv->interface != NULL &&
875
        else if (!priv->interface)
810
                 priv->accuracy_level != GCLUE_ACCURACY_LEVEL_CITY)
811
                return GCLUE_ACCURACY_LEVEL_STREET;
812
        else
813
                return GCLUE_ACCURACY_LEVEL_CITY;
876
                return GCLUE_ACCURACY_LEVEL_CITY;
877
        else
878
                return MIN (get_accuracy_level (wifi), GCLUE_ACCURACY_LEVEL_STREET);
814
}
879
}
815
880
816
static void
881
static void
Lines 818-835 Link Here
818
                          GAsyncResult *res,
883
                          GAsyncResult *res,
819
                          gpointer      user_data)
884
                          gpointer      user_data)
820
{
885
{
821
        GClueWifi *wifi = GCLUE_WIFI (user_data);
886
        GClueWifi *wifi;
822
        WPAInterface *interface;
887
        WPAInterface *interface;
823
        GError *error = NULL;
888
        g_autoptr(GError) error = NULL;
824
889
825
        interface = wpa_interface_proxy_new_for_bus_finish (res, &error);
890
        interface = wpa_interface_proxy_new_for_bus_finish (res, &error);
826
        if (interface == NULL) {
891
        if (interface == NULL) {
827
                g_debug ("%s", error->message);
892
                if (error) {
828
                g_error_free (error);
893
                        if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
894
                                return;
895
                        }
896
897
                        g_warning ("Interface proxy add failed: %s",
898
                                   error->message);
899
                }
829
900
830
                return;
901
                return;
831
        }
902
        }
832
903
904
        wifi = GCLUE_WIFI (user_data);
833
        if (wifi->priv->interface != NULL) {
905
        if (wifi->priv->interface != NULL) {
834
                g_object_unref (interface);
906
                g_object_unref (interface);
835
                return;
907
                return;
Lines 860-866 Link Here
860
                                         G_DBUS_PROXY_FLAGS_NONE,
932
                                         G_DBUS_PROXY_FLAGS_NONE,
861
                                         "fi.w1.wpa_supplicant1",
933
                                         "fi.w1.wpa_supplicant1",
862
                                         path,
934
                                         path,
863
                                         NULL,
935
                                         wifi->priv->intf_cancellable,
864
                                         on_interface_proxy_ready,
936
                                         on_interface_proxy_ready,
865
                                         wifi);
937
                                         wifi);
866
}
938
}
Lines 888-901 Link Here
888
        disconnect_bss_signals (wifi);
960
        disconnect_bss_signals (wifi);
889
        g_clear_object (&wifi->priv->interface);
961
        g_clear_object (&wifi->priv->interface);
890
962
963
        if (gclue_mozilla_test_set_wifi (priv->mozilla, wifi, NULL)) {
964
                g_debug ("Removed interface was the WiFi source");
965
        }
966
891
        gclue_web_source_refresh (GCLUE_WEB_SOURCE (wifi));
967
        gclue_web_source_refresh (GCLUE_WEB_SOURCE (wifi));
892
}
968
}
893
969
894
static void
970
static void
895
gclue_wifi_init (GClueWifi *wifi)
971
gclue_wifi_init (GClueWifi *wifi)
896
{
972
{
973
        GClueWebSource *web_source = GCLUE_WEB_SOURCE (wifi);
974
897
        wifi->priv = gclue_wifi_get_instance_private (wifi);
975
        wifi->priv = gclue_wifi_get_instance_private (wifi);
898
976
977
        wifi->priv->intf_cancellable = g_cancellable_new ();
978
        wifi->priv->mozilla = gclue_mozilla_get_singleton ();
979
        gclue_web_source_set_locate_url (web_source,
980
                                         gclue_mozilla_get_locate_url (wifi->priv->mozilla));
981
        gclue_web_source_set_submit_url (web_source,
982
                                         gclue_mozilla_get_submit_url (wifi->priv->mozilla));
983
899
        wifi->priv->bss_proxies = g_hash_table_new_full (g_str_hash,
984
        wifi->priv->bss_proxies = g_hash_table_new_full (g_str_hash,
900
                                                         g_str_equal,
985
                                                         g_str_equal,
901
                                                         g_free,
986
                                                         g_free,
Lines 907-913 Link Here
907
        wifi->priv->location_cache = g_hash_table_new_full (variant_hash,
992
        wifi->priv->location_cache = g_hash_table_new_full (variant_hash,
908
                                                            g_variant_equal,
993
                                                            g_variant_equal,
909
                                                            (GDestroyNotify) g_variant_unref,
994
                                                            (GDestroyNotify) g_variant_unref,
910
                                                            g_object_unref);
995
                                                            location_cache_value_free);
911
}
996
}
912
997
913
static void
998
static void
Lines 916-926 Link Here
916
        GClueWifi *wifi = GCLUE_WIFI (object);
1001
        GClueWifi *wifi = GCLUE_WIFI (object);
917
        GClueWifiPrivate *priv = wifi->priv;
1002
        GClueWifiPrivate *priv = wifi->priv;
918
        const gchar *const *interfaces;
1003
        const gchar *const *interfaces;
919
        GError *error = NULL;
1004
        g_autoptr(GError) error = NULL;
920
1005
921
        G_OBJECT_CLASS (gclue_wifi_parent_class)->constructed (object);
1006
        G_OBJECT_CLASS (gclue_wifi_parent_class)->constructed (object);
922
1007
923
        if (wifi->priv->accuracy_level == GCLUE_ACCURACY_LEVEL_CITY) {
1008
        if (get_accuracy_level (wifi) == GCLUE_ACCURACY_LEVEL_CITY) {
924
                GClueConfig *config = gclue_config_get_singleton ();
1009
                GClueConfig *config = gclue_config_get_singleton ();
925
1010
926
                if (!gclue_config_get_enable_wifi_source (config))
1011
                if (!gclue_config_get_enable_wifi_source (config))
Lines 936-955 Link Here
936
                         NULL,
1021
                         NULL,
937
                         &error);
1022
                         &error);
938
        if (priv->supplicant == NULL) {
1023
        if (priv->supplicant == NULL) {
1024
                if (error)
939
                g_warning ("Failed to connect to wpa_supplicant service: %s",
1025
                g_warning ("Failed to connect to wpa_supplicant service: %s",
940
                           error->message);
1026
                           error->message);
941
                g_error_free (error);
942
                goto refresh_n_exit;
1027
                goto refresh_n_exit;
943
        }
1028
        }
944
1029
945
        g_signal_connect (priv->supplicant,
1030
        g_signal_connect_object (priv->supplicant,
946
                          "interface-added",
1031
                          "interface-added",
947
                          G_CALLBACK (on_interface_added),
1032
                          G_CALLBACK (on_interface_added),
948
                          wifi);
1033
                                 wifi, 0);
949
        g_signal_connect (priv->supplicant,
1034
        g_signal_connect_object (priv->supplicant,
950
                          "interface-removed",
1035
                          "interface-removed",
951
                          G_CALLBACK (on_interface_removed),
1036
                          G_CALLBACK (on_interface_removed),
952
                          wifi);
1037
                                 wifi, 0);
953
1038
954
        interfaces = wpa_supplicant_get_interfaces (priv->supplicant);
1039
        interfaces = wpa_supplicant_get_interfaces (priv->supplicant);
955
        if (interfaces != NULL && interfaces[0] != NULL)
1040
        if (interfaces != NULL && interfaces[0] != NULL)
Lines 982-1004 Link Here
982
GClueWifi *
1067
GClueWifi *
983
gclue_wifi_get_singleton (GClueAccuracyLevel level)
1068
gclue_wifi_get_singleton (GClueAccuracyLevel level)
984
{
1069
{
985
        static GClueWifi *wifi[] = { NULL, NULL };
1070
        static GClueWifi *wifi[] = { NULL, NULL, NULL };
986
        guint i;
1071
        guint i;
1072
        GClueConfig *config = gclue_config_get_singleton ();
1073
        gboolean wifi_enabled;
987
        gboolean scramble_location = FALSE;
1074
        gboolean scramble_location = FALSE;
988
        gboolean compute_movement = FALSE;
1075
        gboolean compute_movement = FALSE;
989
1076
990
        g_return_val_if_fail (level >= GCLUE_ACCURACY_LEVEL_CITY, NULL);
1077
        g_return_val_if_fail (level >= GCLUE_ACCURACY_LEVEL_CITY, NULL);
991
        if (level == GCLUE_ACCURACY_LEVEL_NEIGHBORHOOD)
992
                level = GCLUE_ACCURACY_LEVEL_CITY;
993
1078
1079
        wifi_enabled = gclue_config_get_enable_wifi_source (config);
994
        if (level == GCLUE_ACCURACY_LEVEL_CITY) {
1080
        if (level == GCLUE_ACCURACY_LEVEL_CITY) {
995
                GClueConfig *config = gclue_config_get_singleton ();
996
997
                i = 0;
1081
                i = 0;
998
                if (gclue_config_get_enable_wifi_source (config))
1082
                if (wifi_enabled)
999
                        scramble_location = TRUE;
1083
                        scramble_location = TRUE;
1000
        } else {
1084
        } else if (level == GCLUE_ACCURACY_LEVEL_NEIGHBORHOOD) {
1085
                g_return_val_if_fail (wifi_enabled, NULL);
1086
1001
                i = 1;
1087
                i = 1;
1088
                scramble_location = TRUE;
1089
        } else {
1090
                g_return_val_if_fail (wifi_enabled, NULL);
1091
1092
                i = 2;
1002
                compute_movement = TRUE;
1093
                compute_movement = TRUE;
1003
        }
1094
        }
1004
1095
Lines 1017-1054 Link Here
1017
        return wifi[i];
1108
        return wifi[i];
1018
}
1109
}
1019
1110
1020
GClueAccuracyLevel
1111
static gboolean
1021
gclue_wifi_get_accuracy_level (GClueWifi *wifi)
1112
wifi_should_skip_tower (GClueWifi *wifi)
1022
{
1113
{
1023
        g_return_val_if_fail (GCLUE_IS_WIFI (wifi),
1114
        return gclue_3g_should_skip_tower (get_accuracy_level (wifi));
1024
                              GCLUE_ACCURACY_LEVEL_NONE);
1025
1026
        return wifi->priv->accuracy_level;
1027
}
1115
}
1028
1116
1029
/* Can return NULL, signifying an empty BSS list. */
1117
/* Can return NULL, signifying an empty BSS list. */
1030
static GList *
1118
GList *
1031
get_bss_list (GClueWifi *wifi)
1119
gclue_wifi_get_bss_list (GClueWifi *wifi)
1032
{
1120
{
1033
        return g_hash_table_get_values (wifi->priv->bss_proxies);
1121
        return g_hash_table_get_values (wifi->priv->bss_proxies);
1034
}
1122
}
1035
1123
1036
static SoupMessage *
1124
static SoupMessage *
1037
gclue_wifi_create_query (GClueWebSource *source,
1125
gclue_wifi_create_query (GClueWebSource *source,
1126
                         const char **query_data_description,
1038
                         GError        **error)
1127
                         GError        **error)
1039
{
1128
{
1040
        GClueWifi *wifi = GCLUE_WIFI (source);
1129
        GClueWifi *wifi = GCLUE_WIFI (source);
1041
        GList *bss_list = NULL; /* As in Access Points */
1130
        gboolean skip_tower;
1042
        SoupMessage *msg;
1043
1131
1044
        if (wifi->priv->interface == NULL) {
1132
        if (wifi->priv->interface == NULL) {
1045
                goto create_query;
1133
                goto create_query;
1046
        }
1134
        }
1047
1135
1048
        bss_list = get_bss_list (wifi);
1049
1050
        /* Empty list? */
1136
        /* Empty list? */
1051
        if (bss_list == NULL) {
1137
        if (!g_hash_table_size (wifi->priv->bss_proxies)) {
1052
                g_set_error_literal (error,
1138
                g_set_error_literal (error,
1053
                                     G_IO_ERROR,
1139
                                     G_IO_ERROR,
1054
                                     G_IO_ERROR_FAILED,
1140
                                     G_IO_ERROR_FAILED,
Lines 1057-1073 Link Here
1057
        }
1143
        }
1058
1144
1059
create_query:
1145
create_query:
1060
        msg = gclue_mozilla_create_query (bss_list, NULL, error);
1146
        skip_tower = wifi_should_skip_tower (wifi);
1061
        g_list_free (bss_list);
1147
        if (skip_tower) {
1062
        return msg;
1148
                g_debug ("Will skip 3GPP tower in query due to our accuracy level");
1063
}
1149
}
1064
1150
1065
static GClueLocation *
1151
        return gclue_mozilla_create_query (wifi->priv->mozilla, skip_tower, FALSE,
1066
gclue_wifi_parse_response (GClueWebSource *source,
1152
                                           query_data_description, error);
1067
                           const char     *json,
1068
                           GError        **error)
1069
{
1070
        return gclue_mozilla_parse_response (json, error);
1071
}
1153
}
1072
1154
1073
static SoupMessage *
1155
static SoupMessage *
Lines 1076-1082 Link Here
1076
                                GError         **error)
1158
                                GError         **error)
1077
{
1159
{
1078
        GClueWifi *wifi = GCLUE_WIFI (source);
1160
        GClueWifi *wifi = GCLUE_WIFI (source);
1079
        GList *bss_list; /* As in Access Points */
1080
        SoupMessage * msg;
1161
        SoupMessage * msg;
1081
1162
1082
        if (wifi->priv->interface == NULL) {
1163
        if (wifi->priv->interface == NULL) {
Lines 1087-1096 Link Here
1087
                return NULL;
1168
                return NULL;
1088
        }
1169
        }
1089
1170
1090
        bss_list = get_bss_list (wifi);
1091
1092
        /* Empty list? */
1171
        /* Empty list? */
1093
        if (bss_list == NULL) {
1172
        if (!g_hash_table_size (wifi->priv->bss_proxies)) {
1094
                g_set_error_literal (error,
1173
                g_set_error_literal (error,
1095
                                     G_IO_ERROR,
1174
                                     G_IO_ERROR,
1096
                                     G_IO_ERROR_FAILED,
1175
                                     G_IO_ERROR_FAILED,
Lines 1098-1108 Link Here
1098
                return NULL;
1177
                return NULL;
1099
        }
1178
        }
1100
1179
1101
        msg = gclue_mozilla_create_submit_query (location,
1180
        msg = gclue_mozilla_create_submit_query (wifi->priv->mozilla,
1102
                                                 bss_list,
1181
                                                 location,
1103
                                                 NULL,
1104
                                                 error);
1182
                                                 error);
1105
        g_list_free (bss_list);
1106
        return msg;
1183
        return msg;
1107
}
1184
}
1108
1185
Lines 1145-1164 Link Here
1145
        return g_bytes_hash (bytes);
1222
        return g_bytes_hash (bytes);
1146
}
1223
}
1147
1224
1148
static GVariant *
1225
static void location_cache_key_fill_tower (GClueWifi *wifi, GClue3GTower *tower)
1149
get_location_cache_key (GClueWifi *wifi)
1226
{
1227
        GClueWifiPrivate *priv = wifi->priv;
1228
        GClue3GTower *moztower;
1229
1230
        memset (tower, 0, sizeof (*tower));
1231
        tower->tec = GCLUE_TOWER_TEC_NO_FIX;
1232
1233
        moztower = gclue_mozilla_get_tower (priv->mozilla);
1234
        if (!moztower || wifi_should_skip_tower (wifi)) {
1235
                return;
1236
        }
1237
1238
        g_assert (moztower->tec != GCLUE_TOWER_TEC_NO_FIX);
1239
        *tower = *moztower;
1240
}
1241
1242
static void location_cache_key_add_tower (GClueWifi *wifi, GVariantBuilder *builder)
1243
{
1244
        GClue3GTower tower;
1245
1246
        location_cache_key_fill_tower (wifi, &tower);
1247
        g_variant_builder_add (builder, "u", (guint32)tower.tec);
1248
        g_variant_builder_add (builder, "s", tower.opc);
1249
        g_variant_builder_add (builder, "t", (guint64)tower.lac);
1250
        g_variant_builder_add (builder, "t", (guint64)tower.cell_id);
1251
}
1252
1253
static GPtrArray *
1254
get_location_cache_bss_array (GClueWifi *wifi)
1150
{
1255
{
1151
        GHashTableIter iter;
1256
        GHashTableIter iter;
1152
        gpointer value;
1257
        gpointer value;
1153
        g_autoptr(GPtrArray) bss_array = g_ptr_array_new_with_free_func (NULL);  /* (element-type WPABSS) */
1258
        g_autoptr(GPtrArray) bss_array = g_ptr_array_new_with_free_func (NULL);  /* (element-type WPABSS) */
1154
        guint i;
1155
        GVariantBuilder builder;
1156
1259
1157
        /* The Mozilla service puts BSSID and signal strength for each BSS into
1260
        /* The Mozilla service puts BSSID and signal strength for each BSS into
1158
         * its query. The signal strength can typically vary by ±5 for a
1261
         * its query. Pack the whole lot into a #GVariant for simplicity, sorted
1159
         * stationary laptop, so quantise by that. Pack the whole lot into a
1262
         * by MAC address. The sorting has to happen in an array beforehand,
1160
         * #GVariant for simplicity, sorted by MAC address. The sorting has to
1263
         * as variants are immutable.
1161
         * happen in an array beforehand, as variants are immutable. */
1264
         */
1162
        g_hash_table_iter_init (&iter, wifi->priv->bss_proxies);
1265
        g_hash_table_iter_init (&iter, wifi->priv->bss_proxies);
1163
1266
1164
        while (g_hash_table_iter_next (&iter, NULL, &value)) {
1267
        while (g_hash_table_iter_next (&iter, NULL, &value)) {
Lines 1169-1207 Link Here
1169
1272
1170
        g_ptr_array_sort (bss_array, bss_compare);
1273
        g_ptr_array_sort (bss_array, bss_compare);
1171
1274
1275
        return g_steal_pointer (&bss_array);
1276
}
1277
1278
static GVariant *
1279
get_location_cache_hashtable_key (GClueWifi *wifi, GPtrArray *bss_array)
1280
{
1281
        guint i;
1282
        GVariantBuilder builder;
1283
1172
        /* Serialise to a variant. */
1284
        /* Serialise to a variant. */
1173
        g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(ayn)"));
1285
        g_variant_builder_init (&builder, G_VARIANT_TYPE ("(usttaay)"));
1286
        location_cache_key_add_tower (wifi, &builder);
1287
1288
        g_variant_builder_open (&builder, G_VARIANT_TYPE ("aay"));
1174
        for (i = 0; i < bss_array->len; i++) {
1289
        for (i = 0; i < bss_array->len; i++) {
1175
                WPABSS *bss = WPA_BSS (bss_array->pdata[i]);
1290
                WPABSS *bss = WPA_BSS (bss_array->pdata[i]);
1176
                GVariant *bssid;
1291
                GVariant *bssid;
1177
1292
1178
                g_variant_builder_open (&builder, G_VARIANT_TYPE ("(ayn)"));
1179
1180
                bssid = wpa_bss_get_bssid (bss);
1293
                bssid = wpa_bss_get_bssid (bss);
1181
                if (bssid == NULL)
1294
                if (bssid == NULL)
1182
                        continue;
1295
                        continue;
1183
1296
1184
                g_variant_builder_add_value (&builder, bssid);
1297
                g_variant_builder_add_value (&builder, bssid);
1185
                g_variant_builder_add (&builder, "n", wpa_bss_get_signal (bss) / 10);
1186
1187
                g_variant_builder_close (&builder);
1188
        }
1298
        }
1299
        g_variant_builder_close (&builder);
1189
1300
1190
        return g_variant_builder_end (&builder);
1301
        return g_variant_builder_end (&builder);
1191
}
1302
}
1192
1303
1304
static GArray *
1305
get_location_cache_signal_array (GClueWifi *wifi, GPtrArray *bss_array)
1306
{
1307
        g_autoptr(GArray) signal_array = NULL;
1308
        guint i;
1309
1310
        signal_array = g_array_sized_new (FALSE, FALSE, sizeof (gint16), bss_array->len);
1311
        for (i = 0; i < bss_array->len; i++) {
1312
                WPABSS *bss = WPA_BSS (bss_array->pdata[i]);
1313
                gint16 signal = wpa_bss_get_signal (bss);
1314
1315
                g_array_append_val (signal_array, signal);
1316
        }
1317
1318
        return g_steal_pointer (&signal_array);
1319
}
1320
1321
static gboolean cached_signals_match (GArray *signals1, GArray *signals2)
1322
{
1323
        guint i;
1324
1325
        if (signals1->len != signals2->len) {
1326
                g_warning ("Different signal count in one hash table entry: %u vs %u",
1327
                           signals1->len, signals2->len);
1328
                return FALSE;
1329
        }
1330
1331
        for (i = 0; i < signals1->len; i++) {
1332
                gint s1 = g_array_index (signals1, gint16, i);
1333
                gint s2 = g_array_index (signals2, gint16, i);
1334
1335
                if (ABS (s1 - s2) > CACHE_ENTRY_MATCH_SIGNAL_WINDOW / 2)
1336
                        return FALSE;
1337
        }
1338
1339
        return TRUE;
1340
}
1341
1193
static GClueLocation *
1342
static GClueLocation *
1194
duplicate_location_new_timestamp (GClueLocation *location)
1343
find_cached_location (GHashTable *cache, GVariant *key, GArray *signals)
1195
{
1344
{
1196
        return g_object_new (GCLUE_TYPE_LOCATION,
1345
        g_autofree gchar *key_str = g_variant_print (key, FALSE);
1197
                             "latitude", gclue_location_get_latitude (location),
1346
        GClueLocation *location = NULL;
1198
                             "longitude", gclue_location_get_longitude (location),
1347
        LocationCacheValue *value;
1199
                             "accuracy", gclue_location_get_accuracy (location),
1348
        GList *l;
1200
                             "altitude", gclue_location_get_altitude (location),
1349
1201
                             "timestamp", 0,
1350
        value = g_hash_table_lookup (cache, key);
1202
                             "speed", gclue_location_get_speed (location),
1351
        if (!value) {
1203
                             "heading", gclue_location_get_heading (location),
1352
                g_debug ("Cache miss for key %s", key_str);
1204
                             NULL);
1353
                return NULL;
1354
        }
1355
1356
        g_assert (value->elements);
1357
        for (l = value->elements; l; l = l->next) {
1358
                LocationCacheElement *element = l->data;
1359
1360
                if (location &&
1361
                    gclue_location_get_accuracy (element->location) >=
1362
                    gclue_location_get_accuracy (location)) {
1363
                        /* Have at least as accurate location already,
1364
                         * don't bother with comparing signals.
1365
                         */
1366
                        continue;
1367
                }
1368
1369
                if (!cached_signals_match (element->signals, signals))
1370
                        continue;
1371
1372
                location = element->location;
1373
        }
1374
1375
        if (location) {
1376
                g_debug ("Cache hit for key %s: got location %p (%s)",
1377
                         key_str, location,
1378
                         gclue_location_get_description (location));
1379
        } else {
1380
                g_debug ("Cache had key %s, but with different signals", key_str);
1381
        }
1382
1383
        return location;
1384
}
1385
1386
typedef struct {
1387
        GVariant *cache_key;
1388
        GArray *signals;
1389
} RefreshTaskData;
1390
1391
static RefreshTaskData *
1392
refresh_task_data_new (GVariant *cache_key,
1393
                       GArray *signals)
1394
{
1395
        RefreshTaskData *tdata;
1396
1397
        tdata = g_slice_new (RefreshTaskData);
1398
        tdata->cache_key = g_variant_ref (cache_key);
1399
        tdata->signals = signals;
1400
        return tdata;
1401
}
1402
1403
static void refresh_task_data_free (gpointer data)
1404
{
1405
        RefreshTaskData *rdata = data;
1406
1407
        g_clear_pointer (&rdata->cache_key, g_variant_unref);
1408
        if (rdata->signals)
1409
                g_array_free (rdata->signals, TRUE);
1410
        g_slice_free (RefreshTaskData, rdata);
1205
}
1411
}
1206
1412
1207
static void
1413
static void
Lines 1212-1251 Link Here
1212
{
1418
{
1213
        GClueWifi *wifi = GCLUE_WIFI (source);
1419
        GClueWifi *wifi = GCLUE_WIFI (source);
1214
        g_autoptr(GTask) task = g_task_new (source, cancellable, callback, user_data);
1420
        g_autoptr(GTask) task = g_task_new (source, cancellable, callback, user_data);
1215
        g_autoptr(GVariant) cache_key = get_location_cache_key (wifi);
1421
        g_autoptr(GPtrArray) bss_array = get_location_cache_bss_array (wifi);
1216
        g_autofree gchar *cache_key_str = g_variant_print (cache_key, FALSE);
1422
        g_autoptr(GVariant) cache_key = get_location_cache_hashtable_key (wifi, bss_array);
1217
        GClueLocation *cached_location = g_hash_table_lookup (wifi->priv->location_cache, cache_key);
1423
        g_autoptr(GArray) signal_array = get_location_cache_signal_array (wifi, bss_array);
1424
        GClueLocation *cached_location = find_cached_location (wifi->priv->location_cache,
1425
                                                               cache_key, signal_array);
1426
        RefreshTaskData *tdata;
1218
1427
1219
        g_task_set_source_tag (task, gclue_wifi_refresh_async);
1428
        g_task_set_source_tag (task, gclue_wifi_refresh_async);
1220
        g_task_set_task_data (task, g_steal_pointer (&cache_key), (GDestroyNotify) g_variant_unref);
1221
1429
1222
        if (gclue_location_source_get_active (GCLUE_LOCATION_SOURCE (source))) {
1430
        if (gclue_location_source_get_active (GCLUE_LOCATION_SOURCE (source))) {
1223
                /* Try the cache. */
1431
                /* Try the cache. */
1224
                if (cached_location != NULL) {
1432
                if (cached_location != NULL) {
1225
                        g_autoptr(GClueLocation) new_location = NULL;
1433
                        g_autoptr(GClueLocation) new_location = NULL;
1226
1434
1227
                        g_debug ("Cache hit for key %s: got location %p (%s)",
1228
                                 cache_key_str, cached_location,
1229
                                 gclue_location_get_description (cached_location));
1230
                        wifi->priv->cache_hits++;
1435
                        wifi->priv->cache_hits++;
1231
1436
1232
                        /* Duplicate the location so its timestamp is updated. */
1437
                        /* Duplicate the location so its timestamp is updated. */
1233
                        new_location = duplicate_location_new_timestamp (cached_location);
1438
                        new_location = gclue_location_duplicate_fresh (cached_location);
1234
                        gclue_location_source_set_location (GCLUE_LOCATION_SOURCE (source), new_location);
1439
                        gclue_location_source_set_location (GCLUE_LOCATION_SOURCE (source), new_location);
1235
1440
1236
                        g_task_return_pointer (task, g_steal_pointer (&new_location), g_object_unref);
1441
                        g_task_return_pointer (task, g_steal_pointer (&new_location), g_object_unref);
1237
                        return;
1442
                        return;
1238
                }
1443
                }
1239
1444
1240
                g_debug ("Cache miss for key %s; querying web service", cache_key_str);
1241
                wifi->priv->cache_misses++;
1445
                wifi->priv->cache_misses++;
1242
        }
1446
        }
1243
1447
1448
        tdata = refresh_task_data_new (cache_key, g_steal_pointer (&signal_array));
1449
        g_task_set_task_data (task, tdata, refresh_task_data_free);
1450
1244
        /* Fall back to querying the web service. */
1451
        /* Fall back to querying the web service. */
1245
        GCLUE_WEB_SOURCE_CLASS (gclue_wifi_parent_class)->refresh_async (source, cancellable, refresh_cb, g_steal_pointer (&task));
1452
        GCLUE_WEB_SOURCE_CLASS (gclue_wifi_parent_class)->refresh_async (source, cancellable, refresh_cb, g_steal_pointer (&task));
1246
}
1453
}
1247
1454
1248
static void
1455
static void
1456
add_cached_location (GHashTable *cache,
1457
                     GVariant *key, GArray **signals,
1458
                     GClueLocation *location)
1459
{
1460
        LocationCacheValue *value;
1461
        LocationCacheElement *element;
1462
1463
        value = g_hash_table_lookup (cache, key);
1464
        if (!value) {
1465
                value = location_cache_value_new ();
1466
                g_hash_table_insert (cache, g_variant_ref (key), value);
1467
        }
1468
1469
        element = location_cache_element_new (g_steal_pointer (signals), location);
1470
        value->elements = g_list_prepend (value->elements, element);
1471
}
1472
1473
static void
1249
refresh_cb (GObject      *source_object,
1474
refresh_cb (GObject      *source_object,
1250
            GAsyncResult *result,
1475
            GAsyncResult *result,
1251
            gpointer      user_data)
1476
            gpointer      user_data)
Lines 1255-1261 Link Here
1255
        g_autoptr(GTask) task = g_steal_pointer (&user_data);
1480
        g_autoptr(GTask) task = g_steal_pointer (&user_data);
1256
        g_autoptr(GClueLocation) location = NULL;
1481
        g_autoptr(GClueLocation) location = NULL;
1257
        g_autoptr(GError) local_error = NULL;
1482
        g_autoptr(GError) local_error = NULL;
1258
        GVariant *cache_key;
1483
        RefreshTaskData *tdata;
1259
        g_autofree gchar *cache_key_str = NULL;
1484
        g_autofree gchar *cache_key_str = NULL;
1260
        double cache_hit_ratio;
1485
        double cache_hit_ratio;
1261
1486
Lines 1268-1276 Link Here
1268
        }
1493
        }
1269
1494
1270
        /* Cache the result. */
1495
        /* Cache the result. */
1271
        cache_key = g_task_get_task_data (task);
1496
        tdata = g_task_get_task_data (task);
1272
        cache_key_str = g_variant_print (cache_key, FALSE);
1497
        cache_key_str = g_variant_print (tdata->cache_key, FALSE);
1273
        g_hash_table_replace (wifi->priv->location_cache, g_variant_ref (cache_key), g_object_ref (location));
1498
        add_cached_location (wifi->priv->location_cache,
1499
                             tdata->cache_key, &tdata->signals,
1500
                             location);
1274
1501
1275
        if (wifi->priv->cache_hits || wifi->priv->cache_misses) {
1502
        if (wifi->priv->cache_hits || wifi->priv->cache_misses) {
1276
                double cache_attempts;
1503
                double cache_attempts;
(-)geoclue-2.6.0/src/gclue-wifi.h (-1 / +2 lines)
Lines 63-69 Link Here
63
};
63
};
64
64
65
GClueWifi *        gclue_wifi_get_singleton      (GClueAccuracyLevel level);
65
GClueWifi *        gclue_wifi_get_singleton      (GClueAccuracyLevel level);
66
GClueAccuracyLevel gclue_wifi_get_accuracy_level (GClueWifi *wifi);
66
gboolean gclue_wifi_should_skip_bsss (GClueAccuracyLevel level);
67
GList *gclue_wifi_get_bss_list (GClueWifi *wifi);
67
68
68
G_END_DECLS
69
G_END_DECLS
69
70
(-)geoclue-2.6.0/src/meson.build (-2 / +3 lines)
Lines 1-5 Link Here
1
geoclue_deps = base_deps + [ dependency('json-glib-1.0', version: '>= 0.14.0'),
1
geoclue_deps = base_deps + [ dependency('json-glib-1.0', version: '>= 0.14.0'),
2
                             dependency('libsoup-2.4', version: '>= 2.42.0') ]
2
                             dependency('libsoup-3.0', version: '>= 3.0.0') ]
3
3
4
sources = [ libgeoclue_public_api_gen_sources[1],
4
sources = [ libgeoclue_public_api_gen_sources[1],
5
            geoclue_iface_sources,
5
            geoclue_iface_sources,
Lines 28-34 Link Here
28
             'gclue-wifi.h', 'gclue-wifi.c',
28
             'gclue-wifi.h', 'gclue-wifi.c',
29
             'gclue-mozilla.h', 'gclue-mozilla.c',
29
             'gclue-mozilla.h', 'gclue-mozilla.c',
30
             'gclue-min-uint.h', 'gclue-min-uint.c',
30
             'gclue-min-uint.h', 'gclue-min-uint.c',
31
             'gclue-location.h', 'gclue-location.c' ]
31
             'gclue-location.h', 'gclue-location.c',
32
             'gclue-utils.h' ]
32
33
33
if get_option('3g-source') or get_option('cdma-source') or get_option('modem-gps-source')
34
if get_option('3g-source') or get_option('cdma-source') or get_option('modem-gps-source')
34
    geoclue_deps += [ dependency('mm-glib', version: '>= 1.10') ]
35
    geoclue_deps += [ dependency('mm-glib', version: '>= 1.10') ]

Return to bug 880847