diff options
Diffstat (limited to 'src/core/nm-dispatcher.c')
| -rw-r--r-- | src/core/nm-dispatcher.c | 677 |
1 files changed, 479 insertions, 198 deletions
diff --git a/src/core/nm-dispatcher.c b/src/core/nm-dispatcher.c index 9aa4194e..4f442c68 100644 --- a/src/core/nm-dispatcher.c +++ b/src/core/nm-dispatcher.c @@ -50,20 +50,24 @@ } \ G_STMT_END -static gboolean nm_dispatcher_need_device(NMDispatcherAction action); - /*****************************************************************************/ +/* Type for generic callback function; must be cast to either + * NMDispatcherFunc or NMDispatcherFuncDH before using. */ +typedef void (*NMDispatcherCallback)(void); + struct NMDispatcherCallId { - NMDispatcherFunc callback; - gpointer user_data; - const char *log_ifname; - const char *log_con_uuid; - gint64 start_at_msec; - NMDispatcherAction action; - guint idle_id; - guint32 request_id; - char extra_strings[]; + NMDispatcherCallback callback; + 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[]; }; /*****************************************************************************/ @@ -84,14 +88,34 @@ static struct { /*****************************************************************************/ +/* All actions except 'hostname', 'connectivity-change' and 'dns-change' require + * a device */ +static gboolean +action_need_device(NMDispatcherAction action) +{ + if (NM_IN_SET(action, + NM_DISPATCHER_ACTION_HOSTNAME, + NM_DISPATCHER_ACTION_CONNECTIVITY_CHANGE, + NM_DISPATCHER_ACTION_DNS_CHANGE)) { + return FALSE; + } + return TRUE; +} + +static gboolean +action_is_device_handler(NMDispatcherAction action) +{ + return NM_IN_SET(action, NM_DISPATCHER_ACTION_DEVICE_ADD, NM_DISPATCHER_ACTION_DEVICE_DELETE); +} + static NMDispatcherCallId * -dispatcher_call_id_new(guint32 request_id, - gint64 start_at_msec, - NMDispatcherAction action, - NMDispatcherFunc callback, - gpointer user_data, - const char *log_ifname, - const char *log_con_uuid) +dispatcher_call_id_new(guint32 request_id, + gint64 start_at_msec, + NMDispatcherAction action, + NMDispatcherCallback callback, + gpointer user_data, + const char *log_ifname, + const char *log_con_uuid) { NMDispatcherCallId *call_id; gsize l_log_ifname; @@ -109,6 +133,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]; @@ -131,6 +156,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); } @@ -372,20 +398,50 @@ dispatch_result_to_string(DispatchResult result) g_assert_not_reached(); } +/* + * dispatcher_results_process: + * @action: the dispatcher action + * @request_id: request id + * @start_at_msec: the timestamp at which the dispatcher call was started + * @now_msec: the current timestamp in milliseconds + * @log_ifname: the interface name for logging + * @log_con_uuid: the connection UUID for logging + * @out_success: (out): for device-handler actions, the result of the script + * @out_error_msg: (out)(transfer full): for device-handler actions, the + * error message in case of failure + * @out_dict: (out)(transfer full): for device-handler actions, the output + * dictionary in case of success + * @v_results: the GVariant containing the results to parse + * @is_action2: whether the D-Bus method is "Action2()" (or "Action()") + * + * Process the results of the dispatcher call. + * + */ static void -dispatcher_results_process(guint32 request_id, - gint64 start_at_msec, - gint64 now_msec, - const char *log_ifname, - const char *log_con_uuid, - GVariant *v_results) +dispatcher_results_process(NMDispatcherAction action, + guint32 request_id, + gint64 start_at_msec, + gint64 now_msec, + const char *log_ifname, + const char *log_con_uuid, + gboolean *out_success, + char **out_error_msg, + GHashTable **out_dict, + GVariant *v_results, + gboolean is_action2) { nm_auto_free_variant_iter GVariantIter *results = NULL; const char *script, *err; guint32 result; gsize n_children; + gboolean action_is_dh = action_is_device_handler(action); - g_variant_get(v_results, "(a(sus))", &results); + nm_assert(!action_is_dh || is_action2); + + 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); @@ -397,10 +453,26 @@ dispatcher_results_process(guint32 request_id, (int) ((now_msec - start_at_msec) % 1000), n_children); - if (n_children == 0) + if (n_children == 0) { + if (action_is_dh) { + NM_SET_OUT(out_success, FALSE); + NM_SET_OUT(out_error_msg, g_strdup("no result returned from dispatcher service")); + NM_SET_OUT(out_dict, NULL); + } return; + } + + 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; + } - while (g_variant_iter_next(results, "(&su&s)", &script, &result, &err)) { if (result == DISPATCH_RESULT_SUCCESS) { _LOG2D(request_id, log_ifname, log_con_uuid, "%s succeeded", script); } else { @@ -412,22 +484,96 @@ dispatcher_results_process(guint32 request_id, dispatch_result_to_string(result), err); } + + if (action_is_dh) { + if (result == DISPATCH_RESULT_SUCCESS) { + gs_unref_variant GVariant *output_dict = NULL; + gs_unref_hashtable GHashTable *hash = NULL; + GVariantIter iter; + const char *value; + const char *key; + + hash = g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, g_free); + output_dict = + g_variant_lookup_value(options, "output_dict", G_VARIANT_TYPE("a{ss}")); + if (output_dict) { + g_variant_iter_init(&iter, output_dict); + while (g_variant_iter_next(&iter, "{&s&s}", &key, &value)) { + const char *unescaped; + gpointer to_free; + gsize len; + + unescaped = nm_utils_buf_utf8safe_unescape(value, + NM_UTILS_STR_UTF8_SAFE_FLAG_NONE, + &len, + &to_free); + g_hash_table_insert(hash, + g_strdup(key), + ((char *) to_free) ?: g_strdup(unescaped)); + } + } + + NM_SET_OUT(out_success, TRUE); + NM_SET_OUT(out_dict, g_steal_pointer(&hash)); + NM_SET_OUT(out_error_msg, NULL); + } else { + gs_unref_variant GVariant *output_dict = NULL; + const char *err2 = NULL; + + output_dict = + g_variant_lookup_value(options, "output_dict", G_VARIANT_TYPE("a{ss}")); + if (output_dict) { + g_variant_lookup(output_dict, "ERROR", "&s", &err2); + } + + NM_SET_OUT(out_success, FALSE); + NM_SET_OUT(out_dict, NULL); + NM_SET_OUT(out_error_msg, + err2 ? g_strdup_printf("%s (Error: %s)", err, err2) : g_strdup(err)); + } + break; + } } } static void dispatcher_done_cb(GObject *source, GAsyncResult *result, gpointer user_data) { - gs_unref_variant GVariant *ret = NULL; - gs_free_error GError *error = NULL; - NMDispatcherCallId *call_id = user_data; - gint64 now_msec; + gs_unref_variant GVariant *ret = NULL; + gs_free_error GError *error = NULL; + NMDispatcherCallId *call_id = user_data; + gint64 now_msec; + gboolean action_is_dh; + gboolean success = TRUE; + gs_free char *error_msg = NULL; + gs_unref_hashtable GHashTable *hash = NULL; nm_assert((gpointer) source == gl.dbus_connection); 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 && !action_is_device_handler(call_id->action) + && 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; @@ -442,37 +588,55 @@ dispatcher_done_cb(GObject *source, GAsyncResult *result, gpointer user_data) (int) ((now_msec - call_id->start_at_msec) % 1000), error->message); } else { - dispatcher_results_process(call_id->request_id, + dispatcher_results_process(call_id->action, + call_id->request_id, call_id->start_at_msec, now_msec, call_id->log_ifname, call_id->log_con_uuid, - ret); + &success, + &error_msg, + &hash, + ret, + call_id->is_action2); } g_hash_table_remove(gl.requests, call_id); + action_is_dh = action_is_device_handler(call_id->action); + + if (call_id->callback) { + if (action_is_dh) { + NMDispatcherFuncDH cb = (NMDispatcherFuncDH) call_id->callback; + + cb(call_id, call_id->user_data, success, error_msg, hash); + } else { + NMDispatcherFunc cb = (NMDispatcherFunc) call_id->callback; - if (call_id->callback) - call_id->callback(call_id, call_id->user_data); + cb(call_id, call_id->user_data); + } + } dispatcher_call_id_free(call_id); } -static const char *action_table[] = {[NM_DISPATCHER_ACTION_HOSTNAME] = NMD_ACTION_HOSTNAME, - [NM_DISPATCHER_ACTION_PRE_UP] = NMD_ACTION_PRE_UP, - [NM_DISPATCHER_ACTION_UP] = NMD_ACTION_UP, - [NM_DISPATCHER_ACTION_PRE_DOWN] = NMD_ACTION_PRE_DOWN, - [NM_DISPATCHER_ACTION_DOWN] = NMD_ACTION_DOWN, - [NM_DISPATCHER_ACTION_VPN_PRE_UP] = NMD_ACTION_VPN_PRE_UP, - [NM_DISPATCHER_ACTION_VPN_UP] = NMD_ACTION_VPN_UP, - [NM_DISPATCHER_ACTION_VPN_PRE_DOWN] = NMD_ACTION_VPN_PRE_DOWN, - [NM_DISPATCHER_ACTION_VPN_DOWN] = NMD_ACTION_VPN_DOWN, - [NM_DISPATCHER_ACTION_DHCP_CHANGE_4] = NMD_ACTION_DHCP4_CHANGE, - [NM_DISPATCHER_ACTION_DHCP_CHANGE_6] = NMD_ACTION_DHCP6_CHANGE, - [NM_DISPATCHER_ACTION_CONNECTIVITY_CHANGE] = - NMD_ACTION_CONNECTIVITY_CHANGE, - [NM_DISPATCHER_ACTION_REAPPLY] = NMD_ACTION_REAPPLY, - [NM_DISPATCHER_ACTION_DNS_CHANGE] = NMD_ACTION_DNS_CHANGE}; +static const char *action_table[] = { + [NM_DISPATCHER_ACTION_HOSTNAME] = NMD_ACTION_HOSTNAME, + [NM_DISPATCHER_ACTION_PRE_UP] = NMD_ACTION_PRE_UP, + [NM_DISPATCHER_ACTION_UP] = NMD_ACTION_UP, + [NM_DISPATCHER_ACTION_PRE_DOWN] = NMD_ACTION_PRE_DOWN, + [NM_DISPATCHER_ACTION_DOWN] = NMD_ACTION_DOWN, + [NM_DISPATCHER_ACTION_VPN_PRE_UP] = NMD_ACTION_VPN_PRE_UP, + [NM_DISPATCHER_ACTION_VPN_UP] = NMD_ACTION_VPN_UP, + [NM_DISPATCHER_ACTION_VPN_PRE_DOWN] = NMD_ACTION_VPN_PRE_DOWN, + [NM_DISPATCHER_ACTION_VPN_DOWN] = NMD_ACTION_VPN_DOWN, + [NM_DISPATCHER_ACTION_DHCP_CHANGE_4] = NMD_ACTION_DHCP4_CHANGE, + [NM_DISPATCHER_ACTION_DHCP_CHANGE_6] = NMD_ACTION_DHCP6_CHANGE, + [NM_DISPATCHER_ACTION_CONNECTIVITY_CHANGE] = NMD_ACTION_CONNECTIVITY_CHANGE, + [NM_DISPATCHER_ACTION_REAPPLY] = NMD_ACTION_REAPPLY, + [NM_DISPATCHER_ACTION_DNS_CHANGE] = NMD_ACTION_DNS_CHANGE, + [NM_DISPATCHER_ACTION_DEVICE_ADD] = NMD_ACTION_DEVICE_ADD, + [NM_DISPATCHER_ACTION_DEVICE_DELETE] = NMD_ACTION_DEVICE_DELETE, +}; static const char * action_to_string(NMDispatcherAction action) @@ -482,75 +646,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 (!nm_dispatcher_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 = @@ -594,7 +712,7 @@ _dispatcher_call(NMDispatcherAction action, g_variant_builder_init(&vpn_ip6_props, G_VARIANT_TYPE_VARDICT); /* hostname, DNS and connectivity-change actions don't send device data */ - if (nm_dispatcher_need_device(action)) { + if (action_need_device(action)) { fill_device_props(device, &device_props, &device_proxy_props, @@ -609,25 +727,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)); - - start_at_msec = nm_utils_get_monotonic_timestamp_msec(); + 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()); + } + + 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, + NMDispatcherCallback 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) { @@ -638,14 +845,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) { @@ -659,12 +896,17 @@ _dispatcher_call(NMDispatcherAction action, error->message); return FALSE; } - dispatcher_results_process(request_id, + dispatcher_results_process(action, + request_id, start_at_msec, now_msec, log_ifname, log_con_uuid, - ret); + NULL, + NULL, + NULL, + ret, + is_action2); return TRUE; } @@ -676,13 +918,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, @@ -718,11 +972,45 @@ nm_dispatcher_call_hostname(NMDispatcherFunc callback, NM_CONNECTIVITY_UNKNOWN, NULL, NULL, - callback, + (NMDispatcherCallback) callback, user_data, out_call_id); } +static gboolean +_dispatcher_call_device(NMDispatcherAction action, + NMDevice *device, + gboolean blocking, + NMActRequest *act_request, + NMDispatcherCallback callback, + gpointer user_data, + NMDispatcherCallId **out_call_id) +{ + nm_assert(NM_IS_DEVICE(device)); + if (!act_request) { + act_request = nm_device_get_act_request(device); + if (!act_request) + return FALSE; + } + nm_assert(NM_IN_SET(nm_active_connection_get_device(NM_ACTIVE_CONNECTION(act_request)), + NULL, + device)); + return _dispatcher_call( + action, + blocking, + device, + nm_act_request_get_settings_connection(act_request), + nm_act_request_get_applied_connection(act_request), + nm_active_connection_get_activation_type(NM_ACTIVE_CONNECTION(act_request)) + == NM_ACTIVATION_TYPE_EXTERNAL, + NM_CONNECTIVITY_UNKNOWN, + NULL, + NULL, + callback, + user_data, + out_call_id); +} + /** * nm_dispatcher_call_device: * @action: the %NMDispatcherAction @@ -747,29 +1035,50 @@ nm_dispatcher_call_device(NMDispatcherAction action, gpointer user_data, NMDispatcherCallId **out_call_id) { - nm_assert(NM_IS_DEVICE(device)); - if (!act_request) { - act_request = nm_device_get_act_request(device); - if (!act_request) - return FALSE; - } - nm_assert(NM_IN_SET(nm_active_connection_get_device(NM_ACTIVE_CONNECTION(act_request)), - NULL, - device)); - return _dispatcher_call( - action, - FALSE, - device, - nm_act_request_get_settings_connection(act_request), - nm_act_request_get_applied_connection(act_request), - nm_active_connection_get_activation_type(NM_ACTIVE_CONNECTION(act_request)) - == NM_ACTIVATION_TYPE_EXTERNAL, - NM_CONNECTIVITY_UNKNOWN, - NULL, - NULL, - callback, - user_data, - out_call_id); + g_return_val_if_fail(!action_is_device_handler(action), FALSE); + + return _dispatcher_call_device(action, + device, + FALSE, + act_request, + (NMDispatcherCallback) callback, + user_data, + out_call_id); +} + +/** + * nm_dispatcher_call_device_handler: + * @action: the %NMDispatcherAction, must be device-add or device-remove + * @device: the #NMDevice the action applies to + * @act_request: the #NMActRequest for the action. If %NULL, use the + * current request of the device. + * @callback: a caller-supplied device-handler callback to execute when done + * @user_data: caller-supplied pointer passed to @callback + * @out_call_id: on success, a call identifier which can be passed to + * nm_dispatcher_call_cancel() + * + * This method always invokes the device dispatcher action asynchronously. To ignore + * the result, pass %NULL to @callback. + * + * Returns: %TRUE if the action was dispatched, %FALSE on failure + */ +gboolean +nm_dispatcher_call_device_handler(NMDispatcherAction action, + NMDevice *device, + NMActRequest *act_request, + NMDispatcherFuncDH callback, + gpointer user_data, + NMDispatcherCallId **out_call_id) +{ + g_return_val_if_fail(action_is_device_handler(action), FALSE); + + return _dispatcher_call_device(action, + device, + FALSE, + act_request, + (NMDispatcherCallback) callback, + user_data, + out_call_id); } /** @@ -789,29 +1098,9 @@ nm_dispatcher_call_device_sync(NMDispatcherAction action, NMDevice *device, NMActRequest *act_request) { - nm_assert(NM_IS_DEVICE(device)); - if (!act_request) { - act_request = nm_device_get_act_request(device); - if (!act_request) - return FALSE; - } - nm_assert(NM_IN_SET(nm_active_connection_get_device(NM_ACTIVE_CONNECTION(act_request)), - NULL, - device)); - return _dispatcher_call( - action, - TRUE, - device, - nm_act_request_get_settings_connection(act_request), - nm_act_request_get_applied_connection(act_request), - nm_active_connection_get_activation_type(NM_ACTIVE_CONNECTION(act_request)) - == NM_ACTIVATION_TYPE_EXTERNAL, - NM_CONNECTIVITY_UNKNOWN, - NULL, - NULL, - NULL, - NULL, - NULL); + g_return_val_if_fail(!action_is_device_handler(action), FALSE); + + return _dispatcher_call_device(action, device, TRUE, act_request, NULL, NULL, NULL); } /** @@ -852,7 +1141,7 @@ nm_dispatcher_call_vpn(NMDispatcherAction action, NM_CONNECTIVITY_UNKNOWN, vpn_iface, l3cd, - callback, + (NMDispatcherCallback) callback, user_data, out_call_id); } @@ -879,6 +1168,8 @@ nm_dispatcher_call_vpn_sync(NMDispatcherAction action, const char *vpn_iface, const NML3ConfigData *l3cd) { + g_return_val_if_fail(!action_is_device_handler(action), FALSE); + return _dispatcher_call(action, TRUE, parent_device, @@ -920,7 +1211,7 @@ nm_dispatcher_call_connectivity(NMConnectivityState connectivity_state, connectivity_state, NULL, NULL, - callback, + (NMDispatcherCallback) callback, user_data, out_call_id); } @@ -952,7 +1243,10 @@ nm_dispatcher_call_dns_change(void) void nm_dispatcher_call_cancel(NMDispatcherCallId *call_id) { - if (!call_id || g_hash_table_lookup(gl.requests, call_id) != call_id || !call_id->callback) + if (!call_id || g_hash_table_lookup(gl.requests, call_id) != call_id) + g_return_if_reached(); + + if (!call_id->callback) g_return_if_reached(); /* Canceling just means the callback doesn't get called, so set the @@ -961,16 +1255,3 @@ nm_dispatcher_call_cancel(NMDispatcherCallId *call_id) _LOG3D(call_id, "cancelling dispatcher callback action"); call_id->callback = NULL; } - -/* All actions except 'hostname', 'connectivity-change' and 'dns-change' require - * a device */ -static gboolean -nm_dispatcher_need_device(NMDispatcherAction action) -{ - if (action == NM_DISPATCHER_ACTION_HOSTNAME - || action == NM_DISPATCHER_ACTION_CONNECTIVITY_CHANGE - || action == NM_DISPATCHER_ACTION_DNS_CHANGE) { - return FALSE; - } - return TRUE; -} |