2019-09-10 11:19:01 +02:00
|
|
|
// SPDX-License-Identifier: GPL-2.0+
|
2014-07-31 13:32:10 -04:00
|
|
|
/*
|
2019-10-01 09:20:35 +02:00
|
|
|
* Copyright (C) 2010 - 2015 Red Hat, Inc.
|
2014-07-31 13:32:10 -04:00
|
|
|
*/
|
|
|
|
|
|
2016-02-19 14:57:48 +01:00
|
|
|
#include "nm-default.h"
|
2014-11-13 10:07:02 -05:00
|
|
|
|
2018-05-06 08:51:26 +02:00
|
|
|
#include <sys/wait.h>
|
2014-07-31 13:32:10 -04:00
|
|
|
|
|
|
|
|
#include "NetworkManager.h"
|
2019-04-15 09:23:31 +02:00
|
|
|
#include "nm-std-aux/nm-dbus-compat.h"
|
2014-07-31 13:32:10 -04:00
|
|
|
|
2015-12-20 21:59:13 +01:00
|
|
|
#include "nm-test-libnm-utils.h"
|
2014-07-31 13:32:10 -04:00
|
|
|
|
2018-05-30 10:23:17 +02:00
|
|
|
#define NMTSTC_NM_SERVICE NM_BUILD_SRCDIR"/tools/test-networkmanager-service.py"
|
|
|
|
|
|
2015-12-23 14:07:36 +01:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2014-07-31 13:32:10 -04:00
|
|
|
static gboolean
|
|
|
|
|
name_exists (GDBusConnection *c, const char *name)
|
|
|
|
|
{
|
|
|
|
|
GVariant *reply;
|
|
|
|
|
gboolean exists = FALSE;
|
|
|
|
|
|
|
|
|
|
reply = g_dbus_connection_call_sync (c,
|
|
|
|
|
DBUS_SERVICE_DBUS,
|
|
|
|
|
DBUS_PATH_DBUS,
|
|
|
|
|
DBUS_INTERFACE_DBUS,
|
|
|
|
|
"GetNameOwner",
|
|
|
|
|
g_variant_new ("(s)", name),
|
|
|
|
|
NULL,
|
|
|
|
|
G_DBUS_CALL_FLAGS_NO_AUTO_START,
|
|
|
|
|
-1,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL);
|
|
|
|
|
if (reply != NULL) {
|
|
|
|
|
exists = TRUE;
|
|
|
|
|
g_variant_unref (reply);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return exists;
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-06 08:51:26 +02:00
|
|
|
typedef struct {
|
|
|
|
|
GMainLoop *mainloop;
|
|
|
|
|
GDBusConnection *bus;
|
|
|
|
|
int exit_code;
|
|
|
|
|
bool exited:1;
|
|
|
|
|
bool name_found:1;
|
|
|
|
|
} ServiceInitWaitData;
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
_service_init_wait_probe_name (gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
ServiceInitWaitData *data = user_data;
|
|
|
|
|
|
|
|
|
|
if (!name_exists (data->bus, "org.freedesktop.NetworkManager"))
|
|
|
|
|
return G_SOURCE_CONTINUE;
|
|
|
|
|
|
|
|
|
|
data->name_found = TRUE;
|
|
|
|
|
g_main_loop_quit (data->mainloop);
|
|
|
|
|
return G_SOURCE_REMOVE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
_service_init_wait_child_wait (GPid pid,
|
all: don't use gchar/gshort/gint/glong but C types
We commonly don't use the glib typedefs for char/short/int/long,
but their C types directly.
$ git grep '\<g\(char\|short\|int\|long\|float\|double\)\>' | wc -l
587
$ git grep '\<\(char\|short\|int\|long\|float\|double\)\>' | wc -l
21114
One could argue that using the glib typedefs is preferable in
public API (of our glib based libnm library) or where it clearly
is related to glib, like during
g_object_set (obj, PROPERTY, (gint) value, NULL);
However, that argument does not seem strong, because in practice we don't
follow that argument today, and seldomly use the glib typedefs.
Also, the style guide for this would be hard to formalize, because
"using them where clearly related to a glib" is a very loose suggestion.
Also note that glib typedefs will always just be typedefs of the
underlying C types. There is no danger of glib changing the meaning
of these typedefs (because that would be a major API break of glib).
A simple style guide is instead: don't use these typedefs.
No manual actions, I only ran the bash script:
FILES=($(git ls-files '*.[hc]'))
sed -i \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\>\( [^ ]\)/\1\2/g' \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\> /\1 /g' \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\>/\1/g' \
"${FILES[@]}"
2018-07-11 07:40:19 +02:00
|
|
|
int status,
|
2018-05-06 08:51:26 +02:00
|
|
|
gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
ServiceInitWaitData *data = user_data;
|
|
|
|
|
|
|
|
|
|
data->exited = TRUE;
|
|
|
|
|
data->exit_code = status;
|
|
|
|
|
g_main_loop_quit (data->mainloop);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NMTstcServiceInfo *
|
|
|
|
|
nmtstc_service_available (NMTstcServiceInfo *info)
|
|
|
|
|
{
|
|
|
|
|
gs_free char *m = NULL;
|
|
|
|
|
|
|
|
|
|
if (info)
|
|
|
|
|
return info;
|
|
|
|
|
|
|
|
|
|
/* This happens, when test-networkmanager-service.py exits with 77 status
|
|
|
|
|
* code. */
|
2018-05-30 10:23:17 +02:00
|
|
|
m = g_strdup_printf ("missing dependency for running NetworkManager stub service %s", NMTSTC_NM_SERVICE);
|
2018-05-06 08:51:26 +02:00
|
|
|
g_test_skip (m);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-21 10:22:33 +01:00
|
|
|
NMTstcServiceInfo *
|
|
|
|
|
nmtstc_service_init (void)
|
2014-07-31 13:32:10 -04:00
|
|
|
{
|
2015-12-21 10:22:33 +01:00
|
|
|
NMTstcServiceInfo *info;
|
2018-05-30 10:23:17 +02:00
|
|
|
const char *args[] = { TEST_NM_PYTHON, NMTSTC_NM_SERVICE, NULL };
|
2014-07-31 13:32:10 -04:00
|
|
|
GError *error = NULL;
|
|
|
|
|
|
|
|
|
|
info = g_malloc0 (sizeof (*info));
|
|
|
|
|
|
|
|
|
|
info->bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
|
|
|
|
|
g_assert_no_error (error);
|
|
|
|
|
|
2014-07-31 14:00:22 -04:00
|
|
|
/* Spawn the test service. info->keepalive_fd will be a pipe to the service's
|
|
|
|
|
* stdin; if it closes, the service will exit immediately. We use this to
|
|
|
|
|
* make sure the service exits if the test program crashes.
|
|
|
|
|
*/
|
2016-12-14 18:18:37 +01:00
|
|
|
g_spawn_async_with_pipes (NULL, (char **) args, NULL,
|
2018-05-06 08:51:26 +02:00
|
|
|
G_SPAWN_SEARCH_PATH
|
|
|
|
|
| G_SPAWN_DO_NOT_REAP_CHILD,
|
2016-12-14 18:18:37 +01:00
|
|
|
NULL, NULL,
|
2014-07-31 14:00:22 -04:00
|
|
|
&info->pid, &info->keepalive_fd, NULL, NULL, &error);
|
2014-07-31 13:32:10 -04:00
|
|
|
g_assert_no_error (error);
|
|
|
|
|
|
2018-05-06 08:51:26 +02:00
|
|
|
{
|
|
|
|
|
nm_auto_unref_gsource GSource *timeout_source = NULL;
|
|
|
|
|
nm_auto_unref_gsource GSource *child_source = NULL;
|
|
|
|
|
GMainContext *context = g_main_context_new ();
|
|
|
|
|
ServiceInitWaitData data = {
|
|
|
|
|
.bus = info->bus,
|
|
|
|
|
.mainloop = g_main_loop_new (context, FALSE),
|
|
|
|
|
};
|
|
|
|
|
gboolean had_timeout;
|
|
|
|
|
|
|
|
|
|
timeout_source = g_timeout_source_new (50);
|
|
|
|
|
g_source_set_callback (timeout_source, _service_init_wait_probe_name, &data, NULL);
|
|
|
|
|
g_source_attach (timeout_source, context);
|
|
|
|
|
|
|
|
|
|
child_source = g_child_watch_source_new (info->pid);
|
|
|
|
|
g_source_set_callback (child_source, (GSourceFunc)(void (*) (void)) _service_init_wait_child_wait, &data, NULL);
|
|
|
|
|
g_source_attach (child_source, context);
|
|
|
|
|
|
2018-07-05 03:53:35 +02:00
|
|
|
had_timeout = !nmtst_main_loop_run (data.mainloop, 30000);
|
2018-05-06 08:51:26 +02:00
|
|
|
|
|
|
|
|
g_source_destroy (timeout_source);
|
|
|
|
|
g_source_destroy (child_source);
|
|
|
|
|
g_main_loop_unref (data.mainloop);
|
|
|
|
|
g_main_context_unref (context);
|
|
|
|
|
|
|
|
|
|
if (had_timeout)
|
2018-05-30 10:23:17 +02:00
|
|
|
g_error ("test service %s did not start in time", NMTSTC_NM_SERVICE);
|
2018-05-06 08:51:26 +02:00
|
|
|
if (!data.name_found) {
|
|
|
|
|
g_assert (data.exited);
|
|
|
|
|
info->pid = NM_PID_T_INVAL;
|
|
|
|
|
nmtstc_service_cleanup (info);
|
|
|
|
|
|
|
|
|
|
if ( WIFEXITED (data.exit_code)
|
|
|
|
|
&& WEXITSTATUS (data.exit_code) == 77) {
|
|
|
|
|
/* If the stub service exited with status 77 it means that it decided
|
|
|
|
|
* that it cannot conduct the tests and the test should be (gracefully)
|
|
|
|
|
* skip. The likely reason for that, is that libnm is not available
|
|
|
|
|
* via pygobject. */
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2018-05-30 10:23:17 +02:00
|
|
|
g_error ("test service %s exited with error code %d", NMTSTC_NM_SERVICE, data.exit_code);
|
2018-05-06 08:51:26 +02:00
|
|
|
}
|
2014-07-31 13:32:10 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Grab a proxy to our fake NM service to trigger tests */
|
|
|
|
|
info->proxy = g_dbus_proxy_new_sync (info->bus,
|
|
|
|
|
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
|
|
|
|
|
G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS |
|
|
|
|
|
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
|
|
|
|
|
NULL,
|
|
|
|
|
NM_DBUS_SERVICE,
|
|
|
|
|
NM_DBUS_PATH,
|
|
|
|
|
"org.freedesktop.NetworkManager.LibnmGlibTest",
|
|
|
|
|
NULL, &error);
|
|
|
|
|
g_assert_no_error (error);
|
|
|
|
|
|
|
|
|
|
return info;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2015-12-21 10:22:33 +01:00
|
|
|
nmtstc_service_cleanup (NMTstcServiceInfo *info)
|
2014-07-31 13:32:10 -04:00
|
|
|
{
|
2018-05-06 08:51:26 +02:00
|
|
|
int ret;
|
|
|
|
|
gint64 t;
|
|
|
|
|
int status;
|
2014-07-31 13:32:10 -04:00
|
|
|
|
2018-05-06 08:51:26 +02:00
|
|
|
if (!info)
|
|
|
|
|
return;
|
2014-07-31 13:32:10 -04:00
|
|
|
|
2018-05-06 08:51:26 +02:00
|
|
|
nm_close (nm_steal_fd (&info->keepalive_fd));
|
2014-07-31 13:32:10 -04:00
|
|
|
|
2018-05-06 08:51:26 +02:00
|
|
|
g_clear_object (&info->proxy);
|
2014-07-31 13:32:10 -04:00
|
|
|
|
2018-05-06 08:51:26 +02:00
|
|
|
if (info->pid != NM_PID_T_INVAL) {
|
|
|
|
|
kill (info->pid, SIGTERM);
|
|
|
|
|
|
|
|
|
|
t = g_get_monotonic_time ();
|
|
|
|
|
again_wait:
|
|
|
|
|
ret = waitpid (info->pid, &status, WNOHANG);
|
|
|
|
|
if (ret == 0) {
|
|
|
|
|
if (t + 2000000 < g_get_monotonic_time ()) {
|
|
|
|
|
kill (info->pid, SIGKILL);
|
|
|
|
|
g_error ("child process %lld did not exit within timeout", (long long) info->pid);
|
|
|
|
|
}
|
|
|
|
|
g_usleep (G_USEC_PER_SEC / 50);
|
|
|
|
|
goto again_wait;
|
|
|
|
|
}
|
|
|
|
|
if (ret == -1 && errno == EINTR)
|
|
|
|
|
goto again_wait;
|
|
|
|
|
|
|
|
|
|
g_assert (ret == info->pid);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_assert (!name_exists (info->bus, "org.freedesktop.NetworkManager"));
|
|
|
|
|
|
|
|
|
|
g_clear_object (&info->bus);
|
|
|
|
|
|
2014-07-31 13:32:10 -04:00
|
|
|
memset (info, 0, sizeof (*info));
|
|
|
|
|
g_free (info);
|
|
|
|
|
}
|
2015-12-20 16:43:01 +01:00
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
|
GMainLoop *loop;
|
|
|
|
|
const char *ifname;
|
|
|
|
|
char *path;
|
|
|
|
|
NMDevice *device;
|
|
|
|
|
} AddDeviceInfo;
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
device_added_cb (NMClient *client,
|
|
|
|
|
NMDevice *device,
|
|
|
|
|
gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
AddDeviceInfo *info = user_data;
|
|
|
|
|
|
|
|
|
|
g_assert (device);
|
|
|
|
|
g_assert_cmpstr (nm_object_get_path (NM_OBJECT (device)), ==, info->path);
|
|
|
|
|
g_assert_cmpstr (nm_device_get_iface (device), ==, info->ifname);
|
|
|
|
|
|
|
|
|
|
info->device = device;
|
|
|
|
|
g_main_loop_quit (info->loop);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
timeout (gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
g_assert_not_reached ();
|
|
|
|
|
return G_SOURCE_REMOVE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static GVariant *
|
|
|
|
|
call_add_wired_device (GDBusProxy *proxy, const char *ifname, const char *hwaddr,
|
|
|
|
|
const char **subchannels, GError **error)
|
|
|
|
|
{
|
|
|
|
|
const char *empty[] = { NULL };
|
|
|
|
|
|
|
|
|
|
if (!hwaddr)
|
|
|
|
|
hwaddr = "/";
|
|
|
|
|
if (!subchannels)
|
|
|
|
|
subchannels = empty;
|
|
|
|
|
|
|
|
|
|
return g_dbus_proxy_call_sync (proxy,
|
|
|
|
|
"AddWiredDevice",
|
|
|
|
|
g_variant_new ("(ss^as)", ifname, hwaddr, subchannels),
|
|
|
|
|
G_DBUS_CALL_FLAGS_NO_AUTO_START,
|
|
|
|
|
3000,
|
|
|
|
|
NULL,
|
|
|
|
|
error);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static GVariant *
|
|
|
|
|
call_add_device (GDBusProxy *proxy, const char *method, const char *ifname, GError **error)
|
|
|
|
|
{
|
|
|
|
|
return g_dbus_proxy_call_sync (proxy,
|
2015-12-21 10:22:33 +01:00
|
|
|
method,
|
|
|
|
|
g_variant_new ("(s)", ifname),
|
|
|
|
|
G_DBUS_CALL_FLAGS_NO_AUTO_START,
|
|
|
|
|
3000,
|
|
|
|
|
NULL,
|
|
|
|
|
error);
|
2015-12-20 16:43:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static NMDevice *
|
2015-12-21 10:22:33 +01:00
|
|
|
add_device_common (NMTstcServiceInfo *sinfo, NMClient *client,
|
2015-12-20 16:43:01 +01:00
|
|
|
const char *method, const char *ifname,
|
|
|
|
|
const char *hwaddr, const char **subchannels)
|
|
|
|
|
{
|
|
|
|
|
AddDeviceInfo info;
|
|
|
|
|
GError *error = NULL;
|
|
|
|
|
GVariant *ret;
|
|
|
|
|
guint timeout_id;
|
|
|
|
|
|
|
|
|
|
if (g_strcmp0 (method, "AddWiredDevice") == 0)
|
|
|
|
|
ret = call_add_wired_device (sinfo->proxy, ifname, hwaddr, subchannels, &error);
|
|
|
|
|
else
|
|
|
|
|
ret = call_add_device (sinfo->proxy, method, ifname, &error);
|
|
|
|
|
|
|
|
|
|
g_assert_no_error (error);
|
|
|
|
|
g_assert (ret);
|
|
|
|
|
g_assert_cmpstr (g_variant_get_type_string (ret), ==, "(o)");
|
|
|
|
|
g_variant_get (ret, "(o)", &info.path);
|
|
|
|
|
g_variant_unref (ret);
|
|
|
|
|
|
|
|
|
|
/* Wait for libnm to find the device */
|
|
|
|
|
info.ifname = ifname;
|
|
|
|
|
info.loop = g_main_loop_new (NULL, FALSE);
|
|
|
|
|
g_signal_connect (client, "device-added",
|
|
|
|
|
G_CALLBACK (device_added_cb), &info);
|
|
|
|
|
timeout_id = g_timeout_add_seconds (5, timeout, NULL);
|
|
|
|
|
g_main_loop_run (info.loop);
|
|
|
|
|
|
|
|
|
|
g_source_remove (timeout_id);
|
|
|
|
|
g_signal_handlers_disconnect_by_func (client, device_added_cb, &info);
|
|
|
|
|
g_free (info.path);
|
|
|
|
|
g_main_loop_unref (info.loop);
|
|
|
|
|
|
|
|
|
|
return info.device;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NMDevice *
|
2015-12-21 10:22:33 +01:00
|
|
|
nmtstc_service_add_device (NMTstcServiceInfo *sinfo, NMClient *client,
|
|
|
|
|
const char *method, const char *ifname)
|
2015-12-20 16:43:01 +01:00
|
|
|
{
|
|
|
|
|
return add_device_common (sinfo, client, method, ifname, NULL, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NMDevice *
|
2015-12-21 10:22:33 +01:00
|
|
|
nmtstc_service_add_wired_device (NMTstcServiceInfo *sinfo, NMClient *client,
|
|
|
|
|
const char *ifname, const char *hwaddr,
|
|
|
|
|
const char **subchannels)
|
2015-12-20 16:43:01 +01:00
|
|
|
{
|
|
|
|
|
return add_device_common (sinfo, client, "AddWiredDevice", ifname, hwaddr, subchannels);
|
|
|
|
|
}
|
2015-12-22 13:53:20 +01:00
|
|
|
|
2015-12-25 20:27:45 +01:00
|
|
|
void
|
|
|
|
|
nmtstc_service_add_connection (NMTstcServiceInfo *sinfo,
|
|
|
|
|
NMConnection *connection,
|
|
|
|
|
gboolean verify_connection,
|
|
|
|
|
char **out_path)
|
|
|
|
|
{
|
|
|
|
|
nmtstc_service_add_connection_variant (sinfo,
|
|
|
|
|
nm_connection_to_dbus (connection, NM_CONNECTION_SERIALIZE_ALL),
|
|
|
|
|
verify_connection,
|
|
|
|
|
out_path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
nmtstc_service_add_connection_variant (NMTstcServiceInfo *sinfo,
|
|
|
|
|
GVariant *connection,
|
|
|
|
|
gboolean verify_connection,
|
|
|
|
|
char **out_path)
|
|
|
|
|
{
|
|
|
|
|
GVariant *result;
|
|
|
|
|
GError *error = NULL;
|
|
|
|
|
|
|
|
|
|
g_assert (sinfo);
|
|
|
|
|
g_assert (G_IS_DBUS_PROXY (sinfo->proxy));
|
|
|
|
|
g_assert (g_variant_is_of_type (connection, G_VARIANT_TYPE ("a{sa{sv}}")));
|
|
|
|
|
|
|
|
|
|
result = g_dbus_proxy_call_sync (sinfo->proxy,
|
|
|
|
|
"AddConnection",
|
|
|
|
|
g_variant_new ("(vb)", connection, verify_connection),
|
|
|
|
|
G_DBUS_CALL_FLAGS_NO_AUTO_START,
|
|
|
|
|
3000,
|
|
|
|
|
NULL,
|
|
|
|
|
&error);
|
|
|
|
|
g_assert_no_error (error);
|
|
|
|
|
g_assert (g_variant_is_of_type (result, G_VARIANT_TYPE ("(o)")));
|
|
|
|
|
if (out_path)
|
|
|
|
|
g_variant_get (result, "(o)", out_path);
|
|
|
|
|
g_variant_unref (result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
nmtstc_service_update_connection (NMTstcServiceInfo *sinfo,
|
|
|
|
|
const char *path,
|
|
|
|
|
NMConnection *connection,
|
|
|
|
|
gboolean verify_connection)
|
|
|
|
|
{
|
|
|
|
|
if (!path)
|
|
|
|
|
path = nm_connection_get_path (connection);
|
|
|
|
|
g_assert (path);
|
|
|
|
|
|
|
|
|
|
nmtstc_service_update_connection_variant (sinfo,
|
|
|
|
|
path,
|
|
|
|
|
nm_connection_to_dbus (connection, NM_CONNECTION_SERIALIZE_ALL),
|
|
|
|
|
verify_connection);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
nmtstc_service_update_connection_variant (NMTstcServiceInfo *sinfo,
|
|
|
|
|
const char *path,
|
|
|
|
|
GVariant *connection,
|
|
|
|
|
gboolean verify_connection)
|
|
|
|
|
{
|
|
|
|
|
GVariant *result;
|
|
|
|
|
GError *error = NULL;
|
|
|
|
|
|
|
|
|
|
g_assert (sinfo);
|
|
|
|
|
g_assert (G_IS_DBUS_PROXY (sinfo->proxy));
|
|
|
|
|
g_assert (g_variant_is_of_type (connection, G_VARIANT_TYPE ("a{sa{sv}}")));
|
|
|
|
|
g_assert (path && path[0] == '/');
|
|
|
|
|
|
|
|
|
|
result = g_dbus_proxy_call_sync (sinfo->proxy,
|
|
|
|
|
"UpdateConnection",
|
|
|
|
|
g_variant_new ("(ovb)", path, connection, verify_connection),
|
|
|
|
|
G_DBUS_CALL_FLAGS_NO_AUTO_START,
|
|
|
|
|
3000,
|
|
|
|
|
NULL,
|
|
|
|
|
&error);
|
|
|
|
|
g_assert_no_error (error);
|
|
|
|
|
g_assert (g_variant_is_of_type (result, G_VARIANT_TYPE ("()")));
|
|
|
|
|
g_variant_unref (result);
|
|
|
|
|
}
|
2019-11-02 14:15:48 +01:00
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
|
GMainLoop *loop;
|
|
|
|
|
NMClient *client;
|
|
|
|
|
} NMTstcClientNewData;
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
_nmtstc_client_new_cb (GObject *source_object,
|
|
|
|
|
GAsyncResult *res,
|
|
|
|
|
gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
NMTstcClientNewData *d = user_data;
|
|
|
|
|
gs_free_error GError *error = NULL;
|
|
|
|
|
|
|
|
|
|
g_assert (!d->client);
|
|
|
|
|
|
|
|
|
|
d->client = nm_client_new_finish (res,
|
|
|
|
|
nmtst_get_rand_bool () ? &error : NULL);
|
|
|
|
|
|
|
|
|
|
nmtst_assert_success (NM_IS_CLIENT (d->client), error);
|
|
|
|
|
|
|
|
|
|
g_main_loop_quit (d->loop);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static NMClient *
|
|
|
|
|
_nmtstc_client_new (gboolean sync)
|
|
|
|
|
{
|
|
|
|
|
gs_free GError *error = NULL;
|
|
|
|
|
NMClient *client;
|
|
|
|
|
|
|
|
|
|
/* Create a NMClient instance synchronously, and arbitrarily use either
|
|
|
|
|
* the sync or async constructor.
|
|
|
|
|
*
|
|
|
|
|
* Note that the sync and async construct differ in one important aspect:
|
|
|
|
|
* the async constructor iterates the current g_main_context_get_thread_default(),
|
|
|
|
|
* while the sync constructor does not! Aside from that, both should behave
|
|
|
|
|
* pretty much the same way. */
|
|
|
|
|
|
|
|
|
|
if (sync) {
|
|
|
|
|
nm_auto_destroy_and_unref_gsource GSource *source = NULL;
|
|
|
|
|
|
|
|
|
|
if (nmtst_get_rand_bool ()) {
|
|
|
|
|
/* the current main context must not be iterated! */
|
|
|
|
|
source = g_idle_source_new ();
|
|
|
|
|
g_source_set_callback (source, nmtst_g_source_assert_not_called, NULL, NULL);
|
|
|
|
|
g_source_attach (source, g_main_context_get_thread_default ());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (nmtst_get_rand_bool ()) {
|
|
|
|
|
gboolean success;
|
|
|
|
|
|
|
|
|
|
client = g_object_new (NM_TYPE_CLIENT, NULL);
|
|
|
|
|
g_assert (NM_IS_CLIENT (client));
|
|
|
|
|
|
|
|
|
|
success = g_initable_init (G_INITABLE (client),
|
|
|
|
|
NULL,
|
|
|
|
|
nmtst_get_rand_bool () ? &error : NULL);
|
|
|
|
|
nmtst_assert_success (success, error);
|
|
|
|
|
} else {
|
|
|
|
|
client = nm_client_new (NULL,
|
|
|
|
|
nmtst_get_rand_bool () ? &error : NULL);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
nm_auto_unref_gmainloop GMainLoop *loop = NULL;
|
|
|
|
|
NMTstcClientNewData d = { .loop = NULL, };
|
|
|
|
|
|
|
|
|
|
loop = g_main_loop_new (g_main_context_get_thread_default (), FALSE);
|
|
|
|
|
|
|
|
|
|
d.loop = loop;
|
|
|
|
|
nm_client_new_async (NULL,
|
|
|
|
|
_nmtstc_client_new_cb,
|
|
|
|
|
&d);
|
|
|
|
|
g_main_loop_run (loop);
|
|
|
|
|
g_assert (NM_IS_CLIENT (d.client));
|
|
|
|
|
client = d.client;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nmtst_assert_success (NM_IS_CLIENT (client), error);
|
|
|
|
|
return client;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
|
GMainLoop *loop;
|
|
|
|
|
NMClient *client;
|
|
|
|
|
bool sync;
|
|
|
|
|
} NewSyncInsideDispatchedData;
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
_nmtstc_client_new_inside_loop_do (gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
NewSyncInsideDispatchedData *d = user_data;
|
|
|
|
|
|
|
|
|
|
g_assert (d->loop);
|
|
|
|
|
g_assert (!d->client);
|
|
|
|
|
|
|
|
|
|
d->client = nmtstc_client_new (d->sync);
|
|
|
|
|
g_main_loop_quit (d->loop);
|
|
|
|
|
return G_SOURCE_CONTINUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static NMClient *
|
|
|
|
|
_nmtstc_client_new_inside_loop (gboolean sync)
|
|
|
|
|
{
|
|
|
|
|
GMainContext *context = g_main_context_get_thread_default ();
|
|
|
|
|
nm_auto_unref_gmainloop GMainLoop *loop = g_main_loop_new (context, FALSE);
|
|
|
|
|
NewSyncInsideDispatchedData d = {
|
|
|
|
|
.sync = sync,
|
|
|
|
|
.loop = loop,
|
|
|
|
|
};
|
|
|
|
|
nm_auto_destroy_and_unref_gsource GSource *source = NULL;
|
|
|
|
|
|
|
|
|
|
source = g_idle_source_new ();
|
|
|
|
|
g_source_set_callback (source, _nmtstc_client_new_inside_loop_do, &d, NULL);
|
|
|
|
|
g_source_attach (source, context);
|
|
|
|
|
|
|
|
|
|
g_main_loop_run (loop);
|
|
|
|
|
g_assert (NM_IS_CLIENT (d.client));
|
|
|
|
|
return d.client;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NMClient *
|
|
|
|
|
nmtstc_client_new (gboolean allow_iterate_main_context)
|
|
|
|
|
{
|
|
|
|
|
gboolean inside_loop;
|
|
|
|
|
gboolean sync;
|
|
|
|
|
|
|
|
|
|
if (!allow_iterate_main_context) {
|
|
|
|
|
sync = TRUE;
|
|
|
|
|
inside_loop = FALSE;
|
|
|
|
|
} else {
|
|
|
|
|
/* The caller allows to iterate the main context. That that point,
|
|
|
|
|
* we can both use the synchronous and the asynchronous initialization,
|
|
|
|
|
* both should yield the same result. Choose one randomly. */
|
|
|
|
|
sync = nmtst_get_rand_bool ();
|
|
|
|
|
inside_loop = ((nmtst_get_rand_uint32 () % 3) == 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (inside_loop) {
|
|
|
|
|
/* Create the client on an idle handler of the current context.
|
|
|
|
|
* In practice, it should make no difference, which this check
|
|
|
|
|
* tries to prove. */
|
|
|
|
|
return _nmtstc_client_new_inside_loop (sync);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return _nmtstc_client_new (sync);
|
|
|
|
|
}
|