Blame src/core/nm-pacrunner-manager.c

Packit Service 5ffa24
/* SPDX-License-Identifier: GPL-2.0-or-later */
Packit Service 5ffa24
/*
Packit Service 5ffa24
 * Copyright (C) 2016 Atul Anand <atulhjp@gmail.com>.
Packit Service 5ffa24
 */
Packit Service 5ffa24
Packit Service 5ffa24
#include "nm-default.h"
Packit Service 5ffa24
Packit Service 5ffa24
#include "nm-pacrunner-manager.h"
Packit Service 5ffa24
Packit Service 5ffa24
#include "nm-utils.h"
Packit Service 5ffa24
#include "NetworkManagerUtils.h"
Packit Service 5ffa24
#include "platform/nm-platform.h"
Packit Service 5ffa24
#include "nm-dbus-manager.h"
Packit Service 5ffa24
#include "nm-proxy-config.h"
Packit Service 5ffa24
#include "nm-ip4-config.h"
Packit Service 5ffa24
#include "nm-ip6-config.h"
Packit Service 5ffa24
#include "c-list/src/c-list.h"
Packit Service 5ffa24
#include "nm-glib-aux/nm-dbus-aux.h"
Packit Service 5ffa24
Packit Service 5ffa24
#define PACRUNNER_DBUS_SERVICE   "org.pacrunner"
Packit Service 5ffa24
#define PACRUNNER_DBUS_INTERFACE "org.pacrunner.Manager"
Packit Service 5ffa24
#define PACRUNNER_DBUS_PATH      "/org/pacrunner/manager"
Packit Service 5ffa24
Packit Service 5ffa24
/*****************************************************************************/
Packit Service 5ffa24
Packit Service 5ffa24
struct _NMPacrunnerConfId {
Packit Service 5ffa24
    CList conf_id_lst;
Packit Service 5ffa24
Packit Service 5ffa24
    NMPacrunnerManager *self;
Packit Service 5ffa24
Packit Service 5ffa24
    GVariant *parameters;
Packit Service 5ffa24
Packit Service 5ffa24
    char *  path;
Packit Service 5ffa24
    guint64 log_id;
Packit Service 5ffa24
    guint   refcount;
Packit Service 5ffa24
};
Packit Service 5ffa24
Packit Service 5ffa24
typedef struct {
Packit Service 5ffa24
    GDBusConnection *dbus_connection;
Packit Service 5ffa24
    GCancellable *   cancellable;
Packit Service 5ffa24
    CList            conf_id_lst_head;
Packit Service 5ffa24
    guint64          log_id_counter;
Packit Service 5ffa24
    guint            name_owner_changed_id;
Packit Service 5ffa24
    bool             dbus_initied : 1;
Packit Service 5ffa24
    bool             has_name_owner : 1;
Packit Service 5ffa24
    bool             try_start_blocked : 1;
Packit Service 5ffa24
} NMPacrunnerManagerPrivate;
Packit Service 5ffa24
Packit Service 5ffa24
struct _NMPacrunnerManager {
Packit Service 5ffa24
    GObject                   parent;
Packit Service 5ffa24
    NMPacrunnerManagerPrivate _priv;
Packit Service 5ffa24
};
Packit Service 5ffa24
Packit Service 5ffa24
struct _NMPacrunnerManagerClass {
Packit Service 5ffa24
    GObjectClass parent;
Packit Service 5ffa24
};
Packit Service 5ffa24
Packit Service 5ffa24
G_DEFINE_TYPE(NMPacrunnerManager, nm_pacrunner_manager, G_TYPE_OBJECT)
Packit Service 5ffa24
Packit Service 5ffa24
#define NM_PACRUNNER_MANAGER_GET_PRIVATE(self) \
Packit Service 5ffa24
    _NM_GET_PRIVATE(self, NMPacrunnerManager, NM_IS_PACRUNNER_MANAGER)
Packit Service 5ffa24
Packit Service 5ffa24
/*****************************************************************************/
Packit Service 5ffa24
Packit Service 5ffa24
NM_DEFINE_SINGLETON_GETTER(NMPacrunnerManager, nm_pacrunner_manager_get, NM_TYPE_PACRUNNER_MANAGER);
Packit Service 5ffa24
Packit Service 5ffa24
/*****************************************************************************/
Packit Service 5ffa24
Packit Service 5ffa24
#define _NMLOG_DOMAIN      LOGD_PROXY
Packit Service 5ffa24
#define _NMLOG(level, ...) __NMLOG_DEFAULT(level, _NMLOG_DOMAIN, "pacrunner", __VA_ARGS__)
Packit Service 5ffa24
Packit Service 5ffa24
#define _NMLOG2_PREFIX_NAME "pacrunner"
Packit Service 5ffa24
#define _NMLOG2(level, conf_id, ...)                                            \
Packit Service 5ffa24
    G_STMT_START                                                                \
Packit Service 5ffa24
    {                                                                           \
Packit Service 5ffa24
        nm_log((level),                                                         \
Packit Service 5ffa24
               _NMLOG_DOMAIN,                                                   \
Packit Service 5ffa24
               NULL,                                                            \
Packit Service 5ffa24
               NULL,                                                            \
Packit Service 5ffa24
               "%s%" G_GUINT64_FORMAT "]: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
Packit Service 5ffa24
               _NMLOG2_PREFIX_NAME ": call[",                                   \
Packit Service 5ffa24
               (conf_id)->log_id _NM_UTILS_MACRO_REST(__VA_ARGS__));            \
Packit Service 5ffa24
    }                                                                           \
Packit Service 5ffa24
    G_STMT_END
Packit Service 5ffa24
Packit Service 5ffa24
/*****************************************************************************/
Packit Service 5ffa24
Packit Service 5ffa24
static void _call_destroy_proxy_configuration(NMPacrunnerManager *self,
Packit Service 5ffa24
                                              NMPacrunnerConfId * conf_id,
Packit Service 5ffa24
                                              const char *        path,
Packit Service 5ffa24
                                              gboolean            verbose_log);
Packit Service 5ffa24
Packit Service 5ffa24
/*****************************************************************************/
Packit Service 5ffa24
Packit Service 5ffa24
static NMPacrunnerConfId *
Packit Service 5ffa24
conf_id_ref(NMPacrunnerConfId *conf_id)
Packit Service 5ffa24
{
Packit Service 5ffa24
    nm_assert(conf_id);
Packit Service 5ffa24
    nm_assert(conf_id->refcount > 0);
Packit Service 5ffa24
Packit Service 5ffa24
    conf_id->refcount++;
Packit Service 5ffa24
    return conf_id;
Packit Service 5ffa24
}
Packit Service 5ffa24
Packit Service 5ffa24
static void
Packit Service 5ffa24
conf_id_unref(NMPacrunnerConfId *conf_id)
Packit Service 5ffa24
{
Packit Service 5ffa24
    nm_assert(conf_id);
Packit Service 5ffa24
    nm_assert(conf_id->refcount > 0);
Packit Service 5ffa24
Packit Service 5ffa24
    if (conf_id->refcount == 1) {
Packit Service 5ffa24
        g_variant_unref(conf_id->parameters);
Packit Service 5ffa24
        g_free(conf_id->path);
Packit Service 5ffa24
        c_list_unlink_stale(&conf_id->conf_id_lst);
Packit Service 5ffa24
        g_object_unref(conf_id->self);
Packit Service 5ffa24
        g_slice_free(NMPacrunnerConfId, conf_id);
Packit Service 5ffa24
    } else
Packit Service 5ffa24
        conf_id->refcount--;
Packit Service 5ffa24
}
Packit Service 5ffa24
Packit Service 5ffa24
NM_AUTO_DEFINE_FCN0(NMPacrunnerConfId *, _nm_auto_unref_conf_id, conf_id_unref);
Packit Service 5ffa24
#define nm_auto_unref_conf_id nm_auto(_nm_auto_unref_conf_id)
Packit Service 5ffa24
Packit Service 5ffa24
/*****************************************************************************/
Packit Service 5ffa24
Packit Service 5ffa24
static void
Packit Service 5ffa24
get_ip_domains(GPtrArray *domains, NMIPConfig *ip_config)
Packit Service 5ffa24
{
Packit Service 5ffa24
    NMDedupMultiIter           ipconf_iter;
Packit Service 5ffa24
    char *                     cidr;
Packit Service 5ffa24
    guint                      i, num;
Packit Service 5ffa24
    char                       sbuf[NM_UTILS_INET_ADDRSTRLEN];
Packit Service 5ffa24
    int                        addr_family;
Packit Service 5ffa24
    const NMPlatformIPAddress *address;
Packit Service 5ffa24
    const NMPlatformIPRoute *  routes;
Packit Service 5ffa24
Packit Service 5ffa24
    if (!ip_config)
Packit Service 5ffa24
        return;
Packit Service 5ffa24
Packit Service 5ffa24
    addr_family = nm_ip_config_get_addr_family(ip_config);
Packit Service 5ffa24
Packit Service 5ffa24
    num = nm_ip_config_get_num_searches(ip_config);
Packit Service 5ffa24
    for (i = 0; i < num; i++)
Packit Service 5ffa24
        g_ptr_array_add(domains, g_strdup(nm_ip_config_get_search(ip_config, i)));
Packit Service 5ffa24
Packit Service 5ffa24
    num = nm_ip_config_get_num_domains(ip_config);
Packit Service 5ffa24
    for (i = 0; i < num; i++)
Packit Service 5ffa24
        g_ptr_array_add(domains, g_strdup(nm_ip_config_get_domain(ip_config, i)));
Packit Service 5ffa24
Packit Service 5ffa24
    nm_ip_config_iter_ip_address_for_each (&ipconf_iter, ip_config, &address) {
Packit Service 5ffa24
        cidr = g_strdup_printf("%s/%u",
Packit Service 5ffa24
                               nm_utils_inet_ntop(addr_family, address->address_ptr, sbuf),
Packit Service 5ffa24
                               address->plen);
Packit Service 5ffa24
        g_ptr_array_add(domains, cidr);
Packit Service 5ffa24
    }
Packit Service 5ffa24
Packit Service 5ffa24
    nm_ip_config_iter_ip_route_for_each (&ipconf_iter, ip_config, &routes) {
Packit Service 5ffa24
        if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT(routes))
Packit Service 5ffa24
            continue;
Packit Service 5ffa24
        cidr = g_strdup_printf("%s/%u",
Packit Service 5ffa24
                               nm_utils_inet_ntop(addr_family, routes->network_ptr, sbuf),
Packit Service 5ffa24
                               routes->plen);
Packit Service 5ffa24
        g_ptr_array_add(domains, cidr);
Packit Service 5ffa24
    }
Packit Service 5ffa24
}
Packit Service 5ffa24
Packit Service 5ffa24
static GVariant *
Packit Service 5ffa24
_make_request_create_proxy_configuration(NMProxyConfig *proxy_config,
Packit Service 5ffa24
                                         const char *   iface,
Packit Service 5ffa24
                                         NMIP4Config *  ip4_config,
Packit Service 5ffa24
                                         NMIP6Config *  ip6_config)
Packit Service 5ffa24
{
Packit Service 5ffa24
    GVariantBuilder     builder;
Packit Service 5ffa24
    NMProxyConfigMethod method;
Packit Service 5ffa24
    const char *        pac_url;
Packit Service 5ffa24
    const char *        pac_script;
Packit Service 5ffa24
Packit Service 5ffa24
    nm_assert(NM_IS_PROXY_CONFIG(proxy_config));
Packit Service 5ffa24
Packit Service 5ffa24
    g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
Packit Service 5ffa24
Packit Service 5ffa24
    if (iface) {
Packit Service 5ffa24
        g_variant_builder_add(&builder, "{sv}", "Interface", g_variant_new_string(iface));
Packit Service 5ffa24
    }
Packit Service 5ffa24
Packit Service 5ffa24
    method = nm_proxy_config_get_method(proxy_config);
Packit Service 5ffa24
    switch (method) {
Packit Service 5ffa24
    case NM_PROXY_CONFIG_METHOD_AUTO:
Packit Service 5ffa24
        g_variant_builder_add(&builder, "{sv}", "Method", g_variant_new_string("auto"));
Packit Service 5ffa24
Packit Service 5ffa24
        pac_url = nm_proxy_config_get_pac_url(proxy_config);
Packit Service 5ffa24
        if (pac_url) {
Packit Service 5ffa24
            g_variant_builder_add(&builder, "{sv}", "URL", g_variant_new_string(pac_url));
Packit Service 5ffa24
        }
Packit Service 5ffa24
Packit Service 5ffa24
        pac_script = nm_proxy_config_get_pac_script(proxy_config);
Packit Service 5ffa24
        if (pac_script) {
Packit Service 5ffa24
            g_variant_builder_add(&builder, "{sv}", "Script", g_variant_new_string(pac_script));
Packit Service 5ffa24
        }
Packit Service 5ffa24
        break;
Packit Service 5ffa24
    case NM_PROXY_CONFIG_METHOD_NONE:
Packit Service 5ffa24
        g_variant_builder_add(&builder, "{sv}", "Method", g_variant_new_string("direct"));
Packit Service 5ffa24
        break;
Packit Service 5ffa24
    }
Packit Service 5ffa24
Packit Service 5ffa24
    g_variant_builder_add(&builder,
Packit Service 5ffa24
                          "{sv}",
Packit Service 5ffa24
                          "BrowserOnly",
Packit Service 5ffa24
                          g_variant_new_boolean(nm_proxy_config_get_browser_only(proxy_config)));
Packit Service 5ffa24
Packit Service 5ffa24
    if (ip4_config || ip6_config) {
Packit Service 5ffa24
        gs_unref_ptrarray GPtrArray *domains = NULL;
Packit Service 5ffa24
Packit Service 5ffa24
        domains = g_ptr_array_new_with_free_func(g_free);
Packit Service 5ffa24
Packit Service 5ffa24
        get_ip_domains(domains, NM_IP_CONFIG_CAST(ip4_config));
Packit Service 5ffa24
        get_ip_domains(domains, NM_IP_CONFIG_CAST(ip6_config));
Packit Service 5ffa24
Packit Service 5ffa24
        if (domains->len > 0) {
Packit Service 5ffa24
            g_variant_builder_add(
Packit Service 5ffa24
                &builder,
Packit Service 5ffa24
                "{sv}",
Packit Service 5ffa24
                "Domains",
Packit Service 5ffa24
                g_variant_new_strv((const char *const *) domains->pdata, domains->len));
Packit Service 5ffa24
        }
Packit Service 5ffa24
    }
Packit Service 5ffa24
Packit Service 5ffa24
    return g_variant_new("(a{sv})", &builder);
Packit Service 5ffa24
}
Packit Service 5ffa24
Packit Service 5ffa24
/*****************************************************************************/
Packit Service 5ffa24
Packit Service 5ffa24
static void
Packit Service 5ffa24
_call_destroy_proxy_configuration_cb(GObject *source, GAsyncResult *res, gpointer user_data)
Packit Service 5ffa24
{
Packit Service 5ffa24
    nm_auto_unref_conf_id NMPacrunnerConfId *conf_id = user_data;
Packit Service 5ffa24
    gs_free_error GError *error                      = NULL;
Packit Service 5ffa24
    gs_unref_variant GVariant *ret                   = NULL;
Packit Service 5ffa24
Packit Service 5ffa24
    ret = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), res, &error);
Packit Service 5ffa24
    if (!ret) {
Packit Service 5ffa24
        if (!g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
Packit Service 5ffa24
            _LOG2T(conf_id, "destroy proxy configuration: failed with %s", error->message);
Packit Service 5ffa24
        else
Packit Service 5ffa24
            _LOG2T(conf_id, "destroy proxy configuration: cancelled");
Packit Service 5ffa24
        return;
Packit Service 5ffa24
    }
Packit Service 5ffa24
    _LOG2T(conf_id, "destroy proxy configuration: success");
Packit Service 5ffa24
}
Packit Service 5ffa24
Packit Service 5ffa24
static void
Packit Service 5ffa24
_call_create_proxy_configuration_cb(GObject *source, GAsyncResult *res, gpointer user_data)
Packit Service 5ffa24
{
Packit Service 5ffa24
    nm_auto_unref_conf_id NMPacrunnerConfId *conf_id = user_data;
Packit Service 5ffa24
    NMPacrunnerManager *                     self    = NM_PACRUNNER_MANAGER(conf_id->self);
Packit Service 5ffa24
    gs_free_error GError *error                      = NULL;
Packit Service 5ffa24
    gs_unref_variant GVariant *variant               = NULL;
Packit Service 5ffa24
    const char *               path                  = NULL;
Packit Service 5ffa24
Packit Service 5ffa24
    nm_assert(!conf_id->path);
Packit Service 5ffa24
Packit Service 5ffa24
    variant = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), res, &error);
Packit Service 5ffa24
Packit Service 5ffa24
    if (!variant) {
Packit Service 5ffa24
        if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
Packit Service 5ffa24
            _LOG2T(conf_id, "create proxy configuration failed: %s", error->message);
Packit Service 5ffa24
        else
Packit Service 5ffa24
            _LOG2T(conf_id, "create proxy configuration cancelled");
Packit Service 5ffa24
        return;
Packit Service 5ffa24
    }
Packit Service 5ffa24
Packit Service 5ffa24
    g_variant_get(variant, "(&o)", &path);
Packit Service 5ffa24
Packit Service 5ffa24
    if (c_list_is_empty(&conf_id->conf_id_lst)) {
Packit Service 5ffa24
        _LOG2T(conf_id,
Packit Service 5ffa24
               "create proxy configuration succeeded (%s), but destroy it right away",
Packit Service 5ffa24
               path);
Packit Service 5ffa24
        _call_destroy_proxy_configuration(self, conf_id, path, FALSE);
Packit Service 5ffa24
    } else {
Packit Service 5ffa24
        _LOG2T(conf_id, "create proxy configuration succeeded (%s)", path);
Packit Service 5ffa24
        conf_id->path = g_strdup(path);
Packit Service 5ffa24
    }
Packit Service 5ffa24
}
Packit Service 5ffa24
Packit Service 5ffa24
static void
Packit Service 5ffa24
_call_destroy_proxy_configuration(NMPacrunnerManager *self,
Packit Service 5ffa24
                                  NMPacrunnerConfId * conf_id,
Packit Service 5ffa24
                                  const char *        path,
Packit Service 5ffa24
                                  gboolean            verbose_log)
Packit Service 5ffa24
{
Packit Service 5ffa24
    NMPacrunnerManagerPrivate *priv = NM_PACRUNNER_MANAGER_GET_PRIVATE(self);
Packit Service 5ffa24
Packit Service 5ffa24
    if (verbose_log)
Packit Service 5ffa24
        _LOG2T(conf_id, "destroy proxy configuration %s...", path);
Packit Service 5ffa24
Packit Service 5ffa24
    g_dbus_connection_call(priv->dbus_connection,
Packit Service 5ffa24
                           PACRUNNER_DBUS_SERVICE,
Packit Service 5ffa24
                           PACRUNNER_DBUS_PATH,
Packit Service 5ffa24
                           PACRUNNER_DBUS_INTERFACE,
Packit Service 5ffa24
                           "DestroyProxyConfiguration",
Packit Service 5ffa24
                           g_variant_new("(o)", path),
Packit Service 5ffa24
                           G_VARIANT_TYPE("()"),
Packit Service 5ffa24
                           G_DBUS_CALL_FLAGS_NO_AUTO_START,
Packit Service 5ffa24
                           NM_SHUTDOWN_TIMEOUT_MS,
Packit Service 5ffa24
                           priv->cancellable,
Packit Service 5ffa24
                           _call_destroy_proxy_configuration_cb,
Packit Service 5ffa24
                           conf_id_ref(conf_id));
Packit Service 5ffa24
}
Packit Service 5ffa24
Packit Service 5ffa24
static void
Packit Service 5ffa24
_call_create_proxy_configuration(NMPacrunnerManager *self,
Packit Service 5ffa24
                                 NMPacrunnerConfId * conf_id,
Packit Service 5ffa24
                                 gboolean            verbose_log)
Packit Service 5ffa24
{
Packit Service 5ffa24
    NMPacrunnerManagerPrivate *priv = NM_PACRUNNER_MANAGER_GET_PRIVATE(self);
Packit Service 5ffa24
Packit Service 5ffa24
    if (verbose_log)
Packit Service 5ffa24
        _LOG2T(conf_id, "create proxy configuration...");
Packit Service 5ffa24
Packit Service 5ffa24
    g_dbus_connection_call(priv->dbus_connection,
Packit Service 5ffa24
                           PACRUNNER_DBUS_SERVICE,
Packit Service 5ffa24
                           PACRUNNER_DBUS_PATH,
Packit Service 5ffa24
                           PACRUNNER_DBUS_INTERFACE,
Packit Service 5ffa24
                           "CreateProxyConfiguration",
Packit Service 5ffa24
                           conf_id->parameters,
Packit Service 5ffa24
                           G_VARIANT_TYPE("(o)"),
Packit Service 5ffa24
                           G_DBUS_CALL_FLAGS_NO_AUTO_START,
Packit Service 5ffa24
                           NM_SHUTDOWN_TIMEOUT_MS,
Packit Service 5ffa24
                           priv->cancellable,
Packit Service 5ffa24
                           _call_create_proxy_configuration_cb,
Packit Service 5ffa24
                           conf_id_ref(conf_id));
Packit Service 5ffa24
}
Packit Service 5ffa24
Packit Service 5ffa24
static gboolean
Packit Service 5ffa24
_try_start_service_by_name(NMPacrunnerManager *self)
Packit Service 5ffa24
{
Packit Service 5ffa24
    NMPacrunnerManagerPrivate *priv = NM_PACRUNNER_MANAGER_GET_PRIVATE(self);
Packit Service 5ffa24
Packit Service 5ffa24
    if (priv->try_start_blocked || !priv->dbus_initied)
Packit Service 5ffa24
        return FALSE;
Packit Service 5ffa24
Packit Service 5ffa24
    _LOGD("try D-Bus activating pacrunner...");
Packit Service 5ffa24
    priv->try_start_blocked = TRUE;
Packit Service 5ffa24
    nm_dbus_connection_call_start_service_by_name(priv->dbus_connection,
Packit Service 5ffa24
                                                  PACRUNNER_DBUS_SERVICE,
Packit Service 5ffa24
                                                  -1,
Packit Service 5ffa24
                                                  NULL,
Packit Service 5ffa24
                                                  NULL,
Packit Service 5ffa24
                                                  NULL);
Packit Service 5ffa24
    return TRUE;
Packit Service 5ffa24
}
Packit Service 5ffa24
Packit Service 5ffa24
/*****************************************************************************/
Packit Service 5ffa24
Packit Service 5ffa24
/**
Packit Service 5ffa24
 * nm_pacrunner_manager_add:
Packit Service 5ffa24
 * @self: the #NMPacrunnerManager
Packit Service 5ffa24
 * @proxy_config: proxy config of the connection
Packit Service 5ffa24
 * @iface: the iface for the connection or %NULL
Packit Service 5ffa24
 * @ip4_config: IP4 config of the connection to extract domain info from
Packit Service 5ffa24
 * @ip6_config: IP6 config of the connection to extract domain info from
Packit Service 5ffa24
 *
Packit Service 5ffa24
 * Returns: a #NMPacrunnerConfId id. The function cannot
Packit Service 5ffa24
 *  fail and always returns a non NULL pointer. The conf-id may
Packit Service 5ffa24
 *  be used to remove the configuration later via nm_pacrunner_manager_remove().
Packit Service 5ffa24
 *  Note that the conf-id keeps the @self instance alive.
Packit Service 5ffa24
 */
Packit Service 5ffa24
NMPacrunnerConfId *
Packit Service 5ffa24
nm_pacrunner_manager_add(NMPacrunnerManager *self,
Packit Service 5ffa24
                         NMProxyConfig *     proxy_config,
Packit Service 5ffa24
                         const char *        iface,
Packit Service 5ffa24
                         NMIP4Config *       ip4_config,
Packit Service 5ffa24
                         NMIP6Config *       ip6_config)
Packit Service 5ffa24
{
Packit Service 5ffa24
    NMPacrunnerManagerPrivate *priv;
Packit Service 5ffa24
    NMPacrunnerConfId *        conf_id;
Packit Service 5ffa24
    gs_free char *             log_msg = NULL;
Packit Service 5ffa24
Packit Service 5ffa24
    g_return_val_if_fail(NM_IS_PACRUNNER_MANAGER(self), NULL);
Packit Service 5ffa24
    g_return_val_if_fail(proxy_config, NULL);
Packit Service 5ffa24
Packit Service 5ffa24
    priv = NM_PACRUNNER_MANAGER_GET_PRIVATE(self);
Packit Service 5ffa24
Packit Service 5ffa24
    conf_id  = g_slice_new(NMPacrunnerConfId);
Packit Service 5ffa24
    *conf_id = (NMPacrunnerConfId){
Packit Service 5ffa24
        .log_id     = ++priv->log_id_counter,
Packit Service 5ffa24
        .refcount   = 1,
Packit Service 5ffa24
        .self       = g_object_ref(self),
Packit Service 5ffa24
        .parameters = g_variant_ref_sink(
Packit Service 5ffa24
            _make_request_create_proxy_configuration(proxy_config, iface, ip4_config, ip6_config)),
Packit Service 5ffa24
    };
Packit Service 5ffa24
    c_list_link_tail(&priv->conf_id_lst_head, &conf_id->conf_id_lst);
Packit Service 5ffa24
Packit Service 5ffa24
    if (!priv->has_name_owner) {
Packit Service 5ffa24
        _LOG2T(conf_id,
Packit Service 5ffa24
               "add config: %s (%s)",
Packit Service 5ffa24
               (log_msg = g_variant_print(conf_id->parameters, FALSE)),
Packit Service 5ffa24
               "pacrunner D-Bus service not running");
Packit Service 5ffa24
        _try_start_service_by_name(self);
Packit Service 5ffa24
    } else {
Packit Service 5ffa24
        _LOG2T(conf_id,
Packit Service 5ffa24
               "add config: %s (%s)",
Packit Service 5ffa24
               (log_msg = g_variant_print(conf_id->parameters, FALSE)),
Packit Service 5ffa24
               "create proxy configuration");
Packit Service 5ffa24
        _call_create_proxy_configuration(self, conf_id, FALSE);
Packit Service 5ffa24
    }
Packit Service 5ffa24
Packit Service 5ffa24
    return conf_id;
Packit Service 5ffa24
}
Packit Service 5ffa24
Packit Service 5ffa24
/**
Packit Service 5ffa24
 * nm_pacrunner_manager_remove:
Packit Service 5ffa24
 * @conf_id: the conf id obtained from nm_pacrunner_manager_add()
Packit Service 5ffa24
 */
Packit Service 5ffa24
void
Packit Service 5ffa24
nm_pacrunner_manager_remove(NMPacrunnerConfId *conf_id)
Packit Service 5ffa24
{
Packit Service 5ffa24
    _nm_unused nm_auto_unref_conf_id NMPacrunnerConfId *conf_id_free = conf_id;
Packit Service 5ffa24
    NMPacrunnerManager *                                self;
Packit Service 5ffa24
    NMPacrunnerManagerPrivate *                         priv;
Packit Service 5ffa24
Packit Service 5ffa24
    g_return_if_fail(conf_id);
Packit Service 5ffa24
Packit Service 5ffa24
    self = conf_id->self;
Packit Service 5ffa24
Packit Service 5ffa24
    g_return_if_fail(NM_IS_PACRUNNER_MANAGER(self));
Packit Service 5ffa24
Packit Service 5ffa24
    priv = NM_PACRUNNER_MANAGER_GET_PRIVATE(self);
Packit Service 5ffa24
Packit Service 5ffa24
    _LOG2T(conf_id, "removing...");
Packit Service 5ffa24
Packit Service 5ffa24
    nm_assert(c_list_contains(&priv->conf_id_lst_head, &conf_id->conf_id_lst));
Packit Service 5ffa24
Packit Service 5ffa24
    c_list_unlink(&conf_id->conf_id_lst);
Packit Service 5ffa24
Packit Service 5ffa24
    if (!conf_id->path) {
Packit Service 5ffa24
        /* There is no ID to destroy the configuration.
Packit Service 5ffa24
         *
Packit Service 5ffa24
         * That can happen because:
Packit Service 5ffa24
         *
Packit Service 5ffa24
         *  - pacrunner D-Bus service is not running (no name owner) and we didn't call CreateProxyConfiguration.
Packit Service 5ffa24
         *  - CreateProxyConfiguration failed.
Packit Service 5ffa24
         *  - CreateProxyConfiguration is in progress.
Packit Service 5ffa24
         *
Packit Service 5ffa24
         * In all cases there is nothing to do. Note that if CreateProxyConfiguration is in progress
Packit Service 5ffa24
         * it has a reference on the conf-id and it will automatically destroy the configuration
Packit Service 5ffa24
         * when it completes.
Packit Service 5ffa24
         */
Packit Service 5ffa24
        return;
Packit Service 5ffa24
    }
Packit Service 5ffa24
Packit Service 5ffa24
    _call_destroy_proxy_configuration(self, conf_id, conf_id->path, TRUE);
Packit Service 5ffa24
}
Packit Service 5ffa24
Packit Service 5ffa24
gboolean
Packit Service 5ffa24
nm_pacrunner_manager_remove_clear(NMPacrunnerConfId **p_conf_id)
Packit Service 5ffa24
{
Packit Service 5ffa24
    g_return_val_if_fail(p_conf_id, FALSE);
Packit Service 5ffa24
Packit Service 5ffa24
    if (!*p_conf_id)
Packit Service 5ffa24
        return FALSE;
Packit Service 5ffa24
    nm_pacrunner_manager_remove(g_steal_pointer(p_conf_id));
Packit Service 5ffa24
    return TRUE;
Packit Service 5ffa24
}
Packit Service 5ffa24
Packit Service 5ffa24
/*****************************************************************************/
Packit Service 5ffa24
Packit Service 5ffa24
static void
Packit Service 5ffa24
name_owner_changed(NMPacrunnerManager *self, const char *name_owner)
Packit Service 5ffa24
{
Packit Service 5ffa24
    NMPacrunnerManagerPrivate *priv = NM_PACRUNNER_MANAGER_GET_PRIVATE(self);
Packit Service 5ffa24
    NMPacrunnerConfId *        conf_id;
Packit Service 5ffa24
    gboolean                   has_name_owner;
Packit Service 5ffa24
Packit Service 5ffa24
    has_name_owner = (name_owner && name_owner[0]);
Packit Service 5ffa24
Packit Service 5ffa24
    if (priv->dbus_initied && priv->has_name_owner == has_name_owner)
Packit Service 5ffa24
        return;
Packit Service 5ffa24
Packit Service 5ffa24
    priv->has_name_owner = has_name_owner;
Packit Service 5ffa24
Packit Service 5ffa24
    nm_clear_g_cancellable(&priv->cancellable);
Packit Service 5ffa24
Packit Service 5ffa24
    if (has_name_owner) {
Packit Service 5ffa24
        priv->dbus_initied      = TRUE;
Packit Service 5ffa24
        priv->try_start_blocked = FALSE;
Packit Service 5ffa24
        _LOGD("pacrunner appeared on D-Bus (%s)", name_owner);
Packit Service 5ffa24
        priv->cancellable = g_cancellable_new();
Packit Service 5ffa24
        c_list_for_each_entry (conf_id, &priv->conf_id_lst_head, conf_id_lst)
Packit Service 5ffa24
            _call_create_proxy_configuration(self, conf_id, TRUE);
Packit Service 5ffa24
    } else {
Packit Service 5ffa24
        if (!priv->dbus_initied) {
Packit Service 5ffa24
            priv->dbus_initied = TRUE;
Packit Service 5ffa24
            nm_assert(!priv->try_start_blocked);
Packit Service 5ffa24
            _LOGD("pacrunner not on D-Bus");
Packit Service 5ffa24
        } else
Packit Service 5ffa24
            _LOGD("pacrunner disappeared from D-Bus");
Packit Service 5ffa24
        if (!c_list_is_empty(&priv->conf_id_lst_head)) {
Packit Service 5ffa24
            c_list_for_each_entry (conf_id, &priv->conf_id_lst_head, conf_id_lst)
Packit Service 5ffa24
                nm_clear_g_free(&conf_id->path);
Packit Service 5ffa24
            _try_start_service_by_name(self);
Packit Service 5ffa24
        }
Packit Service 5ffa24
    }
Packit Service 5ffa24
}
Packit Service 5ffa24
Packit Service 5ffa24
static void
Packit Service 5ffa24
name_owner_changed_cb(GDBusConnection *connection,
Packit Service 5ffa24
                      const char *     sender_name,
Packit Service 5ffa24
                      const char *     object_path,
Packit Service 5ffa24
                      const char *     interface_name,
Packit Service 5ffa24
                      const char *     signal_name,
Packit Service 5ffa24
                      GVariant *       parameters,
Packit Service 5ffa24
                      gpointer         user_data)
Packit Service 5ffa24
{
Packit Service 5ffa24
    const char *new_owner;
Packit Service 5ffa24
Packit Service 5ffa24
    if (!g_variant_is_of_type(parameters, G_VARIANT_TYPE("(sss)")))
Packit Service 5ffa24
        return;
Packit Service 5ffa24
Packit Service 5ffa24
    g_variant_get(parameters, "(&s&s&s)", NULL, NULL, &new_owner);
Packit Service 5ffa24
Packit Service 5ffa24
    name_owner_changed(user_data, new_owner);
Packit Service 5ffa24
}
Packit Service 5ffa24
Packit Service 5ffa24
static void
Packit Service 5ffa24
get_name_owner_cb(const char *name_owner, GError *error, gpointer user_data)
Packit Service 5ffa24
{
Packit Service 5ffa24
    if (!name_owner && g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
Packit Service 5ffa24
        return;
Packit Service 5ffa24
Packit Service 5ffa24
    name_owner_changed(user_data, name_owner);
Packit Service 5ffa24
}
Packit Service 5ffa24
Packit Service 5ffa24
/*****************************************************************************/
Packit Service 5ffa24
Packit Service 5ffa24
static void
Packit Service 5ffa24
nm_pacrunner_manager_init(NMPacrunnerManager *self)
Packit Service 5ffa24
{
Packit Service 5ffa24
    NMPacrunnerManagerPrivate *priv = NM_PACRUNNER_MANAGER_GET_PRIVATE(self);
Packit Service 5ffa24
Packit Service 5ffa24
    c_list_init(&priv->conf_id_lst_head);
Packit Service 5ffa24
Packit Service 5ffa24
    priv->dbus_connection = nm_g_object_ref(NM_MAIN_DBUS_CONNECTION_GET);
Packit Service 5ffa24
Packit Service 5ffa24
    if (!priv->dbus_connection) {
Packit Service 5ffa24
        _LOGD("no D-Bus connection to talk to pacrunner");
Packit Service 5ffa24
        return;
Packit Service 5ffa24
    }
Packit Service 5ffa24
Packit Service 5ffa24
    priv->name_owner_changed_id =
Packit Service 5ffa24
        nm_dbus_connection_signal_subscribe_name_owner_changed(priv->dbus_connection,
Packit Service 5ffa24
                                                               PACRUNNER_DBUS_SERVICE,
Packit Service 5ffa24
                                                               name_owner_changed_cb,
Packit Service 5ffa24
                                                               self,
Packit Service 5ffa24
                                                               NULL);
Packit Service 5ffa24
    priv->cancellable = g_cancellable_new();
Packit Service 5ffa24
Packit Service 5ffa24
    nm_dbus_connection_call_get_name_owner(priv->dbus_connection,
Packit Service 5ffa24
                                           PACRUNNER_DBUS_SERVICE,
Packit Service 5ffa24
                                           -1,
Packit Service 5ffa24
                                           priv->cancellable,
Packit Service 5ffa24
                                           get_name_owner_cb,
Packit Service 5ffa24
                                           self);
Packit Service 5ffa24
}
Packit Service 5ffa24
Packit Service 5ffa24
static void
Packit Service 5ffa24
dispose(GObject *object)
Packit Service 5ffa24
{
Packit Service 5ffa24
    NMPacrunnerManagerPrivate *priv = NM_PACRUNNER_MANAGER_GET_PRIVATE(object);
Packit Service 5ffa24
Packit Service 5ffa24
    nm_assert(c_list_is_empty(&priv->conf_id_lst_head));
Packit Service 5ffa24
Packit Service 5ffa24
    /* we cancel all pending operations. Note that pacrunner automatically
Packit Service 5ffa24
     * removes all configuration once NetworkManager disconnects from
Packit Service 5ffa24
     * the bus -- which happens soon after we destroy the pacrunner manager.
Packit Service 5ffa24
     */
Packit Service 5ffa24
    nm_clear_g_cancellable(&priv->cancellable);
Packit Service 5ffa24
Packit Service 5ffa24
    nm_clear_g_dbus_connection_signal(priv->dbus_connection, &priv->name_owner_changed_id);
Packit Service 5ffa24
    g_clear_object(&priv->dbus_connection);
Packit Service 5ffa24
Packit Service 5ffa24
    G_OBJECT_CLASS(nm_pacrunner_manager_parent_class)->dispose(object);
Packit Service 5ffa24
}
Packit Service 5ffa24
Packit Service 5ffa24
static void
Packit Service 5ffa24
nm_pacrunner_manager_class_init(NMPacrunnerManagerClass *klass)
Packit Service 5ffa24
{
Packit Service 5ffa24
    GObjectClass *object_class = G_OBJECT_CLASS(klass);
Packit Service 5ffa24
Packit Service 5ffa24
    object_class->dispose = dispose;
Packit Service 5ffa24
}