1 | /* GIO - GLib Input, Output and Streaming Library |
2 | * |
3 | * Copyright 2011 Red Hat, Inc |
4 | * |
5 | * This library is free software; you can redistribute it and/or |
6 | * modify it under the terms of the GNU Lesser General Public |
7 | * License as published by the Free Software Foundation; either |
8 | * version 2.1 of the License, or (at your option) any later version. |
9 | * |
10 | * This library is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | * Lesser General Public License for more details. |
14 | * |
15 | * You should have received a copy of the GNU Lesser General |
16 | * Public License along with this library; if not, see <http://www.gnu.org/licenses/>. |
17 | */ |
18 | |
19 | #include "config.h" |
20 | #include "glib.h" |
21 | #include "glibintl.h" |
22 | |
23 | #include "gnetworkmonitor.h" |
24 | #include "ginetaddress.h" |
25 | #include "ginetsocketaddress.h" |
26 | #include "ginitable.h" |
27 | #include "gioenumtypes.h" |
28 | #include "giomodule-priv.h" |
29 | #include "gtask.h" |
30 | |
31 | /** |
32 | * SECTION:gnetworkmonitor |
33 | * @title: GNetworkMonitor |
34 | * @short_description: Network status monitor |
35 | * @include: gio/gio.h |
36 | * |
37 | * #GNetworkMonitor provides an easy-to-use cross-platform API |
38 | * for monitoring network connectivity. On Linux, the available |
39 | * implementations are based on the kernel's netlink interface and |
40 | * on NetworkManager. |
41 | * |
42 | * There is also an implementation for use inside Flatpak sandboxes. |
43 | */ |
44 | |
45 | /** |
46 | * GNetworkMonitor: |
47 | * |
48 | * #GNetworkMonitor monitors the status of network connections and |
49 | * indicates when a possibly-user-visible change has occurred. |
50 | * |
51 | * Since: 2.32 |
52 | */ |
53 | |
54 | /** |
55 | * GNetworkMonitorInterface: |
56 | * @g_iface: The parent interface. |
57 | * @network_changed: the virtual function pointer for the |
58 | * GNetworkMonitor::network-changed signal. |
59 | * @can_reach: the virtual function pointer for g_network_monitor_can_reach() |
60 | * @can_reach_async: the virtual function pointer for |
61 | * g_network_monitor_can_reach_async() |
62 | * @can_reach_finish: the virtual function pointer for |
63 | * g_network_monitor_can_reach_finish() |
64 | * |
65 | * The virtual function table for #GNetworkMonitor. |
66 | * |
67 | * Since: 2.32 |
68 | */ |
69 | |
70 | G_DEFINE_INTERFACE_WITH_CODE (GNetworkMonitor, g_network_monitor, G_TYPE_OBJECT, |
71 | g_type_interface_add_prerequisite (g_define_type_id, G_TYPE_INITABLE)) |
72 | |
73 | |
74 | enum { |
75 | NETWORK_CHANGED, |
76 | LAST_SIGNAL |
77 | }; |
78 | |
79 | static guint signals[LAST_SIGNAL] = { 0 }; |
80 | static GNetworkMonitor *network_monitor_default_singleton = NULL; /* (owned) (atomic) */ |
81 | |
82 | /** |
83 | * g_network_monitor_get_default: |
84 | * |
85 | * Gets the default #GNetworkMonitor for the system. |
86 | * |
87 | * Returns: (not nullable) (transfer none): a #GNetworkMonitor, which will be |
88 | * a dummy object if no network monitor is available |
89 | * |
90 | * Since: 2.32 |
91 | */ |
92 | GNetworkMonitor * |
93 | g_network_monitor_get_default (void) |
94 | { |
95 | if (g_once_init_enter (&network_monitor_default_singleton)) |
96 | { |
97 | GNetworkMonitor *singleton; |
98 | |
99 | singleton = _g_io_module_get_default (G_NETWORK_MONITOR_EXTENSION_POINT_NAME, |
100 | envvar: "GIO_USE_NETWORK_MONITOR" , |
101 | NULL); |
102 | |
103 | g_once_init_leave (&network_monitor_default_singleton, singleton); |
104 | } |
105 | |
106 | return network_monitor_default_singleton; |
107 | } |
108 | |
109 | /** |
110 | * g_network_monitor_get_network_available: |
111 | * @monitor: the #GNetworkMonitor |
112 | * |
113 | * Checks if the network is available. "Available" here means that the |
114 | * system has a default route available for at least one of IPv4 or |
115 | * IPv6. It does not necessarily imply that the public Internet is |
116 | * reachable. See #GNetworkMonitor:network-available for more details. |
117 | * |
118 | * Returns: whether the network is available |
119 | * |
120 | * Since: 2.32 |
121 | */ |
122 | gboolean |
123 | g_network_monitor_get_network_available (GNetworkMonitor *monitor) |
124 | { |
125 | gboolean available = FALSE; |
126 | |
127 | g_object_get (G_OBJECT (monitor), first_property_name: "network-available" , &available, NULL); |
128 | return available; |
129 | } |
130 | |
131 | /** |
132 | * g_network_monitor_get_network_metered: |
133 | * @monitor: the #GNetworkMonitor |
134 | * |
135 | * Checks if the network is metered. |
136 | * See #GNetworkMonitor:network-metered for more details. |
137 | * |
138 | * Returns: whether the connection is metered |
139 | * |
140 | * Since: 2.46 |
141 | */ |
142 | gboolean |
143 | g_network_monitor_get_network_metered (GNetworkMonitor *monitor) |
144 | { |
145 | gboolean metered = FALSE; |
146 | |
147 | g_object_get (G_OBJECT (monitor), first_property_name: "network-metered" , &metered, NULL); |
148 | return metered; |
149 | } |
150 | |
151 | /** |
152 | * g_network_monitor_get_connectivity: |
153 | * @monitor: the #GNetworkMonitor |
154 | * |
155 | * Gets a more detailed networking state than |
156 | * g_network_monitor_get_network_available(). |
157 | * |
158 | * If #GNetworkMonitor:network-available is %FALSE, then the |
159 | * connectivity state will be %G_NETWORK_CONNECTIVITY_LOCAL. |
160 | * |
161 | * If #GNetworkMonitor:network-available is %TRUE, then the |
162 | * connectivity state will be %G_NETWORK_CONNECTIVITY_FULL (if there |
163 | * is full Internet connectivity), %G_NETWORK_CONNECTIVITY_LIMITED (if |
164 | * the host has a default route, but appears to be unable to actually |
165 | * reach the full Internet), or %G_NETWORK_CONNECTIVITY_PORTAL (if the |
166 | * host is trapped behind a "captive portal" that requires some sort |
167 | * of login or acknowledgement before allowing full Internet access). |
168 | * |
169 | * Note that in the case of %G_NETWORK_CONNECTIVITY_LIMITED and |
170 | * %G_NETWORK_CONNECTIVITY_PORTAL, it is possible that some sites are |
171 | * reachable but others are not. In this case, applications can |
172 | * attempt to connect to remote servers, but should gracefully fall |
173 | * back to their "offline" behavior if the connection attempt fails. |
174 | * |
175 | * Return value: the network connectivity state |
176 | * |
177 | * Since: 2.44 |
178 | */ |
179 | GNetworkConnectivity |
180 | g_network_monitor_get_connectivity (GNetworkMonitor *monitor) |
181 | { |
182 | GNetworkConnectivity connectivity; |
183 | |
184 | g_object_get (G_OBJECT (monitor), first_property_name: "connectivity" , &connectivity, NULL); |
185 | |
186 | return connectivity; |
187 | } |
188 | |
189 | /** |
190 | * g_network_monitor_can_reach: |
191 | * @monitor: a #GNetworkMonitor |
192 | * @connectable: a #GSocketConnectable |
193 | * @cancellable: (nullable): a #GCancellable, or %NULL |
194 | * @error: return location for a #GError, or %NULL |
195 | * |
196 | * Attempts to determine whether or not the host pointed to by |
197 | * @connectable can be reached, without actually trying to connect to |
198 | * it. |
199 | * |
200 | * This may return %TRUE even when #GNetworkMonitor:network-available |
201 | * is %FALSE, if, for example, @monitor can determine that |
202 | * @connectable refers to a host on a local network. |
203 | * |
204 | * If @monitor believes that an attempt to connect to @connectable |
205 | * will succeed, it will return %TRUE. Otherwise, it will return |
206 | * %FALSE and set @error to an appropriate error (such as |
207 | * %G_IO_ERROR_HOST_UNREACHABLE). |
208 | * |
209 | * Note that although this does not attempt to connect to |
210 | * @connectable, it may still block for a brief period of time (eg, |
211 | * trying to do multicast DNS on the local network), so if you do not |
212 | * want to block, you should use g_network_monitor_can_reach_async(). |
213 | * |
214 | * Returns: %TRUE if @connectable is reachable, %FALSE if not. |
215 | * |
216 | * Since: 2.32 |
217 | */ |
218 | gboolean |
219 | g_network_monitor_can_reach (GNetworkMonitor *monitor, |
220 | GSocketConnectable *connectable, |
221 | GCancellable *cancellable, |
222 | GError **error) |
223 | { |
224 | GNetworkMonitorInterface *iface; |
225 | |
226 | iface = G_NETWORK_MONITOR_GET_INTERFACE (monitor); |
227 | return iface->can_reach (monitor, connectable, cancellable, error); |
228 | } |
229 | |
230 | static void |
231 | g_network_monitor_real_can_reach_async (GNetworkMonitor *monitor, |
232 | GSocketConnectable *connectable, |
233 | GCancellable *cancellable, |
234 | GAsyncReadyCallback callback, |
235 | gpointer user_data) |
236 | { |
237 | GTask *task; |
238 | GError *error = NULL; |
239 | |
240 | task = g_task_new (source_object: monitor, cancellable, callback, callback_data: user_data); |
241 | g_task_set_source_tag (task, g_network_monitor_real_can_reach_async); |
242 | |
243 | if (g_network_monitor_can_reach (monitor, connectable, cancellable, error: &error)) |
244 | g_task_return_boolean (task, TRUE); |
245 | else |
246 | g_task_return_error (task, error); |
247 | g_object_unref (object: task); |
248 | } |
249 | |
250 | /** |
251 | * g_network_monitor_can_reach_async: |
252 | * @monitor: a #GNetworkMonitor |
253 | * @connectable: a #GSocketConnectable |
254 | * @cancellable: (nullable): a #GCancellable, or %NULL |
255 | * @callback: (scope async): a #GAsyncReadyCallback to call when the |
256 | * request is satisfied |
257 | * @user_data: (closure): the data to pass to callback function |
258 | * |
259 | * Asynchronously attempts to determine whether or not the host |
260 | * pointed to by @connectable can be reached, without actually |
261 | * trying to connect to it. |
262 | * |
263 | * For more details, see g_network_monitor_can_reach(). |
264 | * |
265 | * When the operation is finished, @callback will be called. |
266 | * You can then call g_network_monitor_can_reach_finish() |
267 | * to get the result of the operation. |
268 | */ |
269 | void |
270 | g_network_monitor_can_reach_async (GNetworkMonitor *monitor, |
271 | GSocketConnectable *connectable, |
272 | GCancellable *cancellable, |
273 | GAsyncReadyCallback callback, |
274 | gpointer user_data) |
275 | { |
276 | GNetworkMonitorInterface *iface; |
277 | |
278 | iface = G_NETWORK_MONITOR_GET_INTERFACE (monitor); |
279 | iface->can_reach_async (monitor, connectable, cancellable, callback, user_data); |
280 | } |
281 | |
282 | static gboolean |
283 | g_network_monitor_real_can_reach_finish (GNetworkMonitor *monitor, |
284 | GAsyncResult *result, |
285 | GError **error) |
286 | { |
287 | g_return_val_if_fail (g_task_is_valid (result, monitor), FALSE); |
288 | |
289 | return g_task_propagate_boolean (G_TASK (result), error); |
290 | } |
291 | |
292 | /** |
293 | * g_network_monitor_can_reach_finish: |
294 | * @monitor: a #GNetworkMonitor |
295 | * @result: a #GAsyncResult |
296 | * @error: return location for errors, or %NULL |
297 | * |
298 | * Finishes an async network connectivity test. |
299 | * See g_network_monitor_can_reach_async(). |
300 | * |
301 | * Returns: %TRUE if network is reachable, %FALSE if not. |
302 | */ |
303 | gboolean |
304 | g_network_monitor_can_reach_finish (GNetworkMonitor *monitor, |
305 | GAsyncResult *result, |
306 | GError **error) |
307 | { |
308 | GNetworkMonitorInterface *iface; |
309 | |
310 | iface = G_NETWORK_MONITOR_GET_INTERFACE (monitor); |
311 | return iface->can_reach_finish (monitor, result, error); |
312 | } |
313 | |
314 | static void |
315 | g_network_monitor_default_init (GNetworkMonitorInterface *iface) |
316 | { |
317 | iface->can_reach_async = g_network_monitor_real_can_reach_async; |
318 | iface->can_reach_finish = g_network_monitor_real_can_reach_finish; |
319 | |
320 | /** |
321 | * GNetworkMonitor::network-changed: |
322 | * @monitor: a #GNetworkMonitor |
323 | * @network_available: the current value of #GNetworkMonitor:network-available |
324 | * |
325 | * Emitted when the network configuration changes. |
326 | * |
327 | * Since: 2.32 |
328 | */ |
329 | signals[NETWORK_CHANGED] = |
330 | g_signal_new (I_("network-changed" ), |
331 | G_TYPE_NETWORK_MONITOR, |
332 | signal_flags: G_SIGNAL_RUN_LAST, |
333 | G_STRUCT_OFFSET (GNetworkMonitorInterface, network_changed), |
334 | NULL, NULL, |
335 | NULL, |
336 | G_TYPE_NONE, n_params: 1, |
337 | G_TYPE_BOOLEAN); |
338 | |
339 | /** |
340 | * GNetworkMonitor:network-available: |
341 | * |
342 | * Whether the network is considered available. That is, whether the |
343 | * system has a default route for at least one of IPv4 or IPv6. |
344 | * |
345 | * Real-world networks are of course much more complicated than |
346 | * this; the machine may be connected to a wifi hotspot that |
347 | * requires payment before allowing traffic through, or may be |
348 | * connected to a functioning router that has lost its own upstream |
349 | * connectivity. Some hosts might only be accessible when a VPN is |
350 | * active. Other hosts might only be accessible when the VPN is |
351 | * not active. Thus, it is best to use g_network_monitor_can_reach() |
352 | * or g_network_monitor_can_reach_async() to test for reachability |
353 | * on a host-by-host basis. (On the other hand, when the property is |
354 | * %FALSE, the application can reasonably expect that no remote |
355 | * hosts at all are reachable, and should indicate this to the user |
356 | * in its UI.) |
357 | * |
358 | * See also #GNetworkMonitor::network-changed. |
359 | * |
360 | * Since: 2.32 |
361 | */ |
362 | g_object_interface_install_property (g_iface: iface, |
363 | pspec: g_param_spec_boolean (name: "network-available" , |
364 | P_("Network available" ), |
365 | P_("Whether the network is available" ), |
366 | FALSE, |
367 | flags: G_PARAM_READABLE | |
368 | G_PARAM_STATIC_STRINGS)); |
369 | |
370 | /** |
371 | * GNetworkMonitor:network-metered: |
372 | * |
373 | * Whether the network is considered metered. That is, whether the |
374 | * system has traffic flowing through the default connection that is |
375 | * subject to limitations set by service providers. For example, traffic |
376 | * might be billed by the amount of data transmitted, or there might be a |
377 | * quota on the amount of traffic per month. This is typical with tethered |
378 | * connections (3G and 4G) and in such situations, bandwidth intensive |
379 | * applications may wish to avoid network activity where possible if it will |
380 | * cost the user money or use up their limited quota. |
381 | * |
382 | * If more information is required about specific devices then the |
383 | * system network management API should be used instead (for example, |
384 | * NetworkManager or ConnMan). |
385 | * |
386 | * If this information is not available then no networks will be |
387 | * marked as metered. |
388 | * |
389 | * See also #GNetworkMonitor:network-available. |
390 | * |
391 | * Since: 2.46 |
392 | */ |
393 | g_object_interface_install_property (g_iface: iface, |
394 | pspec: g_param_spec_boolean (name: "network-metered" , |
395 | P_("Network metered" ), |
396 | P_("Whether the network is metered" ), |
397 | FALSE, |
398 | flags: G_PARAM_READABLE | |
399 | G_PARAM_STATIC_STRINGS)); |
400 | |
401 | /** |
402 | * GNetworkMonitor:connectivity: |
403 | * |
404 | * More detailed information about the host's network connectivity. |
405 | * See g_network_monitor_get_connectivity() and |
406 | * #GNetworkConnectivity for more details. |
407 | * |
408 | * Since: 2.44 |
409 | */ |
410 | g_object_interface_install_property (g_iface: iface, |
411 | pspec: g_param_spec_enum (name: "connectivity" , |
412 | P_("Network connectivity" ), |
413 | P_("Level of network connectivity" ), |
414 | enum_type: G_TYPE_NETWORK_CONNECTIVITY, |
415 | default_value: G_NETWORK_CONNECTIVITY_FULL, |
416 | flags: G_PARAM_READABLE | |
417 | G_PARAM_STATIC_STRINGS)); |
418 | } |
419 | |