mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-02-27 10:30:36 +01:00
core/dispatcher: prefer the Action2() method and fall back to Action()
Call the Action2() method first, and fall back to the old Action() if
the new one is not available. This allows full interoperability
between different versions of the dispatcher service and NM.
(cherry picked from commit 8fd0d39444)
This commit is contained in:
parent
ad5b3b38db
commit
220d42c6f8
1 changed files with 212 additions and 86 deletions
|
|
@ -57,10 +57,12 @@ struct NMDispatcherCallId {
|
|||
gpointer user_data;
|
||||
const char *log_ifname;
|
||||
const char *log_con_uuid;
|
||||
GVariant *action_params;
|
||||
gint64 start_at_msec;
|
||||
NMDispatcherAction action;
|
||||
guint idle_id;
|
||||
guint32 request_id;
|
||||
bool is_action2 : 1;
|
||||
char extra_strings[];
|
||||
};
|
||||
|
||||
|
|
@ -121,6 +123,7 @@ dispatcher_call_id_new(guint32 request_id,
|
|||
call_id->callback = callback;
|
||||
call_id->user_data = user_data;
|
||||
call_id->idle_id = 0;
|
||||
call_id->is_action2 = TRUE;
|
||||
|
||||
extra_strings = &call_id->extra_strings[0];
|
||||
|
||||
|
|
@ -143,6 +146,7 @@ dispatcher_call_id_new(guint32 request_id,
|
|||
static void
|
||||
dispatcher_call_id_free(NMDispatcherCallId *call_id)
|
||||
{
|
||||
nm_clear_pointer(&call_id->action_params, g_variant_unref);
|
||||
nm_clear_g_source(&call_id->idle_id);
|
||||
g_free(call_id);
|
||||
}
|
||||
|
|
@ -390,14 +394,18 @@ dispatcher_results_process(guint32 request_id,
|
|||
gint64 now_msec,
|
||||
const char *log_ifname,
|
||||
const char *log_con_uuid,
|
||||
GVariant *v_results)
|
||||
GVariant *v_results,
|
||||
gboolean is_action2)
|
||||
{
|
||||
nm_auto_free_variant_iter GVariantIter *results = NULL;
|
||||
const char *script, *err;
|
||||
guint32 result;
|
||||
gsize n_children;
|
||||
|
||||
g_variant_get(v_results, "(a(sus))", &results);
|
||||
if (is_action2)
|
||||
g_variant_get(v_results, "(a(susa{sv}))", &results);
|
||||
else
|
||||
g_variant_get(v_results, "(a(sus))", &results);
|
||||
|
||||
n_children = g_variant_iter_n_children(results);
|
||||
|
||||
|
|
@ -412,7 +420,17 @@ dispatcher_results_process(guint32 request_id,
|
|||
if (n_children == 0)
|
||||
return;
|
||||
|
||||
while (g_variant_iter_next(results, "(&su&s)", &script, &result, &err)) {
|
||||
while (TRUE) {
|
||||
gs_unref_variant GVariant *options = NULL;
|
||||
|
||||
if (is_action2) {
|
||||
if (!g_variant_iter_next(results, "(&su&s@a{sv})", &script, &result, &err, &options))
|
||||
break;
|
||||
} else {
|
||||
if (!g_variant_iter_next(results, "(&su&s)", &script, &result, &err))
|
||||
break;
|
||||
}
|
||||
|
||||
if (result == DISPATCH_RESULT_SUCCESS) {
|
||||
_LOG2D(request_id, log_ifname, log_con_uuid, "%s succeeded", script);
|
||||
} else {
|
||||
|
|
@ -440,6 +458,27 @@ dispatcher_done_cb(GObject *source, GAsyncResult *result, gpointer user_data)
|
|||
now_msec = nm_utils_get_monotonic_timestamp_msec();
|
||||
|
||||
ret = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), result, &error);
|
||||
|
||||
if (!ret && call_id->is_action2
|
||||
&& g_error_matches(error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD)) {
|
||||
_LOG3D(call_id,
|
||||
"dispatcher service does not implement Action2() method, falling back to Action()");
|
||||
call_id->is_action2 = FALSE;
|
||||
g_dbus_connection_call(gl.dbus_connection,
|
||||
NM_DISPATCHER_DBUS_SERVICE,
|
||||
NM_DISPATCHER_DBUS_PATH,
|
||||
NM_DISPATCHER_DBUS_INTERFACE,
|
||||
"Action",
|
||||
g_steal_pointer(&call_id->action_params),
|
||||
G_VARIANT_TYPE("(a(sus))"),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
CALL_TIMEOUT,
|
||||
NULL,
|
||||
dispatcher_done_cb,
|
||||
call_id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
NMLogLevel log_level = LOGL_DEBUG;
|
||||
|
||||
|
|
@ -459,7 +498,8 @@ dispatcher_done_cb(GObject *source, GAsyncResult *result, gpointer user_data)
|
|||
now_msec,
|
||||
call_id->log_ifname,
|
||||
call_id->log_con_uuid,
|
||||
ret);
|
||||
ret,
|
||||
call_id->is_action2);
|
||||
}
|
||||
|
||||
g_hash_table_remove(gl.requests, call_id);
|
||||
|
|
@ -494,75 +534,29 @@ action_to_string(NMDispatcherAction action)
|
|||
return action_table[(gsize) action];
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_dispatcher_call(NMDispatcherAction action,
|
||||
gboolean blocking,
|
||||
NMDevice *device,
|
||||
NMSettingsConnection *settings_connection,
|
||||
NMConnection *applied_connection,
|
||||
gboolean activation_type_external,
|
||||
NMConnectivityState connectivity_state,
|
||||
const char *vpn_iface,
|
||||
const NML3ConfigData *l3cd,
|
||||
NMDispatcherFunc callback,
|
||||
gpointer user_data,
|
||||
NMDispatcherCallId **out_call_id)
|
||||
static GVariant *
|
||||
build_call_parameters(NMDispatcherAction action,
|
||||
NMDevice *device,
|
||||
NMSettingsConnection *settings_connection,
|
||||
NMConnection *applied_connection,
|
||||
gboolean activation_type_external,
|
||||
NMConnectivityState connectivity_state,
|
||||
const char *vpn_iface,
|
||||
const NML3ConfigData *l3cd,
|
||||
gboolean is_action2)
|
||||
{
|
||||
const char *connectivity_state_string = "UNKNOWN";
|
||||
GVariant *connection_dict;
|
||||
GVariantBuilder connection_props;
|
||||
GVariantBuilder device_props;
|
||||
GVariantBuilder device_proxy_props;
|
||||
GVariantBuilder device_ip4_props;
|
||||
GVariantBuilder device_ip6_props;
|
||||
gs_unref_variant GVariant *parameters_floating = NULL;
|
||||
gs_unref_variant GVariant *device_dhcp4_props = NULL;
|
||||
gs_unref_variant GVariant *device_dhcp6_props = NULL;
|
||||
gs_unref_variant GVariant *device_dhcp4_props = NULL;
|
||||
gs_unref_variant GVariant *device_dhcp6_props = NULL;
|
||||
GVariantBuilder vpn_proxy_props;
|
||||
GVariantBuilder vpn_ip4_props;
|
||||
GVariantBuilder vpn_ip6_props;
|
||||
NMDispatcherCallId *call_id;
|
||||
guint request_id;
|
||||
const char *connectivity_state_string = "UNKNOWN";
|
||||
const char *log_ifname;
|
||||
const char *log_con_uuid;
|
||||
gint64 start_at_msec;
|
||||
gint64 now_msec;
|
||||
|
||||
g_return_val_if_fail(!blocking || (!callback && !user_data), FALSE);
|
||||
|
||||
NM_SET_OUT(out_call_id, NULL);
|
||||
|
||||
_init_dispatcher();
|
||||
|
||||
if (!gl.dbus_connection)
|
||||
return FALSE;
|
||||
|
||||
log_ifname = device ? nm_device_get_iface(device) : NULL;
|
||||
log_con_uuid =
|
||||
settings_connection ? nm_settings_connection_get_uuid(settings_connection) : NULL;
|
||||
|
||||
request_id = ++gl.request_id_counter;
|
||||
if (G_UNLIKELY(!request_id))
|
||||
request_id = ++gl.request_id_counter;
|
||||
|
||||
if (!action_need_device(action)) {
|
||||
_LOG2D(request_id,
|
||||
log_ifname,
|
||||
log_con_uuid,
|
||||
"dispatching action '%s'%s",
|
||||
action_to_string(action),
|
||||
blocking ? " (blocking)" : (callback ? " (with callback)" : ""));
|
||||
} else {
|
||||
g_return_val_if_fail(NM_IS_DEVICE(device), FALSE);
|
||||
|
||||
_LOG2D(request_id,
|
||||
log_ifname,
|
||||
log_con_uuid,
|
||||
"(%s) dispatching action '%s'%s",
|
||||
vpn_iface ?: nm_device_get_iface(device),
|
||||
action_to_string(action),
|
||||
blocking ? " (blocking)" : (callback ? " (with callback)" : ""));
|
||||
}
|
||||
|
||||
if (applied_connection)
|
||||
connection_dict =
|
||||
|
|
@ -621,25 +615,114 @@ _dispatcher_call(NMDispatcherAction action,
|
|||
|
||||
connectivity_state_string = nm_connectivity_state_to_string(connectivity_state);
|
||||
|
||||
parameters_floating =
|
||||
g_variant_new("(s@a{sa{sv}}a{sv}a{sv}a{sv}a{sv}a{sv}@a{sv}@a{sv}ssa{sv}a{sv}a{sv}b)",
|
||||
action_to_string(action),
|
||||
connection_dict,
|
||||
&connection_props,
|
||||
&device_props,
|
||||
&device_proxy_props,
|
||||
&device_ip4_props,
|
||||
&device_ip6_props,
|
||||
device_dhcp4_props ?: nm_g_variant_singleton_aLsvI(),
|
||||
device_dhcp6_props ?: nm_g_variant_singleton_aLsvI(),
|
||||
connectivity_state_string,
|
||||
vpn_iface ?: "",
|
||||
&vpn_proxy_props,
|
||||
&vpn_ip4_props,
|
||||
&vpn_ip6_props,
|
||||
nm_logging_enabled(LOGL_DEBUG, LOGD_DISPATCH));
|
||||
if (is_action2) {
|
||||
return g_variant_new(
|
||||
"(s@a{sa{sv}}a{sv}a{sv}a{sv}a{sv}a{sv}@a{sv}@a{sv}ssa{sv}a{sv}a{sv}b@a{sv})",
|
||||
action_to_string(action),
|
||||
connection_dict,
|
||||
&connection_props,
|
||||
&device_props,
|
||||
&device_proxy_props,
|
||||
&device_ip4_props,
|
||||
&device_ip6_props,
|
||||
device_dhcp4_props ?: nm_g_variant_singleton_aLsvI(),
|
||||
device_dhcp6_props ?: nm_g_variant_singleton_aLsvI(),
|
||||
connectivity_state_string,
|
||||
vpn_iface ?: "",
|
||||
&vpn_proxy_props,
|
||||
&vpn_ip4_props,
|
||||
&vpn_ip6_props,
|
||||
nm_logging_enabled(LOGL_DEBUG, LOGD_DISPATCH),
|
||||
nm_g_variant_singleton_aLsvI());
|
||||
}
|
||||
|
||||
start_at_msec = nm_utils_get_monotonic_timestamp_msec();
|
||||
return g_variant_new("(s@a{sa{sv}}a{sv}a{sv}a{sv}a{sv}a{sv}@a{sv}@a{sv}ssa{sv}a{sv}a{sv}b)",
|
||||
action_to_string(action),
|
||||
connection_dict,
|
||||
&connection_props,
|
||||
&device_props,
|
||||
&device_proxy_props,
|
||||
&device_ip4_props,
|
||||
&device_ip6_props,
|
||||
device_dhcp4_props ?: nm_g_variant_singleton_aLsvI(),
|
||||
device_dhcp6_props ?: nm_g_variant_singleton_aLsvI(),
|
||||
connectivity_state_string,
|
||||
vpn_iface ?: "",
|
||||
&vpn_proxy_props,
|
||||
&vpn_ip4_props,
|
||||
&vpn_ip6_props,
|
||||
nm_logging_enabled(LOGL_DEBUG, LOGD_DISPATCH));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_dispatcher_call(NMDispatcherAction action,
|
||||
gboolean blocking,
|
||||
NMDevice *device,
|
||||
NMSettingsConnection *settings_connection,
|
||||
NMConnection *applied_connection,
|
||||
gboolean activation_type_external,
|
||||
NMConnectivityState connectivity_state,
|
||||
const char *vpn_iface,
|
||||
const NML3ConfigData *l3cd,
|
||||
NMDispatcherFunc callback,
|
||||
gpointer user_data,
|
||||
NMDispatcherCallId **out_call_id)
|
||||
{
|
||||
NMDispatcherCallId *call_id;
|
||||
guint request_id;
|
||||
const char *log_ifname;
|
||||
const char *log_con_uuid;
|
||||
gint64 start_at_msec;
|
||||
gint64 now_msec;
|
||||
gs_unref_variant GVariant *parameters_floating = NULL;
|
||||
gboolean is_action2 = TRUE;
|
||||
|
||||
g_return_val_if_fail(!blocking || (!callback && !user_data), FALSE);
|
||||
|
||||
NM_SET_OUT(out_call_id, NULL);
|
||||
|
||||
_init_dispatcher();
|
||||
|
||||
if (!gl.dbus_connection)
|
||||
return FALSE;
|
||||
|
||||
log_ifname = device ? nm_device_get_iface(device) : NULL;
|
||||
log_con_uuid =
|
||||
settings_connection ? nm_settings_connection_get_uuid(settings_connection) : NULL;
|
||||
|
||||
request_id = ++gl.request_id_counter;
|
||||
if (G_UNLIKELY(!request_id))
|
||||
request_id = ++gl.request_id_counter;
|
||||
|
||||
if (!action_need_device(action)) {
|
||||
_LOG2D(request_id,
|
||||
log_ifname,
|
||||
log_con_uuid,
|
||||
"dispatching action '%s'%s",
|
||||
action_to_string(action),
|
||||
blocking ? " (blocking)" : (callback ? " (with callback)" : ""));
|
||||
} else {
|
||||
g_return_val_if_fail(NM_IS_DEVICE(device), FALSE);
|
||||
|
||||
_LOG2D(request_id,
|
||||
log_ifname,
|
||||
log_con_uuid,
|
||||
"(%s) dispatching action '%s'%s",
|
||||
vpn_iface ?: nm_device_get_iface(device),
|
||||
action_to_string(action),
|
||||
blocking ? " (blocking)" : (callback ? " (with callback)" : ""));
|
||||
}
|
||||
|
||||
parameters_floating = build_call_parameters(action,
|
||||
device,
|
||||
settings_connection,
|
||||
applied_connection,
|
||||
activation_type_external,
|
||||
connectivity_state,
|
||||
vpn_iface,
|
||||
l3cd,
|
||||
TRUE);
|
||||
start_at_msec = nm_utils_get_monotonic_timestamp_msec();
|
||||
|
||||
/* Send the action to the dispatcher */
|
||||
if (blocking) {
|
||||
|
|
@ -650,14 +733,44 @@ _dispatcher_call(NMDispatcherAction action,
|
|||
NM_DISPATCHER_DBUS_SERVICE,
|
||||
NM_DISPATCHER_DBUS_PATH,
|
||||
NM_DISPATCHER_DBUS_INTERFACE,
|
||||
"Action",
|
||||
"Action2",
|
||||
g_steal_pointer(¶meters_floating),
|
||||
G_VARIANT_TYPE("(a(sus))"),
|
||||
G_VARIANT_TYPE("(a(susa{sv}))"),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
CALL_TIMEOUT,
|
||||
NULL,
|
||||
&error);
|
||||
|
||||
if (!ret && g_error_matches(error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD)) {
|
||||
_LOG2D(
|
||||
request_id,
|
||||
log_ifname,
|
||||
log_con_uuid,
|
||||
"dispatcher service does not implement Action2() method, falling back to Action()");
|
||||
g_clear_error(&error);
|
||||
parameters_floating = build_call_parameters(action,
|
||||
device,
|
||||
settings_connection,
|
||||
applied_connection,
|
||||
activation_type_external,
|
||||
connectivity_state,
|
||||
vpn_iface,
|
||||
l3cd,
|
||||
FALSE);
|
||||
ret = g_dbus_connection_call_sync(gl.dbus_connection,
|
||||
NM_DISPATCHER_DBUS_SERVICE,
|
||||
NM_DISPATCHER_DBUS_PATH,
|
||||
NM_DISPATCHER_DBUS_INTERFACE,
|
||||
"Action",
|
||||
g_steal_pointer(¶meters_floating),
|
||||
G_VARIANT_TYPE("(a(sus))"),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
CALL_TIMEOUT,
|
||||
NULL,
|
||||
&error);
|
||||
is_action2 = FALSE;
|
||||
}
|
||||
|
||||
now_msec = nm_utils_get_monotonic_timestamp_msec();
|
||||
|
||||
if (!ret) {
|
||||
|
|
@ -676,7 +789,8 @@ _dispatcher_call(NMDispatcherAction action,
|
|||
now_msec,
|
||||
log_ifname,
|
||||
log_con_uuid,
|
||||
ret);
|
||||
ret,
|
||||
is_action2);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -688,13 +802,25 @@ _dispatcher_call(NMDispatcherAction action,
|
|||
log_ifname,
|
||||
log_con_uuid);
|
||||
|
||||
/* Since we don't want to cache all the input parameters, already build
|
||||
* and cache the argument for the Action() method in case Action2() fails. */
|
||||
call_id->action_params = build_call_parameters(action,
|
||||
device,
|
||||
settings_connection,
|
||||
applied_connection,
|
||||
activation_type_external,
|
||||
connectivity_state,
|
||||
vpn_iface,
|
||||
l3cd,
|
||||
FALSE);
|
||||
|
||||
g_dbus_connection_call(gl.dbus_connection,
|
||||
NM_DISPATCHER_DBUS_SERVICE,
|
||||
NM_DISPATCHER_DBUS_PATH,
|
||||
NM_DISPATCHER_DBUS_INTERFACE,
|
||||
"Action",
|
||||
"Action2",
|
||||
g_steal_pointer(¶meters_floating),
|
||||
G_VARIANT_TYPE("(a(sus))"),
|
||||
G_VARIANT_TYPE("(a(susa{sv}))"),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
CALL_TIMEOUT,
|
||||
NULL,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue