glib2.0/gio/tests/network-monitor.c

583 lines
19 KiB
C

/* GIO - GLib Input, Output and Streaming Library
*
* Copyright 2011 Red Hat, Inc.
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "gio.h"
/* hack */
#define GIO_COMPILATION
#include "gnetworkmonitorbase.h"
#include <string.h>
/* Test data; the GInetAddresses and GInetAddressMasks get filled in
* in main(). Each address in a TestAddress matches the mask in its
* corresponding TestMask, and none of them match any of the other
* masks. The addresses in unmatched don't match any of the masks.
*/
typedef struct {
const char *string;
GInetAddress *address;
} TestAddress;
typedef struct {
const char *mask_string;
GInetAddressMask *mask;
TestAddress *addresses;
} TestMask;
TestAddress net127addrs[] = {
{ "127.0.0.1", NULL },
{ "127.0.0.2", NULL },
{ "127.0.0.255", NULL },
{ "127.0.1.0", NULL },
{ "127.0.255.0", NULL },
{ "127.0.255.0", NULL },
{ "127.255.255.255", NULL },
{ NULL, NULL }
};
TestMask net127 = { "127.0.0.0/8", NULL, net127addrs };
TestAddress net10addrs[] = {
{ "10.0.0.1", NULL },
{ "10.0.0.2", NULL },
{ "10.0.0.255", NULL },
{ NULL, NULL }
};
TestMask net10 = { "10.0.0.0/24", NULL, net10addrs };
TestAddress net192addrs[] = {
{ "192.168.0.1", NULL },
{ "192.168.0.2", NULL },
{ "192.168.0.255", NULL },
{ "192.168.1.0", NULL },
{ "192.168.15.0", NULL },
{ NULL, NULL }
};
TestMask net192 = { "192.168.0.0/20", NULL, net192addrs };
TestAddress netlocal6addrs[] = {
{ "::1", NULL },
{ NULL, NULL }
};
TestMask netlocal6 = { "::1/128", NULL, netlocal6addrs };
TestAddress netfe80addrs[] = {
{ "fe80::", NULL },
{ "fe80::1", NULL },
{ "fe80::21b:77ff:fea2:972a", NULL },
{ NULL, NULL }
};
TestMask netfe80 = { "fe80::/64", NULL, netfe80addrs };
TestAddress unmatched[] = {
{ "10.0.1.0", NULL },
{ "10.0.255.0", NULL },
{ "10.255.255.255", NULL },
{ "192.168.16.0", NULL },
{ "192.168.255.0", NULL },
{ "192.169.0.0", NULL },
{ "192.255.255.255", NULL },
{ "::2", NULL },
{ "1::1", NULL },
{ "fe80::1:0:0:0:0", NULL },
{ "fe80:8000::0:0:0:0", NULL },
{ NULL, NULL }
};
GInetAddressMask *ip4_default, *ip6_default;
static void
notify_handler (GObject *object,
GParamSpec *pspec,
gpointer user_data)
{
gboolean *emitted = user_data;
*emitted = TRUE;
}
static void
network_changed_handler (GNetworkMonitor *monitor,
gboolean available,
gpointer user_data)
{
gboolean *emitted = user_data;
*emitted = TRUE;
}
static void
assert_signals (GNetworkMonitor *monitor,
gboolean should_emit_notify,
gboolean should_emit_network_changed,
gboolean expected_network_available)
{
gboolean emitted_notify = FALSE, emitted_network_changed = FALSE;
guint h1, h2;
h1 = g_signal_connect (monitor, "notify::network-available",
G_CALLBACK (notify_handler),
&emitted_notify);
h2 = g_signal_connect (monitor, "network-changed",
G_CALLBACK (network_changed_handler),
&emitted_network_changed);
g_main_context_iteration (NULL, FALSE);
g_signal_handler_disconnect (monitor, h1);
g_signal_handler_disconnect (monitor, h2);
g_assert (emitted_notify == should_emit_notify);
g_assert (emitted_network_changed == should_emit_network_changed);
g_assert (g_network_monitor_get_network_available (monitor) == expected_network_available);
}
typedef struct {
GNetworkMonitor *monitor;
GMainLoop *loop;
GSocketAddress *sockaddr;
gboolean should_be_reachable;
} CanReachData;
static void
reach_cb (GObject *source,
GAsyncResult *res,
gpointer user_data)
{
GError *error = NULL;
gboolean reachable;
CanReachData *data = user_data;
reachable = g_network_monitor_can_reach_finish (data->monitor, res, &error);
if (data->should_be_reachable)
g_assert_no_error (error);
else
{
g_assert (error != NULL);
g_clear_error (&error);
}
g_assert (reachable == data->should_be_reachable);
g_main_loop_quit (data->loop);
}
static gboolean
test_reach_async (gpointer user_data)
{
CanReachData *data = user_data;
g_network_monitor_can_reach_async (data->monitor,
G_SOCKET_CONNECTABLE (data->sockaddr),
NULL,
reach_cb,
data);
return G_SOURCE_REMOVE;
}
static void
run_tests (GNetworkMonitor *monitor,
TestAddress *addresses,
gboolean should_be_reachable)
{
GError *error = NULL;
int i;
gboolean reachable;
GSocketAddress *sockaddr;
CanReachData data;
data.monitor = monitor;
data.loop = g_main_loop_new (NULL, FALSE);
for (i = 0; addresses[i].address; i++)
{
sockaddr = g_inet_socket_address_new (addresses[i].address, 0);
reachable = g_network_monitor_can_reach (monitor,
G_SOCKET_CONNECTABLE (sockaddr),
NULL, &error);
data.sockaddr = sockaddr;
data.should_be_reachable = should_be_reachable;
g_idle_add (test_reach_async, &data);
g_main_loop_run (data.loop);
g_object_unref (sockaddr);
g_assert_cmpint (reachable, ==, should_be_reachable);
if (should_be_reachable)
g_assert_no_error (error);
else
{
g_assert (error != NULL);
g_clear_error (&error);
}
}
g_main_loop_unref (data.loop);
}
static void
test_default (void)
{
GNetworkMonitor *monitor, *m;
GError *error = NULL;
m = g_network_monitor_get_default ();
g_assert (G_IS_NETWORK_MONITOR (m));
monitor = g_object_new (G_TYPE_NETWORK_MONITOR_BASE, NULL);
g_initable_init (G_INITABLE (monitor), NULL, &error);
g_assert_no_error (error);
/* In the default configuration, all addresses are reachable */
run_tests (monitor, net127.addresses, TRUE);
run_tests (monitor, net10.addresses, TRUE);
run_tests (monitor, net192.addresses, TRUE);
run_tests (monitor, netlocal6.addresses, TRUE);
run_tests (monitor, netfe80.addresses, TRUE);
run_tests (monitor, unmatched, TRUE);
assert_signals (monitor, FALSE, FALSE, TRUE);
g_object_unref (monitor);
}
static void
test_remove_default (void)
{
GNetworkMonitor *monitor;
GError *error = NULL;
monitor = g_initable_new (G_TYPE_NETWORK_MONITOR_BASE, NULL, &error, NULL);
g_assert_no_error (error);
assert_signals (monitor, FALSE, FALSE, TRUE);
g_network_monitor_base_remove_network (G_NETWORK_MONITOR_BASE (monitor),
ip4_default);
assert_signals (monitor, FALSE, TRUE, TRUE);
g_network_monitor_base_remove_network (G_NETWORK_MONITOR_BASE (monitor),
ip6_default);
assert_signals (monitor, TRUE, TRUE, FALSE);
/* Now nothing should be reachable */
run_tests (monitor, net127.addresses, FALSE);
run_tests (monitor, net10.addresses, FALSE);
run_tests (monitor, net192.addresses, FALSE);
run_tests (monitor, netlocal6.addresses, FALSE);
run_tests (monitor, netfe80.addresses, FALSE);
run_tests (monitor, unmatched, FALSE);
g_object_unref (monitor);
}
static void
test_add_networks (void)
{
GNetworkMonitor *monitor;
GError *error = NULL;
monitor = g_initable_new (G_TYPE_NETWORK_MONITOR_BASE, NULL, &error, NULL);
g_assert_no_error (error);
assert_signals (monitor, FALSE, FALSE, TRUE);
g_network_monitor_base_remove_network (G_NETWORK_MONITOR_BASE (monitor),
ip4_default);
assert_signals (monitor, FALSE, TRUE, TRUE);
g_network_monitor_base_remove_network (G_NETWORK_MONITOR_BASE (monitor),
ip6_default);
assert_signals (monitor, TRUE, TRUE, FALSE);
/* Now add the masks one by one */
g_network_monitor_base_add_network (G_NETWORK_MONITOR_BASE (monitor),
net127.mask);
assert_signals (monitor, FALSE, TRUE, FALSE);
run_tests (monitor, net127.addresses, TRUE);
run_tests (monitor, net10.addresses, FALSE);
run_tests (monitor, net192.addresses, FALSE);
run_tests (monitor, netlocal6.addresses, FALSE);
run_tests (monitor, netfe80.addresses, FALSE);
run_tests (monitor, unmatched, FALSE);
g_network_monitor_base_add_network (G_NETWORK_MONITOR_BASE (monitor),
net10.mask);
assert_signals (monitor, FALSE, TRUE, FALSE);
run_tests (monitor, net127.addresses, TRUE);
run_tests (monitor, net10.addresses, TRUE);
run_tests (monitor, net192.addresses, FALSE);
run_tests (monitor, netlocal6.addresses, FALSE);
run_tests (monitor, netfe80.addresses, FALSE);
run_tests (monitor, unmatched, FALSE);
g_network_monitor_base_add_network (G_NETWORK_MONITOR_BASE (monitor),
net192.mask);
assert_signals (monitor, FALSE, TRUE, FALSE);
run_tests (monitor, net127.addresses, TRUE);
run_tests (monitor, net10.addresses, TRUE);
run_tests (monitor, net192.addresses, TRUE);
run_tests (monitor, netlocal6.addresses, FALSE);
run_tests (monitor, netfe80.addresses, FALSE);
run_tests (monitor, unmatched, FALSE);
g_network_monitor_base_add_network (G_NETWORK_MONITOR_BASE (monitor),
netlocal6.mask);
assert_signals (monitor, FALSE, TRUE, FALSE);
run_tests (monitor, net127.addresses, TRUE);
run_tests (monitor, net10.addresses, TRUE);
run_tests (monitor, net192.addresses, TRUE);
run_tests (monitor, netlocal6.addresses, TRUE);
run_tests (monitor, netfe80.addresses, FALSE);
run_tests (monitor, unmatched, FALSE);
g_network_monitor_base_add_network (G_NETWORK_MONITOR_BASE (monitor),
netfe80.mask);
assert_signals (monitor, FALSE, TRUE, FALSE);
run_tests (monitor, net127.addresses, TRUE);
run_tests (monitor, net10.addresses, TRUE);
run_tests (monitor, net192.addresses, TRUE);
run_tests (monitor, netlocal6.addresses, TRUE);
run_tests (monitor, netfe80.addresses, TRUE);
run_tests (monitor, unmatched, FALSE);
g_object_unref (monitor);
}
static void
test_remove_networks (void)
{
GNetworkMonitor *monitor;
GError *error = NULL;
monitor = g_initable_new (G_TYPE_NETWORK_MONITOR_BASE, NULL, &error, NULL);
g_assert_no_error (error);
assert_signals (monitor, FALSE, FALSE, TRUE);
g_network_monitor_base_remove_network (G_NETWORK_MONITOR_BASE (monitor),
ip4_default);
assert_signals (monitor, FALSE, TRUE, TRUE);
g_network_monitor_base_remove_network (G_NETWORK_MONITOR_BASE (monitor),
ip6_default);
assert_signals (monitor, TRUE, TRUE, FALSE);
/* First add them */
g_network_monitor_base_add_network (G_NETWORK_MONITOR_BASE (monitor),
net127.mask);
assert_signals (monitor, FALSE, TRUE, FALSE);
g_network_monitor_base_add_network (G_NETWORK_MONITOR_BASE (monitor),
net10.mask);
assert_signals (monitor, FALSE, TRUE, FALSE);
g_network_monitor_base_add_network (G_NETWORK_MONITOR_BASE (monitor),
net192.mask);
assert_signals (monitor, FALSE, TRUE, FALSE);
g_network_monitor_base_add_network (G_NETWORK_MONITOR_BASE (monitor),
netlocal6.mask);
assert_signals (monitor, FALSE, TRUE, FALSE);
g_network_monitor_base_add_network (G_NETWORK_MONITOR_BASE (monitor),
netfe80.mask);
assert_signals (monitor, FALSE, TRUE, FALSE);
run_tests (monitor, net127.addresses, TRUE);
run_tests (monitor, net10.addresses, TRUE);
run_tests (monitor, net192.addresses, TRUE);
run_tests (monitor, netlocal6.addresses, TRUE);
run_tests (monitor, netfe80.addresses, TRUE);
run_tests (monitor, unmatched, FALSE);
/* Now remove them one by one */
g_network_monitor_base_remove_network (G_NETWORK_MONITOR_BASE (monitor),
net127.mask);
assert_signals (monitor, FALSE, TRUE, FALSE);
run_tests (monitor, net127.addresses, FALSE);
run_tests (monitor, net10.addresses, TRUE);
run_tests (monitor, net192.addresses, TRUE);
run_tests (monitor, netlocal6.addresses, TRUE);
run_tests (monitor, netfe80.addresses, TRUE);
run_tests (monitor, unmatched, FALSE);
g_network_monitor_base_remove_network (G_NETWORK_MONITOR_BASE (monitor),
net10.mask);
assert_signals (monitor, FALSE, TRUE, FALSE);
run_tests (monitor, net127.addresses, FALSE);
run_tests (monitor, net10.addresses, FALSE);
run_tests (monitor, net192.addresses, TRUE);
run_tests (monitor, netlocal6.addresses, TRUE);
run_tests (monitor, netfe80.addresses, TRUE);
run_tests (monitor, unmatched, FALSE);
g_network_monitor_base_remove_network (G_NETWORK_MONITOR_BASE (monitor),
net192.mask);
assert_signals (monitor, FALSE, TRUE, FALSE);
run_tests (monitor, net127.addresses, FALSE);
run_tests (monitor, net10.addresses, FALSE);
run_tests (monitor, net192.addresses, FALSE);
run_tests (monitor, netlocal6.addresses, TRUE);
run_tests (monitor, netfe80.addresses, TRUE);
run_tests (monitor, unmatched, FALSE);
g_network_monitor_base_remove_network (G_NETWORK_MONITOR_BASE (monitor),
netlocal6.mask);
assert_signals (monitor, FALSE, TRUE, FALSE);
run_tests (monitor, net127.addresses, FALSE);
run_tests (monitor, net10.addresses, FALSE);
run_tests (monitor, net192.addresses, FALSE);
run_tests (monitor, netlocal6.addresses, FALSE);
run_tests (monitor, netfe80.addresses, TRUE);
run_tests (monitor, unmatched, FALSE);
g_network_monitor_base_remove_network (G_NETWORK_MONITOR_BASE (monitor),
netfe80.mask);
assert_signals (monitor, FALSE, TRUE, FALSE);
run_tests (monitor, net127.addresses, FALSE);
run_tests (monitor, net10.addresses, FALSE);
run_tests (monitor, net192.addresses, FALSE);
run_tests (monitor, netlocal6.addresses, FALSE);
run_tests (monitor, netfe80.addresses, FALSE);
run_tests (monitor, unmatched, FALSE);
g_object_unref (monitor);
}
static void
init_test (TestMask *test)
{
GError *error = NULL;
int i;
test->mask = g_inet_address_mask_new_from_string (test->mask_string, &error);
g_assert_no_error (error);
for (i = 0; test->addresses[i].string; i++)
{
test->addresses[i].address = g_inet_address_new_from_string (test->addresses[i].string);
if (strchr (test->addresses[i].string, ':'))
g_assert_cmpint (g_inet_address_get_family (test->addresses[i].address), ==, G_SOCKET_FAMILY_IPV6);
else
g_assert_cmpint (g_inet_address_get_family (test->addresses[i].address), ==, G_SOCKET_FAMILY_IPV4);
}
}
static void
cleanup_test (TestMask *test)
{
int i;
g_object_unref (test->mask);
for (i = 0; test->addresses[i].string; i++)
g_object_unref (test->addresses[i].address);
}
static void
watch_network_changed (GNetworkMonitor *monitor,
gboolean available,
gpointer user_data)
{
g_print ("Network is %s\n", available ? "up" : "down");
}
static void
watch_connectivity_changed (GNetworkMonitor *monitor,
GParamSpec *pspec,
gpointer user_data)
{
g_print ("Connectivity is %d\n", g_network_monitor_get_connectivity (monitor));
}
static void
watch_metered_changed (GNetworkMonitor *monitor,
GParamSpec *pspec,
gpointer user_data)
{
g_print ("Metered is %d\n", g_network_monitor_get_network_metered (monitor));
}
static void
do_watch_network (void)
{
GNetworkMonitor *monitor = g_network_monitor_get_default ();
GMainLoop *loop;
g_print ("Monitoring via %s\n", g_type_name_from_instance ((GTypeInstance *) monitor));
g_signal_connect (monitor, "network-changed",
G_CALLBACK (watch_network_changed), NULL);
g_signal_connect (monitor, "notify::connectivity",
G_CALLBACK (watch_connectivity_changed), NULL);
g_signal_connect (monitor, "notify::network-metered",
G_CALLBACK (watch_metered_changed), NULL);
watch_network_changed (monitor, g_network_monitor_get_network_available (monitor), NULL);
watch_connectivity_changed (monitor, NULL, NULL);
watch_metered_changed (monitor, NULL, NULL);
loop = g_main_loop_new (NULL, FALSE);
g_main_loop_run (loop);
}
int
main (int argc, char **argv)
{
int ret;
if (argc == 2 && !strcmp (argv[1], "--watch"))
{
do_watch_network ();
return 0;
}
g_test_init (&argc, &argv, NULL);
/* GNetworkMonitor will resolve addresses through a proxy if one is set and a
* GIO module is available to handle it. In these tests we deliberately
* change the idea of a reachable network to exclude the proxy, which will
* lead to negative results. We're not trying to test the proxy-resolving
* functionality (that would be for e.g. glib-networking's testsuite), so
* let's just use the dummy proxy resolver, which always pretends the
* passed-in URL is directly resolvable.
*/
g_setenv ("GIO_USE_PROXY_RESOLVER", "dummy", TRUE);
init_test (&net127);
init_test (&net10);
init_test (&net192);
init_test (&netlocal6);
init_test (&netfe80);
ip4_default = g_inet_address_mask_new_from_string ("0.0.0.0/0", NULL);
ip6_default = g_inet_address_mask_new_from_string ("::/0", NULL);
g_test_add_func ("/network-monitor/default", test_default);
g_test_add_func ("/network-monitor/remove_default", test_remove_default);
g_test_add_func ("/network-monitor/add_networks", test_add_networks);
g_test_add_func ("/network-monitor/remove_networks", test_remove_networks);
ret = g_test_run ();
cleanup_test (&net127);
cleanup_test (&net10);
cleanup_test (&net192);
cleanup_test (&netlocal6);
cleanup_test (&netfe80);
g_object_unref (ip4_default);
g_object_unref (ip6_default);
return ret;
}