From bbae86d3d2997a853ca0365e8eb7a3ca7489ee09 Mon Sep 17 00:00:00 2001 From: Sebastien Bacher Date: Fri, 25 Jan 2019 11:24:41 +0100 Subject: New upstream version 1.15.2 --- libnm/fake-typelib/meson.build | 6 +- libnm/generate-plugin-docs.pl | 2 +- libnm/libnm.ver | 9 ++ libnm/meson.build | 37 ++--- libnm/nm-active-connection.c | 7 +- libnm/nm-client.c | 151 +++++++++++++++++-- libnm/nm-client.h | 15 ++ libnm/nm-dbus-helpers.c | 2 +- libnm/nm-device-vxlan.c | 2 +- libnm/nm-device-wifi.c | 4 +- libnm/nm-device.c | 76 +++++++++- libnm/nm-device.h | 4 + libnm/nm-libnm-utils.c | 2 +- libnm/nm-manager.c | 144 ++++++++++++++---- libnm/nm-manager.h | 17 +++ libnm/nm-object.c | 2 +- libnm/nm-object.h | 2 +- libnm/nm-property-docs.xml | 22 +-- libnm/nm-settings-docs-overrides.xml | 4 +- libnm/nm-settings-docs.xml | 26 ++-- libnm/nm-settings-ifcfg-rh-docs.xml | 2 +- libnm/nm-vpn-service-plugin.c | 80 +++++++--- libnm/tests/meson.build | 7 +- libnm/tests/test-general.c | 274 +++++++++++++++++++++++++++++++++++ 24 files changed, 776 insertions(+), 121 deletions(-) (limited to 'libnm') diff --git a/libnm/fake-typelib/meson.build b/libnm/fake-typelib/meson.build index c0a779a2..cafe013a 100644 --- a/libnm/fake-typelib/meson.build +++ b/libnm/fake-typelib/meson.build @@ -2,7 +2,7 @@ g_ir_compiler = find_program('g-ir-compiler') girs = [ 'NetworkManager', - 'NMClient' + 'NMClient', ] resource_data = [] @@ -14,7 +14,7 @@ foreach gir: girs gir_typelib, input: gir + '.gir', output: gir_typelib, - command: [g_ir_compiler, '@INPUT@', '-o', '@OUTPUT@'] + command: [g_ir_compiler, '@INPUT@', '-o', '@OUTPUT@'], ) endforeach @@ -26,5 +26,5 @@ sources += gnome.compile_resources( source_dir: '.', dependencies: resource_data, extra_args: '--manual-register', - export: true + export: true, ) diff --git a/libnm/generate-plugin-docs.pl b/libnm/generate-plugin-docs.pl index e4963b7c..74e2126c 100755 --- a/libnm/generate-plugin-docs.pl +++ b/libnm/generate-plugin-docs.pl @@ -60,7 +60,7 @@ open $fo, '>', $output or die "Can't open $output: $!"; # write XML header write_header(); -# write generated documenation for each setting +# write generated documentation for each setting foreach my $c_file (@source_files) { my $setting_name = get_setting_name($c_file); if ($setting_name) { diff --git a/libnm/libnm.ver b/libnm/libnm.ver index 1f76dc0f..652e01eb 100644 --- a/libnm/libnm.ver +++ b/libnm/libnm.ver @@ -1444,3 +1444,12 @@ global: nm_utils_sriov_vf_from_str; nm_utils_sriov_vf_to_str; } libnm_1_12_0; + +libnm_1_16_0 { +global: + nm_client_add_and_activate_connection2; + nm_client_add_and_activate_connection2_finish; + nm_device_get_connectivity; + nm_team_link_watcher_get_vlanid; + nm_team_link_watcher_new_arp_ping2; +} libnm_1_14_0; diff --git a/libnm/meson.build b/libnm/meson.build index 62e3e9d7..2e44a6a4 100644 --- a/libnm/meson.build +++ b/libnm/meson.build @@ -4,7 +4,7 @@ sources = files('nm-libnm-utils.c') deps = [ libnmdbus_dep, - shared_dep + shared_dep, ] cflags = [ @@ -22,7 +22,7 @@ libnm_utils = static_library( sources: sources, include_directories: libnm_core_inc, dependencies: deps, - c_args: cflags + c_args: cflags, ) libnm_headers = files( @@ -69,12 +69,12 @@ libnm_headers = files( 'nm-vpn-editor.h', 'nm-vpn-plugin-old.h', 'nm-vpn-service-plugin.h', - 'nm-wimax-nsp.h' + 'nm-wimax-nsp.h', ) install_headers( libnm_core_headers + libnm_headers + [version_header], - subdir: libnm_name + subdir: libnm_name, ) enum_headers = libnm_headers + [version_header] @@ -87,7 +87,7 @@ libnm_enum = gnome.mkenums( c_template: enum_types + '.c.template', h_template: enum_types + '.h.template', install_header: true, - install_dir: libnm_pkgincludedir + install_dir: libnm_pkgincludedir, ) libnm_sources = files( @@ -139,14 +139,15 @@ libnm_sources = files( 'nm-vpn-plugin-old.c', 'nm-vpn-editor.c', 'nm-vpn-service-plugin.c', - 'nm-wimax-nsp.c' + 'nm-wimax-nsp.c', ) deps = [ dl_dep, libudev_dep, shared_dep, - uuid_dep + uuid_dep, + libnm_systemd_shared_no_logging_dep, ] linker_script = join_paths(meson.current_source_dir(), 'libnm.ver') @@ -165,13 +166,13 @@ libnm = shared_library( '-Wl,--version-script,@0@'.format(linker_script), ], link_depends: linker_script, - install: true + install: true, ) libnm_dep = declare_dependency( sources: libnm_enum[1], include_directories: libnm_inc, - link_with: libnm + link_with: libnm, ) pkg.generate( @@ -184,8 +185,8 @@ pkg.generate( requires: 'gio-2.0', variables: [ 'exec_prefix=${prefix}', - 'vpnservicedir=' + join_paths(nm_pkglibdir, 'VPN') - ] + 'vpnservicedir=' + join_paths('${prefix}', 'lib', nm_name, 'VPN'), + ], ) test( @@ -208,7 +209,7 @@ if enable_introspection includes: 'Gio-2.0', extra_args: cflags, header: 'NetworkManager.h', - install: true + install: true, ) generate_plugin_docs = join_paths(meson.current_source_dir(), 'generate-plugin-docs.pl') @@ -218,7 +219,7 @@ if enable_introspection name, input: libnm_core_settings_sources, output: name, - command: [perl, generate_plugin_docs, 'keyfile', '@OUTPUT@', '@INPUT@'] + command: [perl, generate_plugin_docs, 'keyfile', '@OUTPUT@', '@INPUT@'], ) name = 'nm-settings-docs-overrides.xml' @@ -226,7 +227,7 @@ if enable_introspection name, input: libnm_core_settings_sources, output: name, - command: [perl, generate_plugin_docs, 'dbus', '@OUTPUT@', '@INPUT@'] + command: [perl, generate_plugin_docs, 'dbus', '@OUTPUT@', '@INPUT@'], ) if enable_ifcfg_rh @@ -235,7 +236,7 @@ if enable_introspection name, input: libnm_core_settings_sources, output: name, - command: [perl, generate_plugin_docs, 'ifcfg-rh', '@OUTPUT@', '@INPUT@'] + command: [perl, generate_plugin_docs, 'ifcfg-rh', '@OUTPUT@', '@INPUT@'], ) endif @@ -256,7 +257,7 @@ if enable_introspection generate_setting_docs_env = [ 'env', '-i', 'GI_TYPELIB_PATH=' + gi_typelib_path, - 'LD_LIBRARY_PATH=' + ld_library_path + 'LD_LIBRARY_PATH=' + ld_library_path, ] name = 'nm-property-docs.xml' @@ -265,7 +266,7 @@ if enable_introspection input: libnm_gir[0], output: name, command: [generate_setting_docs_env, generate_setting_docs, '--lib-path', meson.current_build_dir(), '--gir', '@INPUT@', '--output', '@OUTPUT@'], - depends: libnm_gir + depends: libnm_gir, ) name = 'nm-settings-docs.xml' @@ -274,7 +275,7 @@ if enable_introspection input: libnm_gir[0], output: name, command: [generate_setting_docs_env, generate_setting_docs, '--lib-path', meson.current_build_dir(), '--gir', '@INPUT@', '--overrides', nm_settings_docs_overrides, '--output', '@OUTPUT@'], - depends: libnm_gir + depends: libnm_gir, ) endif diff --git a/libnm/nm-active-connection.c b/libnm/nm-active-connection.c index 0314667f..5b238b3b 100644 --- a/libnm/nm-active-connection.c +++ b/libnm/nm-active-connection.c @@ -795,7 +795,12 @@ nm_active_connection_class_init (NMActiveConnectionClass *ap_class) G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); - /* signals */ + /** + * NMActiveConnection::state-changed: + * @active_connection: the source #NMActiveConnection + * @state: the new state number (#NMActiveConnectionState) + * @reason: the state change reason (#NMActiveConnectionStateReason) + */ signals[STATE_CHANGED] = g_signal_new ("state-changed", G_OBJECT_CLASS_TYPE (object_class), diff --git a/libnm/nm-client.c b/libnm/nm-client.c index 1da22540..e2522229 100644 --- a/libnm/nm-client.c +++ b/libnm/nm-client.c @@ -1163,18 +1163,20 @@ add_activate_cb (GObject *object, GAsyncResult *result, gpointer user_data) { - GSimpleAsyncResult *simple = user_data; + gs_unref_object GSimpleAsyncResult *simple = user_data; + gs_unref_variant GVariant *result_data = NULL; NMActiveConnection *ac; GError *error = NULL; - ac = nm_manager_add_and_activate_connection_finish (NM_MANAGER (object), result, &error); - if (ac) - g_simple_async_result_set_op_res_gpointer (simple, ac, g_object_unref); - else + ac = nm_manager_add_and_activate_connection_finish (NM_MANAGER (object), result, &result_data, &error); + if (ac) { + g_simple_async_result_set_op_res_gpointer (simple, + _nm_activate_result_new (ac, result_data), + (GDestroyNotify) _nm_activate_result_free); + } else g_simple_async_result_take_error (simple, error); g_simple_async_result_complete (simple); - g_object_unref (simple); } /** @@ -1233,8 +1235,14 @@ nm_client_add_and_activate_connection_async (NMClient *client, if (cancellable) g_simple_async_result_set_check_cancellable (simple, cancellable); nm_manager_add_and_activate_connection_async (NM_CLIENT_GET_PRIVATE (client)->manager, - partial, device, specific_object, - cancellable, add_activate_cb, simple); + partial, + device, + specific_object, + NULL, + FALSE, + cancellable, + add_activate_cb, + simple); } /** @@ -1257,6 +1265,7 @@ nm_client_add_and_activate_connection_finish (NMClient *client, GError **error) { GSimpleAsyncResult *simple; + _NMActivateResult *r; g_return_val_if_fail (NM_IS_CLIENT (client), NULL); g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), NULL); @@ -1264,8 +1273,128 @@ nm_client_add_and_activate_connection_finish (NMClient *client, simple = G_SIMPLE_ASYNC_RESULT (result); if (g_simple_async_result_propagate_error (simple, error)) return NULL; - else - return g_object_ref (g_simple_async_result_get_op_res_gpointer (simple)); + r = g_simple_async_result_get_op_res_gpointer (simple); + return g_object_ref (r->active); +} + +/** + * nm_client_add_and_activate_connection2: + * @client: a #NMClient + * @partial: (allow-none): an #NMConnection to add; the connection may be + * partially filled (or even %NULL) and will be completed by NetworkManager + * using the given @device and @specific_object before being added + * @device: the #NMDevice + * @specific_object: (allow-none): the object path of a connection-type-specific + * object this activation should use. This parameter is currently ignored for + * wired and mobile broadband connections, and the value of %NULL should be used + * (ie, no specific object). For Wi-Fi or WiMAX connections, pass the object + * path of a #NMAccessPoint or #NMWimaxNsp owned by @device, which you can + * get using nm_object_get_path(), and which will be used to complete the + * details of the newly added connection. + * @options: a #GVariant containing a dictionary with options, or %NULL + * @cancellable: a #GCancellable, or %NULL + * @callback: callback to be called when the activation has started + * @user_data: caller-specific data passed to @callback + * + * Adds a new connection using the given details (if any) as a template, + * automatically filling in missing settings with the capabilities of the given + * device and specific object. The new connection is then asynchronously + * activated as with nm_client_activate_connection_async(). Cannot be used for + * VPN connections at this time. + * + * Note that the callback is invoked when NetworkManager has started activating + * the new connection, not when it finishes. You can used the returned + * #NMActiveConnection object (in particular, #NMActiveConnection:state) to + * track the activation to its completion. + * + * This is identitcal to nm_client_add_and_activate_connection_async() but takes + * a further @options parameter. Currently the following options are supported + * by the daemon: + * * "persist": A string describing how the connection should be stored. + * The default is "disk", but it can be modified to "memory" (until + * the daemon quits) or "volatile" (will be deleted on disconnect). + * * "bind-activation": Bind the connection lifetime to something. The default is "none", + * meaning an explicit disconnect is needed. The value "dbus-client" + * means the connection will automatically be deactivated when the calling + * DBus client disappears from the system bus. + * + * Since: 1.16 + **/ +void +nm_client_add_and_activate_connection2 (NMClient *client, + NMConnection *partial, + NMDevice *device, + const char *specific_object, + GVariant *options, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *simple; + GError *error = NULL; + + g_return_if_fail (NM_IS_CLIENT (client)); + g_return_if_fail (NM_IS_DEVICE (device)); + if (partial) + g_return_if_fail (NM_IS_CONNECTION (partial)); + + if (!_nm_client_check_nm_running (client, &error)) { + g_simple_async_report_take_gerror_in_idle (G_OBJECT (client), callback, user_data, error); + return; + } + + simple = g_simple_async_result_new (G_OBJECT (client), callback, user_data, + nm_client_add_and_activate_connection2); + if (cancellable) + g_simple_async_result_set_check_cancellable (simple, cancellable); + nm_manager_add_and_activate_connection_async (NM_CLIENT_GET_PRIVATE (client)->manager, + partial, + device, + specific_object, + options, + TRUE, + cancellable, + add_activate_cb, + simple); +} + +/** + * nm_client_add_and_activate_connection2_finish: + * @client: an #NMClient + * @result: the result passed to the #GAsyncReadyCallback + * @error: location for a #GError, or %NULL + * @out_result: (allow-none): (transfer full): the output result + * of type "a{sv}" returned by D-Bus' AddAndActivate2 call. Currently no + * output is implemented yet. + * + * Gets the result of a call to nm_client_add_and_activate_connection2(). + * + * You can call nm_active_connection_get_connection() on the returned + * #NMActiveConnection to find the path of the created #NMConnection. + * + * Returns: (transfer full): the new #NMActiveConnection on success, %NULL on + * failure, in which case @error will be set. + **/ +NMActiveConnection * +nm_client_add_and_activate_connection2_finish (NMClient *client, + GAsyncResult *result, + GVariant **out_result, + GError **error) +{ + GSimpleAsyncResult *simple; + _NMActivateResult *r; + + g_return_val_if_fail (NM_IS_CLIENT (client), NULL); + g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), NULL); + + simple = G_SIMPLE_ASYNC_RESULT (result); + if (g_simple_async_result_propagate_error (simple, error)) { + NM_SET_OUT (out_result, NULL); + return NULL; + } + r = g_simple_async_result_get_op_res_gpointer (simple); + NM_SET_OUT (out_result, nm_g_variant_ref (r->add_and_activate_output)); + return g_object_ref (r->active); } /** @@ -2470,7 +2599,7 @@ proxy_type (GDBusObjectManagerClient *manager, const char *interface_name, gpointer user_data) { - /* ObjectManager asks us for an object proxy. Unfortunatelly, we can't + /* ObjectManager asks us for an object proxy. Unfortunately, we can't * decide that by interface name and GDBusObjectManager doesn't allow * us to look at the known interface list. Thus we need to create a * generic GDBusObject and only couple a NMObject subclass later. */ diff --git a/libnm/nm-client.h b/libnm/nm-client.h index 6259b122..97363ef7 100644 --- a/libnm/nm-client.h +++ b/libnm/nm-client.h @@ -339,6 +339,21 @@ NMActiveConnection *nm_client_add_and_activate_connection_finish (NMClient *clie GAsyncResult *result, GError **error); +NM_AVAILABLE_IN_1_16 +void nm_client_add_and_activate_connection2 (NMClient *client, + NMConnection *partial, + NMDevice *device, + const char *specific_object, + GVariant *options, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +NM_AVAILABLE_IN_1_16 +NMActiveConnection *nm_client_add_and_activate_connection2_finish (NMClient *client, + GAsyncResult *result, + GVariant **out_result, + GError **error); + gboolean nm_client_deactivate_connection (NMClient *client, NMActiveConnection *active, GCancellable *cancellable, diff --git a/libnm/nm-dbus-helpers.c b/libnm/nm-dbus-helpers.c index 33c68191..44eed0c8 100644 --- a/libnm/nm-dbus-helpers.c +++ b/libnm/nm-dbus-helpers.c @@ -105,7 +105,7 @@ _nm_dbus_is_connection_private (GDBusConnection *connection) * rule the proxy added and ensure a less granular rule is present instead. * * Also, don't do this immediately since it has a performance penalty. - * Still better than loosing the signals altogether. + * Still better than losing the signals altogether. * * Ideally, we should be able to tell glib not to hook its rules: * https://bugzilla.gnome.org/show_bug.cgi?id=758749 diff --git a/libnm/nm-device-vxlan.c b/libnm/nm-device-vxlan.c index 27b9c981..9a87ad13 100644 --- a/libnm/nm-device-vxlan.c +++ b/libnm/nm-device-vxlan.c @@ -361,7 +361,7 @@ nm_device_vxlan_get_l2miss (NMDeviceVxlan *device) * nm_device_vxlan_get_l3miss: * @device: a #NMDeviceVxlan * - * Returns: wether netlink IP ADDR miss notifications are generated + * Returns: whether netlink IP ADDR miss notifications are generated * * Since: 1.2 **/ diff --git a/libnm/nm-device-wifi.c b/libnm/nm-device-wifi.c index 848e297c..9fb1eebf 100644 --- a/libnm/nm-device-wifi.c +++ b/libnm/nm-device-wifi.c @@ -370,7 +370,7 @@ nm_device_wifi_request_scan (NMDeviceWifi *device, * after that for the scan to complete. * This is the same as @nm_device_wifi_request_scan except it accepts @options * for the scanning. The argument is the dictionary passed to RequestScan() - * D-Bus call. Valid otions inside the dictionary are: + * D-Bus call. Valid options inside the dictionary are: * 'ssids' => array of SSIDs (saay) * * Returns: %TRUE on success, %FALSE on error, in which case @error will be @@ -487,7 +487,7 @@ nm_device_wifi_request_scan_async (NMDeviceWifi *device, * that for the scan to complete. * This is the same as @nm_device_wifi_request_scan_async except it accepts @options * for the scanning. The argument is the dictionary passed to RequestScan() - * D-Bus call. Valid otions inside the dictionary are: + * D-Bus call. Valid options inside the dictionary are: * 'ssids' => array of SSIDs (saay) * * Since: 1.2 diff --git a/libnm/nm-device.c b/libnm/nm-device.c index 3f1cc636..4bcd7c6c 100644 --- a/libnm/nm-device.c +++ b/libnm/nm-device.c @@ -74,6 +74,8 @@ typedef struct { NMDhcpConfig *dhcp4_config; NMIPConfig *ip6_config; NMDhcpConfig *dhcp6_config; + NMConnectivityState ip4_connectivity; + NMConnectivityState ip6_connectivity; NMDeviceState state; NMDeviceState last_seen_state; NMDeviceStateReason reason; @@ -120,6 +122,8 @@ enum { PROP_MTU, PROP_METERED, PROP_LLDP_NEIGHBORS, + PROP_IP4_CONNECTIVITY, + PROP_IP6_CONNECTIVITY, LAST_PROP }; @@ -144,6 +148,8 @@ nm_device_init (NMDevice *device) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device); + priv->ip4_connectivity = NM_CONNECTIVITY_UNKNOWN; + priv->ip6_connectivity = NM_CONNECTIVITY_UNKNOWN; priv->state = NM_DEVICE_STATE_UNKNOWN; priv->reason = NM_DEVICE_STATE_REASON_NONE; priv->lldp_neighbors = g_ptr_array_new (); @@ -216,6 +222,8 @@ init_dbus (NMObject *object) { NM_DEVICE_DHCP4_CONFIG, &priv->dhcp4_config, NULL, NM_TYPE_DHCP4_CONFIG }, { NM_DEVICE_IP6_CONFIG, &priv->ip6_config, NULL, NM_TYPE_IP6_CONFIG }, { NM_DEVICE_DHCP6_CONFIG, &priv->dhcp6_config, NULL, NM_TYPE_DHCP6_CONFIG }, + { NM_DEVICE_IP4_CONNECTIVITY, &priv->ip4_connectivity }, + { NM_DEVICE_IP6_CONNECTIVITY, &priv->ip6_connectivity }, { NM_DEVICE_STATE, &priv->state }, { NM_DEVICE_STATE_REASON, &priv->reason, demarshal_state_reason }, { NM_DEVICE_ACTIVE_CONNECTION, &priv->active_connection, NULL, NM_TYPE_ACTIVE_CONNECTION }, @@ -428,6 +436,12 @@ get_property (GObject *object, case PROP_LLDP_NEIGHBORS: g_value_set_boxed (value, nm_device_get_lldp_neighbors (device)); break; + case PROP_IP4_CONNECTIVITY: + g_value_set_enum (value, nm_device_get_connectivity (device, AF_INET)); + break; + case PROP_IP6_CONNECTIVITY: + g_value_set_enum (value, nm_device_get_connectivity (device, AF_INET6)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -700,6 +714,36 @@ nm_device_class_init (NMDeviceClass *device_class) G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + /** + * NMDevice:ip4-connectivity: + * + * The IPv4 connectivity state of the device. + * + * Since: 1.16 + **/ + g_object_class_install_property + (object_class, PROP_IP4_CONNECTIVITY, + g_param_spec_enum (NM_DEVICE_IP4_CONNECTIVITY, "", "", + NM_TYPE_CONNECTIVITY_STATE, + NM_CONNECTIVITY_UNKNOWN, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMDevice:ip6-connectivity: + * + * The IPv6 connectivity state of the device. + * + * Since: 1.16 + **/ + g_object_class_install_property + (object_class, PROP_IP6_CONNECTIVITY, + g_param_spec_enum (NM_DEVICE_IP6_CONNECTIVITY, "", "", + NM_TYPE_CONNECTIVITY_STATE, + NM_CONNECTIVITY_UNKNOWN, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + /** * NMDevice:state: * @@ -1230,6 +1274,36 @@ nm_device_get_dhcp6_config (NMDevice *device) return NM_DEVICE_GET_PRIVATE (device)->dhcp6_config; } +/** + * nm_device_get_connectivity: + * @device: a #NMDevice + * @addr_family: network address family + * + * The connectivity state of the device for given address family. + * Supported address families are %AF_INET for IPv4, %AF_INET6 + * for IPv6 or %AF_UNSPEC for any. + * + * Returns: the current connectivity state + * + * Since: 1.16 + **/ +NMConnectivityState +nm_device_get_connectivity (NMDevice *device, int addr_family) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device); + + switch (addr_family) { + case AF_INET: + return priv->ip4_connectivity; + case AF_INET6: + return priv->ip6_connectivity; + case AF_UNSPEC: + return NM_MAX (priv->ip4_connectivity, priv->ip6_connectivity); + default: + g_return_val_if_reached (NM_CONNECTIVITY_UNKNOWN); + } +} + /** * nm_device_get_state: * @device: a #NMDevice @@ -2392,7 +2466,7 @@ device_delete_cb (GObject *proxy, * @callback: callback to be called when delete operation completes * @user_data: caller-specific data passed to @callback * - * Asynchronously begins deleteing the software device. Hardware devices can't + * Asynchronously begins deleting the software device. Hardware devices can't * be deleted. **/ void diff --git a/libnm/nm-device.h b/libnm/nm-device.h index 91f31b87..fcda93ab 100644 --- a/libnm/nm-device.h +++ b/libnm/nm-device.h @@ -64,6 +64,8 @@ G_BEGIN_DECLS #define NM_DEVICE_MTU "mtu" #define NM_DEVICE_METERED "metered" #define NM_DEVICE_LLDP_NEIGHBORS "lldp-neighbors" +#define NM_DEVICE_IP4_CONNECTIVITY "ip4-connectivity" +#define NM_DEVICE_IP6_CONNECTIVITY "ip6-connectivity" /** * NMDevice: @@ -121,6 +123,8 @@ NMIPConfig * nm_device_get_ip4_config (NMDevice *device); NMDhcpConfig * nm_device_get_dhcp4_config (NMDevice *device); NMIPConfig * nm_device_get_ip6_config (NMDevice *device); NMDhcpConfig * nm_device_get_dhcp6_config (NMDevice *device); +NM_AVAILABLE_IN_1_16 +NMConnectivityState nm_device_get_connectivity (NMDevice *device, int addr_family); NMDeviceState nm_device_get_state (NMDevice *device); NMDeviceStateReason nm_device_get_state_reason (NMDevice *device); NMActiveConnection * nm_device_get_active_connection(NMDevice *device); diff --git a/libnm/nm-libnm-utils.c b/libnm/nm-libnm-utils.c index 36219065..f740c37c 100644 --- a/libnm/nm-libnm-utils.c +++ b/libnm/nm-libnm-utils.c @@ -125,7 +125,7 @@ next: } if (square_brackets_sensible) { /* If there's a [] that survived the substitution, then the string - * is a short form that is generally preferrable. */ + * is a short form that is generally preferable. */ q = strchr (desc_full, ']'); if (p && q > p) { p++; diff --git a/libnm/nm-manager.c b/libnm/nm-manager.c index a5425127..3254d4a0 100644 --- a/libnm/nm-manager.c +++ b/libnm/nm-manager.c @@ -870,16 +870,49 @@ nm_manager_get_activating_connection (NMManager *manager) return NM_MANAGER_GET_PRIVATE (manager)->activating_connection; } +typedef enum { + ACTIVATE_TYPE_ACTIVATE_CONNECTION, + ACTIVATE_TYPE_ADD_AND_ACTIVATE_CONNECTION, + ACTIVATE_TYPE_ADD_AND_ACTIVATE_CONNECTION2, +} ActivateType; + typedef struct { CList lst; NMManager *manager; GSimpleAsyncResult *simple; GCancellable *cancellable; - gulong cancelled_id; char *active_path; char *new_connection_path; + GVariant *add_and_activate_output; + gulong cancelled_id; + ActivateType activate_type; } ActivateInfo; +_NMActivateResult * +_nm_activate_result_new (NMActiveConnection *active, + GVariant *add_and_activate_output) +{ + _NMActivateResult *r; + + nm_assert (!add_and_activate_output || g_variant_is_of_type (add_and_activate_output, G_VARIANT_TYPE ("a{sv}"))); + nm_assert (!add_and_activate_output || !g_variant_is_floating (add_and_activate_output)); + + r = g_slice_new (_NMActivateResult); + *r = (_NMActivateResult) { + .active = g_object_ref (active), + .add_and_activate_output = nm_g_variant_ref (add_and_activate_output), + }; + return r; +} + +void +_nm_activate_result_free (_NMActivateResult *result) +{ + g_object_unref (result->active); + nm_g_variant_unref (result->add_and_activate_output); + g_slice_free (_NMActivateResult, result); +} + static void activate_info_complete (ActivateInfo *info, NMActiveConnection *active, @@ -889,12 +922,17 @@ activate_info_complete (ActivateInfo *info, c_list_unlink_stale (&info->lst); - if (active) - g_simple_async_result_set_op_res_gpointer (info->simple, g_object_ref (active), g_object_unref); - else + if (active) { + g_simple_async_result_set_op_res_gpointer (info->simple, + _nm_activate_result_new (active, + info->add_and_activate_output), + (GDestroyNotify) _nm_activate_result_free); + } else g_simple_async_result_set_from_error (info->simple, error); + g_simple_async_result_complete (info->simple); + nm_g_variant_unref (info->add_and_activate_output); g_free (info->active_path); g_free (info->new_connection_path); g_object_unref (info->simple); @@ -1035,6 +1073,7 @@ nm_manager_activate_connection_async (NMManager *manager, priv = NM_MANAGER_GET_PRIVATE (manager); info = g_slice_new0 (ActivateInfo); + info->activate_type = ACTIVATE_TYPE_ACTIVATE_CONNECTION; info->manager = manager; info->simple = g_simple_async_result_new (G_OBJECT (manager), callback, user_data, nm_manager_activate_connection_async); @@ -1058,14 +1097,16 @@ nm_manager_activate_connection_finish (NMManager *manager, GError **error) { GSimpleAsyncResult *simple; + _NMActivateResult *r; g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (manager), nm_manager_activate_connection_async), NULL); simple = G_SIMPLE_ASYNC_RESULT (result); if (g_simple_async_result_propagate_error (simple, error)) return NULL; - else - return g_object_ref (g_simple_async_result_get_op_res_gpointer (simple)); + + r = g_simple_async_result_get_op_res_gpointer (simple); + return g_object_ref (r->active); } static void @@ -1074,23 +1115,35 @@ add_activate_cb (GObject *object, gpointer user_data) { ActivateInfo *info = user_data; - GError *error = NULL; - - if (nmdbus_manager_call_add_and_activate_connection_finish (NMDBUS_MANAGER (object), - NULL, - &info->active_path, - result, &error)) { - if (info->cancellable) { - info->cancelled_id = g_signal_connect (info->cancellable, "cancelled", - G_CALLBACK (activation_cancelled), info); - } - - recheck_pending_activations (info->manager); + gs_free_error GError *error = NULL; + gboolean success; + + if (info->activate_type == ACTIVATE_TYPE_ADD_AND_ACTIVATE_CONNECTION) { + success = nmdbus_manager_call_add_and_activate_connection_finish (NMDBUS_MANAGER (object), + NULL, + &info->active_path, + result, + &error); } else { + success = nmdbus_manager_call_add_and_activate_connection2_finish (NMDBUS_MANAGER (object), + NULL, + &info->active_path, + &info->add_and_activate_output, + result, + &error); + } + if (!success) { g_dbus_error_strip_remote_error (error); activate_info_complete (info, NULL, error); - g_clear_error (&error); + return; + } + + if (info->cancellable) { + info->cancelled_id = g_signal_connect (info->cancellable, "cancelled", + G_CALLBACK (activation_cancelled), info); } + + recheck_pending_activations (info->manager); } void @@ -1098,6 +1151,8 @@ nm_manager_add_and_activate_connection_async (NMManager *manager, NMConnection *partial, NMDevice *device, const char *specific_object, + GVariant *options, + gboolean force_v2, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) @@ -1105,6 +1160,7 @@ nm_manager_add_and_activate_connection_async (NMManager *manager, NMManagerPrivate *priv; GVariant *dict = NULL; ActivateInfo *info; + ActivateType activate_type = ACTIVATE_TYPE_ADD_AND_ACTIVATE_CONNECTION; g_return_if_fail (NM_IS_MANAGER (manager)); g_return_if_fail (NM_IS_DEVICE (device)); @@ -1127,29 +1183,61 @@ nm_manager_add_and_activate_connection_async (NMManager *manager, dict = nm_connection_to_dbus (partial, NM_CONNECTION_SERIALIZE_ALL); if (!dict) dict = g_variant_new_array (G_VARIANT_TYPE ("{sa{sv}}"), NULL, 0); + if (force_v2) { + if (!options) + options = g_variant_new_array (G_VARIANT_TYPE ("{sv}"), NULL, 0); + activate_type = ACTIVATE_TYPE_ADD_AND_ACTIVATE_CONNECTION2; + } else { + if (options) { + if (g_variant_n_children (options) > 0) + activate_type = ACTIVATE_TYPE_ADD_AND_ACTIVATE_CONNECTION2; + else + nm_g_variant_unref_floating (options); + } + } - nmdbus_manager_call_add_and_activate_connection (priv->proxy, - dict, - nm_object_get_path (NM_OBJECT (device)), - specific_object ?: "/", - cancellable, - add_activate_cb, info); + info->activate_type = activate_type; + + if (activate_type == ACTIVATE_TYPE_ADD_AND_ACTIVATE_CONNECTION2) { + nmdbus_manager_call_add_and_activate_connection2 (priv->proxy, + dict, + nm_object_get_path (NM_OBJECT (device)), + specific_object ?: "/", + options, + cancellable, + add_activate_cb, + info); + } else { + nmdbus_manager_call_add_and_activate_connection (priv->proxy, + dict, + nm_object_get_path (NM_OBJECT (device)), + specific_object ?: "/", + cancellable, + add_activate_cb, + info); + } } NMActiveConnection * nm_manager_add_and_activate_connection_finish (NMManager *manager, GAsyncResult *result, + GVariant **out_result, GError **error) { GSimpleAsyncResult *simple; + _NMActivateResult *r; g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (manager), nm_manager_add_and_activate_connection_async), NULL); simple = G_SIMPLE_ASYNC_RESULT (result); - if (g_simple_async_result_propagate_error (simple, error)) + if (g_simple_async_result_propagate_error (simple, error)) { + NM_SET_OUT (out_result, NULL); return NULL; - else - return g_object_ref (g_simple_async_result_get_op_res_gpointer (simple)); + } + + r = g_simple_async_result_get_op_res_gpointer (simple); + NM_SET_OUT (out_result, nm_g_variant_ref (r->add_and_activate_output)); + return g_object_ref (r->active); } static void diff --git a/libnm/nm-manager.h b/libnm/nm-manager.h index 0a278aee..04e12eb3 100644 --- a/libnm/nm-manager.h +++ b/libnm/nm-manager.h @@ -163,11 +163,14 @@ void nm_manager_add_and_activate_connection_async (NMManager *ma NMConnection *partial, NMDevice *device, const char *specific_object, + GVariant *options, + gboolean force_v2, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); NMActiveConnection *nm_manager_add_and_activate_connection_finish (NMManager *manager, GAsyncResult *result, + GVariant **out_result, GError **error); gboolean nm_manager_deactivate_connection (NMManager *manager, @@ -220,4 +223,18 @@ gboolean nm_manager_checkpoint_adjust_rollback_timeout_finish (NMManager *manage GAsyncResult *result, GError **error); +/*****************************************************************************/ + +typedef struct { + NMActiveConnection *active; + GVariant *add_and_activate_output; +} _NMActivateResult; + +_NMActivateResult *_nm_activate_result_new (NMActiveConnection *active, + GVariant *add_and_activate_output); + +void _nm_activate_result_free (_NMActivateResult *result); + +/*****************************************************************************/ + #endif /* __NM_MANAGER_H__ */ diff --git a/libnm/nm-object.c b/libnm/nm-object.c index 70f90b63..d2ae25aa 100644 --- a/libnm/nm-object.c +++ b/libnm/nm-object.c @@ -612,7 +612,7 @@ handle_object_property (NMObject *self, const char *property_name, GVariant *val * * NOTE: We've ignored this before and the server hits the condition * more often that it should. Given we're able to recover from - * ther error, let's lower the severity of the log message to + * the error, let's lower the severity of the log message to * avoid unnecessarily bothering the user. This can be removed * once the issue is fixed on the server. */ #if NM_MORE_ASSERTS diff --git a/libnm/nm-object.h b/libnm/nm-object.h index 5b4580eb..1cc61a73 100644 --- a/libnm/nm-object.h +++ b/libnm/nm-object.h @@ -57,7 +57,7 @@ typedef struct { /* The "object-creation-failed" method is PRIVATE for libnm and * is not meant for any external usage. It indicates that an error - * occured during creation of an object. + * occurred during creation of an object. */ void (*object_creation_failed) (NMObject *master_object, const char *failed_path); diff --git a/libnm/nm-property-docs.xml b/libnm/nm-property-docs.xml index 22aed0ea..31bceefb 100644 --- a/libnm/nm-property-docs.xml +++ b/libnm/nm-property-docs.xml @@ -22,7 +22,7 @@ - + @@ -145,7 +145,7 @@ - + @@ -164,14 +164,14 @@ - + - + @@ -187,13 +187,13 @@ - + - + @@ -309,8 +309,8 @@ - - + + @@ -318,7 +318,7 @@ - + @@ -338,7 +338,7 @@ - + @@ -449,7 +449,9 @@ + + diff --git a/libnm/nm-settings-docs-overrides.xml b/libnm/nm-settings-docs-overrides.xml index 276253c6..54d85107 100644 --- a/libnm/nm-settings-docs-overrides.xml +++ b/libnm/nm-settings-docs-overrides.xml @@ -172,7 +172,7 @@ For libnm and nmcli, this field is called "cloned-mac-address"."/> a hardware address in ASCII representation, or one of the special values "preserve", "permanent", "random" or "stable". This field replaces the deprecated "cloned-mac-address" on D-Bus, which -can only contain explict hardware addresses. Note that this property +can only contain explicit hardware addresses. Note that this property only exists in D-Bus API. libnm and nmcli continue to call this property "cloned-mac-address"."/> @@ -186,7 +186,7 @@ For libnm and nmcli, this field is called "cloned-mac-address"."/> a hardware address in ASCII representation, or one of the special values "preserve", "permanent", "random" or "stable". This field replaces the deprecated "cloned-mac-address" on D-Bus, which -can only contain explict hardware addresses. Note that this property +can only contain explicit hardware addresses. Note that this property only exists in D-Bus API. libnm and nmcli continue to call this property "cloned-mac-address"."/> - + @@ -147,7 +147,7 @@ - + @@ -167,14 +167,14 @@ - + - + @@ -192,13 +192,13 @@ - + - + @@ -315,8 +315,8 @@ - - + + @@ -325,7 +325,7 @@ - + @@ -345,7 +345,7 @@ - + @@ -400,7 +400,7 @@ - + @@ -417,7 +417,7 @@ - + @@ -460,7 +460,9 @@ + + diff --git a/libnm/nm-settings-ifcfg-rh-docs.xml b/libnm/nm-settings-ifcfg-rh-docs.xml index 11f3115d..d1913062 100644 --- a/libnm/nm-settings-ifcfg-rh-docs.xml +++ b/libnm/nm-settings-ifcfg-rh-docs.xml @@ -135,7 +135,7 @@ means "do not transmit priority pause", "1" means "tran The sum of the numbers must be 100."/> - + diff --git a/libnm/nm-vpn-service-plugin.c b/libnm/nm-vpn-service-plugin.c index 2213824e..ed9da7f7 100644 --- a/libnm/nm-vpn-service-plugin.c +++ b/libnm/nm-vpn-service-plugin.c @@ -787,10 +787,13 @@ nm_vpn_service_plugin_read_vpn_details (int fd, gs_unref_hashtable GHashTable *data = NULL; gs_unref_hashtable GHashTable *secrets = NULL; gboolean success = FALSE; - char *key = NULL, *val = NULL; + GHashTable *hash = NULL; + GString *key = NULL, *val = NULL; nm_auto_free_gstring GString *line = NULL; char c; + GString *str = NULL; + if (out_data) g_return_val_if_fail (*out_data == NULL, FALSE); if (out_secrets) @@ -804,49 +807,80 @@ nm_vpn_service_plugin_read_vpn_details (int fd, /* Read stdin for data and secret items until we get a DONE */ while (1) { ssize_t nr; - GHashTable *hash = NULL; errno = 0; nr = read (fd, &c, 1); - if (nr == -1) { + if (nr < 0) { if (errno == EAGAIN) { g_usleep (100); continue; } break; } - - if (c != '\n') { + if (nr > 0 && c != '\n') { g_string_append_c (line, c); continue; } - /* Check for the finish marker */ - if (strcmp (line->str, "DONE") == 0) - break; + if (str && *line->str == '=') { + /* continuation */ + g_string_append_c (str, '\n'); + g_string_append (str, line->str + 1); + } else if (key && val) { + /* done a line */ + g_return_val_if_fail (hash, FALSE); + g_hash_table_insert (hash, + g_string_free (key, FALSE), + g_string_free (val, FALSE)); + key = NULL; + val = NULL; + hash = NULL; + success = TRUE; /* Got at least one value */ + } - /* Otherwise it's a data/secret item */ - if (strncmp (line->str, DATA_KEY_TAG, strlen (DATA_KEY_TAG)) == 0) { + if (strcmp (line->str, "DONE") == 0) { + /* finish marker */ + break; + } else if (strncmp (line->str, DATA_KEY_TAG, strlen (DATA_KEY_TAG)) == 0) { + if (key != NULL) { + g_warning ("a value expected"); + g_string_free (key, TRUE); + } + key = g_string_new (line->str + strlen (DATA_KEY_TAG)); + str = key; hash = data; - key = g_strdup (line->str + strlen (DATA_KEY_TAG)); } else if (strncmp (line->str, DATA_VAL_TAG, strlen (DATA_VAL_TAG)) == 0) { - hash = data; - val = g_strdup (line->str + strlen (DATA_VAL_TAG)); + if (val != NULL) + g_string_free (val, TRUE); + if (val || !key || hash != data) { + g_warning ("%s not preceded by %s", DATA_VAL_TAG, DATA_KEY_TAG); + break; + } + val = g_string_new (line->str + strlen (DATA_VAL_TAG)); + str = val; } else if (strncmp (line->str, SECRET_KEY_TAG, strlen (SECRET_KEY_TAG)) == 0) { + if (key != NULL) { + g_warning ("a value expected"); + g_string_free (key, TRUE); + } + key = g_string_new (line->str + strlen (SECRET_KEY_TAG)); + str = key; hash = secrets; - key = g_strdup (line->str + strlen (SECRET_KEY_TAG)); } else if (strncmp (line->str, SECRET_VAL_TAG, strlen (SECRET_VAL_TAG)) == 0) { - hash = secrets; - val = g_strdup (line->str + strlen (SECRET_VAL_TAG)); + if (val != NULL) + g_string_free (val, TRUE); + if (val || !key || hash != secrets) { + g_warning ("%s not preceded by %s", SECRET_VAL_TAG, SECRET_KEY_TAG); + break; + } + val = g_string_new (line->str + strlen (SECRET_VAL_TAG)); + str = val; } + g_string_truncate (line, 0); - if (key && val && hash) { - g_hash_table_insert (hash, key, val); - key = NULL; - val = NULL; - success = TRUE; /* Got at least one value */ - } + if (nr == 0) + break; } if (success) { @@ -1325,7 +1359,7 @@ nm_vpn_service_plugin_initable_iface_init (GInitableIface *iface) /*****************************************************************************/ /* this header is intended to be copied to users of nm_vpn_editor_plugin_call(), - * to simplify invocation of generic functions. Include it here, to complile + * to simplify invocation of generic functions. Include it here, to compile * the code. */ #include "nm-utils/nm-vpn-editor-plugin-call.h" diff --git a/libnm/tests/meson.build b/libnm/tests/meson.build index ae2f7124..d0a2dd30 100644 --- a/libnm/tests/meson.build +++ b/libnm/tests/meson.build @@ -20,16 +20,17 @@ foreach test_unit: test_units dependencies: [ libnm_dep, nm_core_dep, + libnm_systemd_shared_no_logging_dep, ], c_args: cflags, - link_with: test_unit[1] + link_with: test_unit[1], ) test( 'libnm/' + test_unit[0], test_script, timeout: test_unit[2], - args: test_args + [exe.full_path()] + args: test_args + [exe.full_path()], ) endforeach @@ -39,5 +40,5 @@ libnm_vpn_plugin_utils_test = static_library( sources: shared_nm_utils_nm_vpn_plugin_utils_c + [libnm_enum[1]], include_directories: libnm_inc, dependencies: nm_core_dep, - c_args: cflags + c_args: cflags, ) diff --git a/libnm/tests/test-general.c b/libnm/tests/test-general.c index 5959a4e6..410087af 100644 --- a/libnm/tests/test-general.c +++ b/libnm/tests/test-general.c @@ -20,8 +20,16 @@ #include "nm-default.h" +#if defined (HAVE_DECL_MEMFD_CREATE) && HAVE_DECL_MEMFD_CREATE +#include +#endif + +#include + #include "nm-libnm-utils.h" +#include "nm-vpn-service-plugin.h" + #include "nm-utils/nm-test-utils.h" /*****************************************************************************/ @@ -2158,6 +2166,271 @@ test_fixup_product_string (void) /*****************************************************************************/ +static int +_memfd_create (const char *name) +{ +#if defined (HAVE_DECL_MEMFD_CREATE) && HAVE_DECL_MEMFD_CREATE + return memfd_create (name, MFD_CLOEXEC); +#endif + return -1; +} + +typedef struct { + const char *key; + const char *val; +} ReadVpnDetailData; + +#define READ_VPN_DETAIL_DATA(...) \ + ((ReadVpnDetailData []) { __VA_ARGS__ }) + +static gboolean +_do_read_vpn_details_impl1 (const char *file, + int line, + int memfd, + char *mem, + gsize len, + const ReadVpnDetailData *expected_data, + guint expected_data_len, + const ReadVpnDetailData *expected_secrets, + guint expected_secrets_len) +{ + gssize written; + off_t lseeked; + gs_unref_hashtable GHashTable *data = NULL; + gs_unref_hashtable GHashTable *secrets = NULL; + + written = write (memfd, mem, len); + g_assert_cmpint (written, ==, (gssize) len); + + lseeked = lseek (memfd, 0, SEEK_SET); + g_assert_cmpint (lseeked, ==, 0); + + if (!nm_vpn_service_plugin_read_vpn_details (memfd, + &data, + &secrets)) { + g_assert (!data); + g_assert (!secrets); + g_assert_cmpint (expected_data_len, ==, 0); + g_assert_cmpint (expected_secrets_len, ==, 0); + return TRUE; + } + +#define _assert_hash(hash, expected, expected_len) \ + G_STMT_START { \ + GHashTable *_hash = (hash); \ + guint _expected_len = (expected_len); \ + const ReadVpnDetailData *_expected = (expected); \ + GHashTableIter _iter; \ + const char *_k, *_v; \ + guint _i; \ + \ + g_assert (_hash); \ + \ + g_hash_table_iter_init (&_iter, _hash); \ + while (g_hash_table_iter_next (&_iter, (gpointer *) &_k, (gpointer *) &_v)) { \ + for (_i = 0; _i < _expected_len; _i++) { \ + if (nm_streq (_expected[_i].key, _k)) \ + break; \ + } \ + if (_i >= _expected_len) \ + g_error ("%s:%d: hash '%s' contains unexpected data key '%s' with value '%s'", file, line, G_STRINGIFY (hash), _k, _v); \ + } \ + \ + for (_i = 0; _i < _expected_len; _i++) { \ + const ReadVpnDetailData *_d = &_expected[_i]; \ + \ + g_assert (_d->key); \ + g_assert (_d->val); \ + _v = g_hash_table_lookup (_hash, _d->key); \ + if (!nm_streq0 (_v, _d->val)) \ + g_error ("%s:%d: hash '%s' contains data key '%s' with value %s%s%s but we expected '%s'", file, line, G_STRINGIFY (hash), _d->key, NM_PRINT_FMT_QUOTE_STRING (_v), _d->val); \ + } \ + \ + g_assert_cmpint (g_hash_table_size (_hash), ==, _expected_len); \ + } G_STMT_END + + _assert_hash (data, expected_data, expected_data_len); + _assert_hash (secrets, expected_secrets, expected_secrets_len); + +#undef _assert_hash + return TRUE; +} + +#define _do_read_vpn_details_impl0(str, expected_data, expected_data_len, expected_secrets, expected_secrets_len, pre_setup_cmd) \ + G_STMT_START { \ + nm_auto_close int _memfd = _memfd_create ("libnm-test-read-vpn-details"); \ + \ + if (_memfd < 0) \ + g_test_skip ("cannot create memfd"); \ + else { \ + { pre_setup_cmd ; } \ + _do_read_vpn_details_impl1 (__FILE__, \ + __LINE__, \ + _memfd, \ + ""str"", \ + NM_STRLEN (str), \ + expected_data, \ + expected_data_len, \ + expected_secrets, \ + expected_secrets_len); \ + } \ + } G_STMT_END + +#define _do_read_vpn_details_empty(str) \ + _do_read_vpn_details_impl0 (str, \ + NULL, \ + 0, \ + NULL, \ + 0, \ + { } ) + +#define _do_read_vpn_details(str, expected_data, expected_secrets, pre_setup_cmd) \ + _do_read_vpn_details_impl0 (str, \ + expected_data, \ + G_N_ELEMENTS (expected_data), \ + expected_secrets, \ + G_N_ELEMENTS (expected_secrets), \ + pre_setup_cmd) + +static void +test_nm_vpn_service_plugin_read_vpn_details (void) +{ + _do_read_vpn_details_empty (""); + _do_read_vpn_details_empty ("hallo"); + _do_read_vpn_details_empty ("DONE"); + _do_read_vpn_details_empty ("DONE\n"); + _do_read_vpn_details_empty ("DONE\0"); + _do_read_vpn_details_empty ("\0DONE\0"); + + _do_read_vpn_details ("" + "DATA_KEY=some-key\n" + "DATA_VAL=string\n" + "\n" + "DATA_KEY=some-other-key\n" + "DATA_VAL=val2\n" + "\n" + "SECRET_KEY=some-secret\n" + "SECRET_VAL=val3\n" + "\n" + "DONE\n" + "\n" + "", + READ_VPN_DETAIL_DATA ( + { "some-key", "string" }, + { "some-other-key", "val2" }, + ), + READ_VPN_DETAIL_DATA ( + { "some-secret", "val3" }, + ), + ); + + _do_read_vpn_details ("" + "DATA_KEY=some-key\n" + "DATA_VAL=string\n" + "DONE\n", + READ_VPN_DETAIL_DATA ( + { "some-key", "string" }, + ), + READ_VPN_DETAIL_DATA (), + ); + + _do_read_vpn_details ("" + "DATA_KEY=some-key\n" + "DATA_VAL=string\n" + "=continued after a line break\n" + "SECRET_KEY=key names\n" + "=can have\n" + "=continuations too\n" + "bogus1=\n" + "SECRET_VAL=value\n" + "bogus=value\n" + "bogus=\n" + "DATA_VAL=x\n" + "DATA_KEY=\n" + "DATA_VAL=\n" + "DATA_VAL=y\n" + "DATA_KEY=y\n" + "DATA_KEY=y\n" + "DATA_KEY=z\n" + "SECRET_KEY=s1\n" + "DATA_VAL=z\n" + "SECRET_VAL=S1\n" + "\n" + "DONE\n" + "", + READ_VPN_DETAIL_DATA ( + { "some-key", "string\ncontinued after a line break" }, + ), + READ_VPN_DETAIL_DATA ( + { "key names\ncan have\ncontinuations too", "value" }, + ), + NMTST_EXPECT_LIBNM_WARNING ("DATA_VAL= not preceded by DATA_KEY=") + ); + + _do_read_vpn_details ("" + "DATA_KEY=some-key\n" + "DATA_VAL=string\n" + "=continued after a line break\n" + "SECRET_KEY=key names\n" + "=can have\n" + "=continuations too\n" + "SECRET_VAL=value\n" + "", + READ_VPN_DETAIL_DATA ( + { "some-key", "string\ncontinued after a line break" }, + ), + READ_VPN_DETAIL_DATA ( + { "key names\ncan have\ncontinuations too", "value" }, + ), + ); + + _do_read_vpn_details ("" + "DATA_KEY=some-key\n" + "DATA_VAL=string\n" + "\n" + "DATA_KEY=some\n" + "=key-2\n" + "DATA_VAL=val2\n" + "\n" + "DATA_KEY=key3\0" + "=key-2\n" + "DATA_VAL=val3\n" + "\n" + "SECRET_KEY=some-secret\n" + "SECRET_VAL=val3\n" + "\n" + "SECRET_KEY=\n" + "SECRET_VAL=val3\n" + "\n" + "SECRET_KEY=keyx\n" + "SECRET_VAL=\n" + "\n" + "SECRET_KEY=ke\xc0yx\n" + "SECRET_VAL=inval\n" + "\n" + "SECRET_KEY=key-inval\n" + "SECRET_VAL=in\xc1val\n" + "\n" + "DONE\n" + "\n" + "", + READ_VPN_DETAIL_DATA ( + { "some\nkey-2", "val2" }, + { "some-key", "string" }, + { "key3", "val3" }, + ), + READ_VPN_DETAIL_DATA ( + { "some-secret", "val3" }, + { "", "val3" }, + { "keyx", "" }, + { "ke\xc0yx", "inval" }, + { "key-inval", "in\xc1val" }, + ), + ); +} + +/*****************************************************************************/ + NMTST_DEFINE (); int main (int argc, char **argv) @@ -2166,6 +2439,7 @@ int main (int argc, char **argv) g_test_add_func ("/libnm/general/fixup_product_string", test_fixup_product_string); g_test_add_func ("/libnm/general/fixup_vendor_string", test_fixup_vendor_string); + g_test_add_func ("/libnm/general/nm_vpn_service_plugin_read_vpn_details", test_nm_vpn_service_plugin_read_vpn_details); return g_test_run (); } -- cgit 1.3.0-6-gf8a5