Blame keepalived/vrrp/vrrp_dbus.c

Packit Service 5956c7
/*
Packit Service 5956c7
 * Soft:        Keepalived is a failover program for the LVS project
Packit Service 5956c7
 *              <www.linuxvirtualserver.org>. It monitor & manipulate
Packit Service 5956c7
 *              a loadbalanced server pool using multi-layer checks.
Packit Service 5956c7
 *
Packit Service 5956c7
 * Part:        DBus server thread for VRRP
Packit Service 5956c7
 *
Packit Service 5956c7
 * Author:      Alexandre Cassen, <acassen@linux-vs.org>
Packit Service 5956c7
 *
Packit Service 5956c7
 *              This program is distributed in the hope that it will be useful,
Packit Service 5956c7
 *              but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 5956c7
 *              MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Packit Service 5956c7
 *              See the GNU General Public License for more details.
Packit Service 5956c7
 *
Packit Service 5956c7
 *              This program is free software; you can redistribute it and/or
Packit Service 5956c7
 *              modify it under the terms of the GNU General Public License
Packit Service 5956c7
 *              as published by the Free Software Foundation; either version
Packit Service 5956c7
 *              2 of the License, or (at your option) any later version.
Packit Service 5956c7
 *
Packit Service 5956c7
 * Copyright (C) 2016-2017 Alexandre Cassen, <acassen@gmail.com>
Packit Service 5956c7
 */
Packit Service 5956c7
Packit Service 5956c7
/* See https://git.gnome.org/browse/glib/tree/gio/tests/fdbus-example-server.c
Packit Service 5956c7
 * and https://developer.gnome.org/gio/stable/GDBusConnection.html#gdbus-server
Packit Service 5956c7
 * for examples of coding.
Packit Service 5956c7
 *
Packit Service 5956c7
 * Create a general /org/keepalived/Vrrp1/Vrrp DBus
Packit Service 5956c7
 * object and a /org/keepalived/Vrrp1/Instance/#interface#/#group# object for
Packit Service 5956c7
 * each VRRP instance.
Packit Service 5956c7
 * Interface org.keepalived.Vrrp1.Vrrp implements methods PrintData,
Packit Service 5956c7
 * PrintStats and signal VrrpStopped.
Packit Service 5956c7
 * Interface com.keepalived.Vrrp1.Instance implements method SendGarp
Packit Service 5956c7
 * (sends a single Gratuitous ARP from the given Instance),
Packit Service 5956c7
 * signal VrrpStatusChange, and properties Name and State (retrievable
Packit Service 5956c7
 * through calls to org.freedesktop.DBus.Properties.Get)
Packit Service 5956c7
 *
Packit Service 5956c7
 * Interface files need to be installed in /usr/share/dbus-1/interfaces/
Packit Service 5956c7
 * A policy file, which determines who has access to the service, is
Packit Service 5956c7
 * installed in /etc/dbus-1/system.d/. Sources for the policy and interface
Packit Service 5956c7
 * files are in keepalived/dbus.
Packit Service 5956c7
 *
Packit Service 5956c7
 * To test the DBus service run a command like: dbus-send --system --dest=org.keepalived.Vrrp1 --print-reply object interface.method type:argument
Packit Service 5956c7
 * e.g.
Packit Service 5956c7
 * dbus-send --system --dest=org.keepalived.Vrrp1 --print-reply /org/keepalived/Vrrp1/Vrrp org.keepalived.Vrrp1.Vrrp.PrintData
Packit Service 5956c7
 * or
Packit Service 5956c7
 * dbus-send --system --dest=org.keepalived.Vrrp1 --print-reply /org/keepalived/Vrrp1/Instance/eth0/1/IPv4 org.freedesktop.DBus.Properties.Get string:'org.keepalived.Vrrp1.Instance' string:'State'
Packit Service 5956c7
 *
Packit Service 5956c7
 * To monitor signals, run:
Packit Service 5956c7
 * dbus-monitor --system type='signal'
Packit Service 5956c7
 *
Packit Service 5956c7
 * d-feet is a useful program for interfacing with DBus
Packit Service 5956c7
 */
Packit Service 5956c7
Packit Service 5956c7
#include "config.h"
Packit Service 5956c7
Packit Service 5956c7
#include <errno.h>
Packit Service 5956c7
#include <pthread.h>
Packit Service 5956c7
#include <semaphore.h>
Packit Service 5956c7
#include <gio/gio.h>
Packit Service 5956c7
#include <ctype.h>
Packit Service 5956c7
#include <fcntl.h>
Packit Service 5956c7
#include <sys/types.h>
Packit Service 5956c7
#include <stdlib.h>
Packit Service 5956c7
#include <stdint.h>
Packit Service 5956c7
Packit Service 5956c7
#include "vrrp_dbus.h"
Packit Service 5956c7
#include "vrrp_data.h"
Packit Service 5956c7
#include "vrrp_print.h"
Packit Service 5956c7
#include "global_data.h"
Packit Service 5956c7
#include "main.h"
Packit Service 5956c7
#include "logger.h"
Packit Service 5956c7
#include "utils.h"
Packit Service 5956c7
#ifdef THREAD_DUMP
Packit Service 5956c7
#include "scheduler.h"
Packit Service 5956c7
#endif
Packit Service 5956c7
Packit Service 5956c7
typedef enum dbus_action {
Packit Service 5956c7
	DBUS_ACTION_NONE,
Packit Service 5956c7
	DBUS_PRINT_DATA,
Packit Service 5956c7
	DBUS_PRINT_STATS,
Packit Service 5956c7
	DBUS_RELOAD,
Packit Service 5956c7
#ifdef _WITH_DBUS_CREATE_INSTANCE_
Packit Service 5956c7
	DBUS_CREATE_INSTANCE,
Packit Service 5956c7
	DBUS_DESTROY_INSTANCE,
Packit Service 5956c7
#endif
Packit Service 5956c7
	DBUS_SEND_GARP,
Packit Service 5956c7
	DBUS_GET_NAME,
Packit Service 5956c7
	DBUS_GET_STATUS,
Packit Service 5956c7
} dbus_action_t;
Packit Service 5956c7
Packit Service 5956c7
typedef enum dbus_error {
Packit Service 5956c7
	DBUS_SUCCESS,
Packit Service 5956c7
	DBUS_INTERFACE_NOT_FOUND,
Packit Service 5956c7
	DBUS_OBJECT_ALREADY_EXISTS,
Packit Service 5956c7
	DBUS_INTERFACE_TOO_LONG,
Packit Service 5956c7
	DBUS_INSTANCE_NOT_FOUND,
Packit Service 5956c7
} dbus_error_t;
Packit Service 5956c7
Packit Service 5956c7
typedef struct dbus_queue_ent {
Packit Service 5956c7
	dbus_action_t action;
Packit Service 5956c7
	dbus_error_t reply;
Packit Service 5956c7
	char *ifname;
Packit Service 5956c7
	uint8_t vrid;
Packit Service 5956c7
	uint8_t family;
Packit Service 5956c7
	GVariant *args;
Packit Service 5956c7
} dbus_queue_ent_t;
Packit Service 5956c7
Packit Service 5956c7
/* Global file variables */
Packit Service 5956c7
static GDBusNodeInfo *vrrp_introspection_data = NULL;
Packit Service 5956c7
static GDBusNodeInfo *vrrp_instance_introspection_data = NULL;
Packit Service 5956c7
static GDBusConnection *global_connection;
Packit Service 5956c7
static GHashTable *objects;
Packit Service 5956c7
static GMainLoop *loop;
Packit Service 5956c7
Packit Service 5956c7
/* Data passing between main vrrp thread and dbus thread */
Packit Service 5956c7
dbus_queue_ent_t *ent_ptr;
Packit Service 5956c7
static int dbus_in_pipe[2], dbus_out_pipe[2];
Packit Service 5956c7
static sem_t thread_end;
Packit Service 5956c7
Packit Service 5956c7
/* The only characters that are valid in a dbus path are A-Z, a-z, 0-9, _ */
Packit Service 5956c7
static char *
Packit Service 5956c7
set_valid_path(char *valid_path, const char *path)
Packit Service 5956c7
{
Packit Service 5956c7
	const char *str_in;
Packit Service 5956c7
	char *str_out;
Packit Service 5956c7
Packit Service 5956c7
	for (str_in = path, str_out = valid_path; *str_in; str_in++, str_out++) {
Packit Service 5956c7
		if (!isalnum(*str_in))
Packit Service 5956c7
			*str_out = '_';
Packit Service 5956c7
		else
Packit Service 5956c7
			*str_out = *str_in;
Packit Service 5956c7
	}
Packit Service 5956c7
	*str_out = '\0';
Packit Service 5956c7
Packit Service 5956c7
	return valid_path;
Packit Service 5956c7
}
Packit Service 5956c7
Packit Service 5956c7
static bool
Packit Service 5956c7
valid_path_cmp(const char *path, const char *valid_path)
Packit Service 5956c7
{
Packit Service 5956c7
	for ( ; *path && *valid_path; path++, valid_path++) {
Packit Service 5956c7
		if (!isalnum(*path)) {
Packit Service 5956c7
			if (*valid_path != '_')
Packit Service 5956c7
				return true;
Packit Service 5956c7
		}
Packit Service 5956c7
		else if (*path != *valid_path)
Packit Service 5956c7
			return true;
Packit Service 5956c7
	}
Packit Service 5956c7
Packit Service 5956c7
	return *path != *valid_path;
Packit Service 5956c7
}
Packit Service 5956c7
Packit Service 5956c7
static const char *
Packit Service 5956c7
family_str(int family)
Packit Service 5956c7
{
Packit Service 5956c7
	if (family == AF_INET)
Packit Service 5956c7
		return "IPv4";
Packit Service 5956c7
	if (family == AF_INET6)
Packit Service 5956c7
		return "IPv6";
Packit Service 5956c7
	return "None";
Packit Service 5956c7
}
Packit Service 5956c7
Packit Service 5956c7
static const char *
Packit Service 5956c7
state_str(int state)
Packit Service 5956c7
{
Packit Service 5956c7
	switch (state) {
Packit Service 5956c7
	case VRRP_STATE_INIT:
Packit Service 5956c7
		return "Init";
Packit Service 5956c7
	case VRRP_STATE_BACK:
Packit Service 5956c7
		return "Backup";
Packit Service 5956c7
	case VRRP_STATE_MAST:
Packit Service 5956c7
		return "Master";
Packit Service 5956c7
	case VRRP_STATE_FAULT:
Packit Service 5956c7
		return "Fault";
Packit Service 5956c7
	}
Packit Service 5956c7
	return "Unknown";
Packit Service 5956c7
}
Packit Service 5956c7
Packit Service 5956c7
static vrrp_t *
Packit Service 5956c7
get_vrrp_instance(const char *ifname, int vrid, int family)
Packit Service 5956c7
{
Packit Service 5956c7
	element e;
Packit Service 5956c7
	vrrp_t *vrrp;
Packit Service 5956c7
Packit Service 5956c7
	if (LIST_ISEMPTY(vrrp_data->vrrp))
Packit Service 5956c7
		return NULL;
Packit Service 5956c7
Packit Service 5956c7
	for (e = LIST_HEAD(vrrp_data->vrrp); e; ELEMENT_NEXT(e)) {
Packit Service 5956c7
		vrrp = ELEMENT_DATA(e);
Packit Service 5956c7
Packit Service 5956c7
		if (vrrp->vrid == vrid &&
Packit Service 5956c7
		    vrrp->family == family &&
Packit Service 5956c7
		    !valid_path_cmp(IF_BASE_IFP(vrrp->ifp)->ifname, ifname))
Packit Service 5956c7
				return vrrp;
Packit Service 5956c7
	}
Packit Service 5956c7
Packit Service 5956c7
	return NULL;
Packit Service 5956c7
}
Packit Service 5956c7
Packit Service 5956c7
static gboolean
Packit Service 5956c7
unregister_object(gpointer key, gpointer value, __attribute__((unused)) gpointer user_data)
Packit Service 5956c7
{
Packit Service 5956c7
	if (g_hash_table_remove(objects, key))
Packit Service 5956c7
		return g_dbus_connection_unregister_object(global_connection, GPOINTER_TO_UINT(value));
Packit Service 5956c7
	return false;
Packit Service 5956c7
}
Packit Service 5956c7
Packit Service 5956c7
static gchar *
Packit Service 5956c7
dbus_object_create_path_vrrp(void)
Packit Service 5956c7
{
Packit Service 5956c7
	return g_strconcat(DBUS_VRRP_OBJECT_ROOT,
Packit Service 5956c7
#if HAVE_DECL_CLONE_NEWNET
Packit Service 5956c7
			  global_data->network_namespace ? "/" : "", global_data->network_namespace ? global_data->network_namespace : "",
Packit Service 5956c7
#endif
Packit Service 5956c7
			  global_data->instance_name ? "/" : "", global_data->instance_name ? global_data->instance_name : "",
Packit Service 5956c7
Packit Service 5956c7
			  "/Vrrp", NULL);
Packit Service 5956c7
}
Packit Service 5956c7
Packit Service 5956c7
static gchar *
Packit Service 5956c7
dbus_object_create_path_instance(const gchar *interface, int vrid, sa_family_t family)
Packit Service 5956c7
{
Packit Service 5956c7
	gchar *object_path;
Packit Service 5956c7
	char standardized_name[sizeof ((vrrp_t*)NULL)->ifp->ifname];
Packit Service 5956c7
	gchar *vrid_str = g_strdup_printf("%d", vrid);
Packit Service 5956c7
Packit Service 5956c7
	set_valid_path(standardized_name, interface);
Packit Service 5956c7
Packit Service 5956c7
	object_path = g_strconcat(DBUS_VRRP_OBJECT_ROOT,
Packit Service 5956c7
#if HAVE_DECL_CLONE_NEWNET
Packit Service 5956c7
				  global_data->network_namespace ? "/" : "", global_data->network_namespace ? global_data->network_namespace : "",
Packit Service 5956c7
#endif
Packit Service 5956c7
				  global_data->instance_name ? "/" : "", global_data->instance_name ? global_data->instance_name : "",
Packit Service 5956c7
Packit Service 5956c7
				  "/Instance/",
Packit Service 5956c7
				  standardized_name, "/", vrid_str,
Packit Service 5956c7
				  "/", family_str(family),
Packit Service 5956c7
				  NULL);
Packit Service 5956c7
Packit Service 5956c7
	g_free(vrid_str);
Packit Service 5956c7
	return object_path;
Packit Service 5956c7
}
Packit Service 5956c7
Packit Service 5956c7
static dbus_queue_ent_t *
Packit Service 5956c7
process_method_call(dbus_queue_ent_t *ent)
Packit Service 5956c7
{
Packit Service 5956c7
	ssize_t ret;
Packit Service 5956c7
Packit Service 5956c7
	if (!ent)
Packit Service 5956c7
		return NULL;
Packit Service 5956c7
Packit Service 5956c7
	/* Tell the main thread that a queue entry is waiting. Any data works */
Packit Service 5956c7
	ent_ptr = ent;
Packit Service 5956c7
	if (write(dbus_in_pipe[1], ent, 1) != 1)
Packit Service 5956c7
		log_message(LOG_INFO, "Write from DBus thread to main thread failed");
Packit Service 5956c7
Packit Service 5956c7
	/* Wait for a response */
Packit Service 5956c7
	while ((ret = read(dbus_out_pipe[0], ent, 1)) == -1 && errno == EINTR) {
Packit Service 5956c7
		log_message(LOG_INFO, "dbus_out_pipe read returned EINTR");
Packit Service 5956c7
	}
Packit Service 5956c7
	if (ret == -1)
Packit Service 5956c7
		log_message(LOG_INFO, "DBus response read error - errno = %d", errno);
Packit Service 5956c7
Packit Service 5956c7
#ifdef DBUS_DEBUG
Packit Service 5956c7
	if (ent->reply != DBUS_SUCCESS) {
Packit Service 5956c7
		char *iname;
Packit Service 5956c7
Packit Service 5956c7
		if (ent->reply == DBUS_INTERFACE_NOT_FOUND)
Packit Service 5956c7
			log_message(LOG_INFO, "Unable to find DBus requested instance %s/%d/%s", ent->ifname, ent->vrid, family_str(ent->family));
Packit Service 5956c7
		else if (ent->reply == DBUS_OBJECT_ALREADY_EXISTS)
Packit Service 5956c7
			log_message(LOG_INFO, "Unable to create DBus requested object with instance %s/%d/%s", ent->ifname, ent->vrid, family_str(ent->family));
Packit Service 5956c7
		else if (ent->reply == DBUS_INSTANCE_NOT_FOUND) {
Packit Service 5956c7
			g_variant_get(ent->args, "(s)", &iname);
Packit Service 5956c7
			log_message(LOG_INFO, "Unable to find DBus requested instance %s", iname);
Packit Service 5956c7
		}
Packit Service 5956c7
		else
Packit Service 5956c7
			log_message(LOG_INFO, "Unknown DBus reply %d", ent->reply);
Packit Service 5956c7
	}
Packit Service 5956c7
#endif
Packit Service 5956c7
Packit Service 5956c7
	return ent;
Packit Service 5956c7
}
Packit Service 5956c7
Packit Service 5956c7
static void
Packit Service 5956c7
get_interface_ids(const gchar *object_path, gchar *interface, uint8_t *vrid, uint8_t *family)
Packit Service 5956c7
{
Packit Service 5956c7
	int path_length = DBUS_VRRP_INSTANCE_PATH_DEFAULT_LENGTH;
Packit Service 5956c7
	gchar **dirs;
Packit Service 5956c7
	char *endptr;
Packit Service 5956c7
Packit Service 5956c7
#if HAVE_DECL_CLONE_NEWNET
Packit Service 5956c7
	if(global_data->network_namespace)
Packit Service 5956c7
		path_length++;
Packit Service 5956c7
#endif
Packit Service 5956c7
	if(global_data->instance_name)
Packit Service 5956c7
		path_length++;
Packit Service 5956c7
Packit Service 5956c7
	/* object_path will have interface, vrid and family as
Packit Service 5956c7
	 * the third to last, second to last and last levels */
Packit Service 5956c7
	dirs = g_strsplit(object_path, "/", path_length);
Packit Service 5956c7
	strcpy(interface, dirs[path_length-3]);
Packit Service 5956c7
	*vrid = (uint8_t)strtoul(dirs[path_length-2], &endptr, 10);
Packit Service 5956c7
	if (*endptr)
Packit Service 5956c7
		log_message(LOG_INFO, "Dbus unexpected characters '%s' at end of number '%s'", endptr, dirs[path_length-2]);
Packit Service 5956c7
	*family = !g_strcmp0(dirs[path_length-1], "IPv4") ? AF_INET : !g_strcmp0(dirs[path_length-1], "IPv6") ? AF_INET6 : AF_UNSPEC;
Packit Service 5956c7
Packit Service 5956c7
	/* We are finished with all the object_path strings now */
Packit Service 5956c7
	g_strfreev(dirs);
Packit Service 5956c7
}
Packit Service 5956c7
Packit Service 5956c7
/* handles reply to org.freedesktop.DBus.Properties.Get method on any object*/
Packit Service 5956c7
static GVariant *
Packit Service 5956c7
handle_get_property(__attribute__((unused)) GDBusConnection *connection,
Packit Service 5956c7
		    __attribute__((unused)) const gchar     *sender,
Packit Service 5956c7
					    const gchar     *object_path,
Packit Service 5956c7
					    const gchar     *interface_name,
Packit Service 5956c7
					    const gchar     *property_name,
Packit Service 5956c7
					    GError	   **error,
Packit Service 5956c7
		    __attribute__((unused)) gpointer	     user_data)
Packit Service 5956c7
{
Packit Service 5956c7
	GVariant *ret = NULL;
Packit Service 5956c7
	dbus_queue_ent_t ent;
Packit Service 5956c7
	char ifname_str[sizeof ((vrrp_t*)NULL)->ifp->ifname];
Packit Service 5956c7
	int action;
Packit Service 5956c7
Packit Service 5956c7
	if (g_strcmp0(interface_name, DBUS_VRRP_INSTANCE_INTERFACE)) {
Packit Service 5956c7
		log_message(LOG_INFO, "Interface %s has not been implemented yet", interface_name);
Packit Service 5956c7
		return NULL;
Packit Service 5956c7
	}
Packit Service 5956c7
Packit Service 5956c7
	if (!g_strcmp0(property_name, "Name"))
Packit Service 5956c7
		action = DBUS_GET_NAME;
Packit Service 5956c7
	else if (!g_strcmp0(property_name, "State"))
Packit Service 5956c7
		action = DBUS_GET_STATUS;
Packit Service 5956c7
	else {
Packit Service 5956c7
		log_message(LOG_INFO, "Property %s does not exist", property_name);
Packit Service 5956c7
		return NULL;
Packit Service 5956c7
	}
Packit Service 5956c7
Packit Service 5956c7
	get_interface_ids(object_path, ifname_str, &ent.vrid, &ent.family);
Packit Service 5956c7
Packit Service 5956c7
	ent.action = action;
Packit Service 5956c7
	ent.ifname = ifname_str;
Packit Service 5956c7
	ent.args = NULL;
Packit Service 5956c7
	process_method_call(&ent;;
Packit Service 5956c7
	if (ent.reply == DBUS_SUCCESS)
Packit Service 5956c7
		ret = ent.args;
Packit Service 5956c7
	else
Packit Service 5956c7
		g_set_error(error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "Instance '%s/%d/%s' not found", ifname_str, ent.vrid, family_str(ent.family));
Packit Service 5956c7
Packit Service 5956c7
	return ret;
Packit Service 5956c7
}
Packit Service 5956c7
Packit Service 5956c7
/* handles method_calls on any object */
Packit Service 5956c7
static void
Packit Service 5956c7
handle_method_call(__attribute__((unused)) GDBusConnection *connection,
Packit Service 5956c7
		   __attribute__((unused)) const gchar	   *sender,
Packit Service 5956c7
					   const gchar	   *object_path,
Packit Service 5956c7
					   const gchar	   *interface_name,
Packit Service 5956c7
					   const gchar	   *method_name,
Packit Service 5956c7
#ifndef _WITH_DBUS_CREATE_INSTANCE_
Packit Service 5956c7
		   __attribute__((unused))
Packit Service 5956c7
#endif
Packit Service 5956c7
					   GVariant *parameters,
Packit Service 5956c7
		   GDBusMethodInvocation *invocation,
Packit Service 5956c7
		   __attribute__((unused)) gpointer user_data)
Packit Service 5956c7
{
Packit Service 5956c7
#ifdef _WITH_DBUS_CREATE_INSTANCE_
Packit Service 5956c7
	char *iname;
Packit Service 5956c7
	char *ifname;
Packit Service 5956c7
	size_t len;
Packit Service 5956c7
	unsigned family;
Packit Service 5956c7
#endif
Packit Service 5956c7
	dbus_queue_ent_t ent;
Packit Service 5956c7
	char ifname_str[sizeof ((vrrp_t*)NULL)->ifp->ifname];
Packit Service 5956c7
Packit Service 5956c7
	if (!g_strcmp0(interface_name, DBUS_VRRP_INTERFACE)) {
Packit Service 5956c7
		if (!g_strcmp0(method_name, "PrintData")) {
Packit Service 5956c7
			ent.action = DBUS_PRINT_DATA;
Packit Service 5956c7
			process_method_call(&ent;;
Packit Service 5956c7
			g_dbus_method_invocation_return_value(invocation, NULL);
Packit Service 5956c7
		}
Packit Service 5956c7
		else if (g_strcmp0(method_name, "PrintStats") == 0) {
Packit Service 5956c7
			ent.action = DBUS_PRINT_STATS;
Packit Service 5956c7
			process_method_call(&ent;;
Packit Service 5956c7
			g_dbus_method_invocation_return_value(invocation, NULL);
Packit Service 5956c7
		}
Packit Service 5956c7
		else if (g_strcmp0(method_name, "ReloadConfig") == 0) {
Packit Service 5956c7
			g_dbus_method_invocation_return_value(invocation, NULL);
Packit Service 5956c7
			kill(getppid(), SIGHUP);
Packit Service 5956c7
		}
Packit Service 5956c7
#ifdef _WITH_DBUS_CREATE_INSTANCE_
Packit Service 5956c7
		else if (g_strcmp0(method_name, "CreateInstance") == 0) {
Packit Service 5956c7
			g_variant_get(parameters, "(ssuu)", &iname, &ifname, &ent.vrid, &family);
Packit Service 5956c7
			len = strlen(ifname);
Packit Service 5956c7
			if (len == 0 || len >= IFNAMSIZ) {
Packit Service 5956c7
				log_message(LOG_INFO, "Interface name '%s' too long for CreateInstance", ifname);
Packit Service 5956c7
				g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "Interface name empty or too long");
Packit Service 5956c7
				return;
Packit Service 5956c7
			}
Packit Service 5956c7
			ent.action = DBUS_CREATE_INSTANCE;
Packit Service 5956c7
			ent.ifname = ifname;
Packit Service 5956c7
			ent.family = family == 4 ? AF_INET : family == 6 ? AF_INET6 : AF_UNSPEC;
Packit Service 5956c7
			ent.args = g_variant_new("(s)", iname);
Packit Service 5956c7
			process_method_call(&ent;;
Packit Service 5956c7
			g_variant_unref(ent.args);
Packit Service 5956c7
			g_dbus_method_invocation_return_value(invocation, NULL);
Packit Service 5956c7
		}
Packit Service 5956c7
		else if (g_strcmp0(method_name, "DestroyInstance") == 0) {
Packit Service 5956c7
// TODO - this should be on the instance
Packit Service 5956c7
			ent.action = DBUS_DESTROY_INSTANCE;
Packit Service 5956c7
			ent.args = parameters;
Packit Service 5956c7
			process_method_call(&ent;;
Packit Service 5956c7
Packit Service 5956c7
			if (ent.reply == DBUS_INSTANCE_NOT_FOUND) {
Packit Service 5956c7
				g_variant_get(parameters, "(s)", &iname);
Packit Service 5956c7
				g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "Instance '%s' not found", iname);
Packit Service 5956c7
			}
Packit Service 5956c7
			else
Packit Service 5956c7
				g_dbus_method_invocation_return_value(invocation, NULL);
Packit Service 5956c7
		}
Packit Service 5956c7
#endif
Packit Service 5956c7
		else {
Packit Service 5956c7
			log_message(LOG_INFO, "Method %s has not been implemented yet", method_name);
Packit Service 5956c7
			g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR, G_DBUS_ERROR_MATCH_RULE_NOT_FOUND, "Method not implemented");
Packit Service 5956c7
		}
Packit Service 5956c7
Packit Service 5956c7
		return;
Packit Service 5956c7
	}
Packit Service 5956c7
Packit Service 5956c7
	if (!g_strcmp0(interface_name, DBUS_VRRP_INSTANCE_INTERFACE)) {
Packit Service 5956c7
		if (!g_strcmp0(method_name, "SendGarp")) {
Packit Service 5956c7
			get_interface_ids(object_path, ifname_str, &ent.vrid, &ent.family);
Packit Service 5956c7
			ent.action = DBUS_SEND_GARP;
Packit Service 5956c7
			ent.ifname = ifname_str;
Packit Service 5956c7
			process_method_call(&ent;;
Packit Service 5956c7
			if (ent.reply ==  DBUS_INTERFACE_NOT_FOUND)
Packit Service 5956c7
				g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "Instance '%s/%d/%s' not found", ifname_str, ent.vrid, family_str(ent.family));
Packit Service 5956c7
			else
Packit Service 5956c7
				g_dbus_method_invocation_return_value(invocation, NULL);
Packit Service 5956c7
		} else {
Packit Service 5956c7
			log_message(LOG_INFO, "Method %s has not been implemented yet", method_name);
Packit Service 5956c7
			g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR, G_DBUS_ERROR_MATCH_RULE_NOT_FOUND, "Method not implemented");
Packit Service 5956c7
		}
Packit Service 5956c7
Packit Service 5956c7
		return;
Packit Service 5956c7
	}
Packit Service 5956c7
Packit Service 5956c7
	log_message(LOG_INFO, "Interface %s has not been implemented yet", interface_name);
Packit Service 5956c7
	g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR, G_DBUS_ERROR_MATCH_RULE_NOT_FOUND, "Interface not implemented");
Packit Service 5956c7
}
Packit Service 5956c7
Packit Service 5956c7
static const GDBusInterfaceVTable interface_vtable =
Packit Service 5956c7
{
Packit Service 5956c7
	handle_method_call,
Packit Service 5956c7
	handle_get_property,
Packit Service 5956c7
	NULL, /* handle_set_property is null because we have no writeable property */
Packit Service 5956c7
	{}
Packit Service 5956c7
};
Packit Service 5956c7
Packit Service 5956c7
static int
Packit Service 5956c7
dbus_create_object_params(char *instance_name, const char *interface_name, int vrid, sa_family_t family, bool log_success)
Packit Service 5956c7
{
Packit Service 5956c7
	gchar *object_path;
Packit Service 5956c7
	GError *local_error = NULL;
Packit Service 5956c7
Packit Service 5956c7
	if (g_hash_table_lookup(objects, instance_name)) {
Packit Service 5956c7
		log_message(LOG_INFO, "An object for instance %s already exists", instance_name);
Packit Service 5956c7
		return DBUS_OBJECT_ALREADY_EXISTS;
Packit Service 5956c7
	}
Packit Service 5956c7
Packit Service 5956c7
	object_path = dbus_object_create_path_instance(interface_name, vrid, family);
Packit Service 5956c7
Packit Service 5956c7
	guint instance = g_dbus_connection_register_object(global_connection, object_path,
Packit Service 5956c7
						vrrp_instance_introspection_data->interfaces[0],
Packit Service 5956c7
						&interface_vtable, NULL, NULL, &local_error);
Packit Service 5956c7
	if (local_error != NULL) {
Packit Service 5956c7
		log_message(LOG_INFO, "Registering DBus object on %s failed: %s",
Packit Service 5956c7
			    object_path, local_error->message);
Packit Service 5956c7
		g_clear_error(&local_error);
Packit Service 5956c7
	}
Packit Service 5956c7
Packit Service 5956c7
	if (instance) {
Packit Service 5956c7
		g_hash_table_insert(objects, instance_name, GUINT_TO_POINTER(instance));
Packit Service 5956c7
		if (log_success)
Packit Service 5956c7
			log_message(LOG_INFO, "Added DBus object for instance %s on path %s", instance_name, object_path);
Packit Service 5956c7
	}
Packit Service 5956c7
	g_free(object_path);
Packit Service 5956c7
Packit Service 5956c7
	return DBUS_SUCCESS;
Packit Service 5956c7
}
Packit Service 5956c7
Packit Service 5956c7
static void
Packit Service 5956c7
dbus_create_object(vrrp_t *vrrp)
Packit Service 5956c7
{
Packit Service 5956c7
	dbus_create_object_params(vrrp->iname, IF_NAME(IF_BASE_IFP(vrrp->ifp)), vrrp->vrid, vrrp->family, false);
Packit Service 5956c7
}
Packit Service 5956c7
Packit Service 5956c7
static bool
Packit Service 5956c7
dbus_emit_signal(GDBusConnection *connection,
Packit Service 5956c7
		 const gchar *object_path,
Packit Service 5956c7
		 const gchar *interface_name,
Packit Service 5956c7
		 const gchar *signal_name,
Packit Service 5956c7
		 GVariant *parameters)
Packit Service 5956c7
{
Packit Service 5956c7
	GError *local_error = NULL;
Packit Service 5956c7
Packit Service 5956c7
	g_dbus_connection_emit_signal(connection, NULL, object_path, interface_name, signal_name, parameters,
Packit Service 5956c7
				      &local_error);
Packit Service 5956c7
Packit Service 5956c7
	if (local_error != NULL) {
Packit Service 5956c7
		log_message(LOG_INFO, "Emitting DBus signal %s.%s on %s failed: %s",
Packit Service 5956c7
			    interface_name, signal_name, object_path, local_error->message);
Packit Service 5956c7
		g_clear_error(&local_error);
Packit Service 5956c7
		return false;
Packit Service 5956c7
	}
Packit Service 5956c7
	return true;
Packit Service 5956c7
}
Packit Service 5956c7
Packit Service 5956c7
/* first function to be run when trying to own bus,
Packit Service 5956c7
 * exports objects to the bus */
Packit Service 5956c7
static void
Packit Service 5956c7
on_bus_acquired(GDBusConnection *connection,
Packit Service 5956c7
		const gchar     *name,
Packit Service 5956c7
		__attribute__((unused)) gpointer user_data)
Packit Service 5956c7
{
Packit Service 5956c7
	global_connection = connection;
Packit Service 5956c7
	gchar *path;
Packit Service 5956c7
	element e;
Packit Service 5956c7
	GError *local_error = NULL;
Packit Service 5956c7
Packit Service 5956c7
	log_message(LOG_INFO, "Acquired DBus bus %s", name);
Packit Service 5956c7
Packit Service 5956c7
	/* register VRRP object */
Packit Service 5956c7
	path = dbus_object_create_path_vrrp();
Packit Service 5956c7
	guint vrrp = g_dbus_connection_register_object(connection, path,
Packit Service 5956c7
							 vrrp_introspection_data->interfaces[0],
Packit Service 5956c7
							 &interface_vtable, NULL, NULL, &local_error);
Packit Service 5956c7
	g_hash_table_insert(objects, "__Vrrp__", GUINT_TO_POINTER(vrrp));
Packit Service 5956c7
	g_free(path);
Packit Service 5956c7
	if (local_error != NULL) {
Packit Service 5956c7
		log_message(LOG_INFO, "Registering VRRP object on %s failed: %s",
Packit Service 5956c7
			    path, local_error->message);
Packit Service 5956c7
		g_clear_error(&local_error);
Packit Service 5956c7
	}
Packit Service 5956c7
Packit Service 5956c7
	/* for each available VRRP instance, register an object */
Packit Service 5956c7
	if (LIST_ISEMPTY(vrrp_data->vrrp))
Packit Service 5956c7
		return;
Packit Service 5956c7
Packit Service 5956c7
	for (e = LIST_HEAD(vrrp_data->vrrp); e; ELEMENT_NEXT(e)) {
Packit Service 5956c7
		vrrp_t * vrrp = ELEMENT_DATA(e);
Packit Service 5956c7
		dbus_create_object(vrrp);
Packit Service 5956c7
	}
Packit Service 5956c7
Packit Service 5956c7
	/* Send a signal to say we have started */
Packit Service 5956c7
	path = dbus_object_create_path_vrrp();
Packit Service 5956c7
	dbus_emit_signal(global_connection, path, DBUS_VRRP_INTERFACE, "VrrpStarted", NULL);
Packit Service 5956c7
	g_free(path);
Packit Service 5956c7
Packit Service 5956c7
	/* Notify DBus of the state of our instances */
Packit Service 5956c7
	for (e = LIST_HEAD(vrrp_data->vrrp); e; ELEMENT_NEXT(e)) {
Packit Service 5956c7
		vrrp_t * vrrp = ELEMENT_DATA(e);
Packit Service 5956c7
		dbus_send_state_signal(vrrp);
Packit Service 5956c7
	}
Packit Service 5956c7
}
Packit Service 5956c7
Packit Service 5956c7
/* run if bus name is acquired successfully */
Packit Service 5956c7
static void
Packit Service 5956c7
on_name_acquired(__attribute__((unused)) GDBusConnection *connection,
Packit Service 5956c7
		 const gchar     *name,
Packit Service 5956c7
		 __attribute__((unused)) gpointer user_data)
Packit Service 5956c7
{
Packit Service 5956c7
	log_message(LOG_INFO, "Acquired the name %s on the session bus", name);
Packit Service 5956c7
}
Packit Service 5956c7
Packit Service 5956c7
/* run if bus name or connection are lost */
Packit Service 5956c7
static void
Packit Service 5956c7
on_name_lost(GDBusConnection *connection,
Packit Service 5956c7
	     const gchar     *name,
Packit Service 5956c7
	     __attribute__((unused)) gpointer user_data)
Packit Service 5956c7
{
Packit Service 5956c7
	log_message(LOG_INFO, "Lost the name %s on the session bus", name);
Packit Service 5956c7
	global_connection = connection;
Packit Service 5956c7
	g_hash_table_foreach_remove(objects, unregister_object, NULL);
Packit Service 5956c7
	objects = NULL;
Packit Service 5956c7
	global_connection = NULL;
Packit Service 5956c7
}
Packit Service 5956c7
Packit Service 5956c7
static gchar*
Packit Service 5956c7
read_file(gchar* filepath)
Packit Service 5956c7
{
Packit Service 5956c7
	FILE * f;
Packit Service 5956c7
	size_t length;
Packit Service 5956c7
	gchar *ret = NULL;
Packit Service 5956c7
Packit Service 5956c7
	f = fopen(filepath, "r");
Packit Service 5956c7
	if (f) {
Packit Service 5956c7
		fseek(f, 0, SEEK_END);
Packit Service 5956c7
		length = (size_t)ftell(f);
Packit Service 5956c7
		fseek(f, 0, SEEK_SET);
Packit Service 5956c7
Packit Service 5956c7
		/* We can't use MALLOC since it isn't thread safe */
Packit Service 5956c7
		ret = MALLOC(length + 1);
Packit Service 5956c7
		if (ret) {
Packit Service 5956c7
			if (fread(ret, length, 1, f) != 1) {
Packit Service 5956c7
				log_message(LOG_INFO, "Failed to read all of %s", filepath);
Packit Service 5956c7
			}
Packit Service 5956c7
			ret[length] = '\0';
Packit Service 5956c7
		}
Packit Service 5956c7
		else
Packit Service 5956c7
			log_message(LOG_INFO, "Unable to read Dbus file %s", filepath);
Packit Service 5956c7
Packit Service 5956c7
		fclose(f);
Packit Service 5956c7
	}
Packit Service 5956c7
	return ret;
Packit Service 5956c7
}
Packit Service 5956c7
Packit Service 5956c7
static void *
Packit Service 5956c7
dbus_main(__attribute__ ((unused)) void *unused)
Packit Service 5956c7
{
Packit Service 5956c7
	gchar *introspection_xml;
Packit Service 5956c7
	guint owner_id;
Packit Service 5956c7
	const char *service_name;
Packit Service 5956c7
Packit Service 5956c7
	objects = g_hash_table_new(g_str_hash, g_str_equal);
Packit Service 5956c7
Packit Service 5956c7
	/* DBus service org.keepalived.Vrrp1 exposes two interfaces, Vrrp and Instance.
Packit Service 5956c7
	 * Vrrp is implemented by a single VRRP object for general purposes, such as printing
Packit Service 5956c7
	 * data or signaling that the VRRP process has been stopped.
Packit Service 5956c7
	 * Instance is implemented by an Instance object for every VRRP Instance in vrrp_data.
Packit Service 5956c7
	 * It exposes instance specific methods and properties.
Packit Service 5956c7
	 */
Packit Service 5956c7
#ifdef DBUS_NEED_G_TYPE_INIT
Packit Service 5956c7
	g_type_init();
Packit Service 5956c7
#endif
Packit Service 5956c7
	GError *error = NULL;
Packit Service 5956c7
Packit Service 5956c7
	/* read service interface data from xml files */
Packit Service 5956c7
	introspection_xml = read_file(DBUS_VRRP_INTERFACE_FILE_PATH);
Packit Service 5956c7
	if (!introspection_xml)
Packit Service 5956c7
		return NULL;
Packit Service 5956c7
	vrrp_introspection_data = g_dbus_node_info_new_for_xml(introspection_xml, &error);
Packit Service 5956c7
	FREE(introspection_xml);
Packit Service 5956c7
	if (error != NULL) {
Packit Service 5956c7
		log_message(LOG_INFO, "Parsing DBus interface %s from file %s failed: %s",
Packit Service 5956c7
			    DBUS_VRRP_INTERFACE, DBUS_VRRP_INTERFACE_FILE_PATH, error->message);
Packit Service 5956c7
		g_clear_error(&error);
Packit Service 5956c7
		return NULL;
Packit Service 5956c7
	}
Packit Service 5956c7
Packit Service 5956c7
	introspection_xml = read_file(DBUS_VRRP_INSTANCE_INTERFACE_FILE_PATH);
Packit Service 5956c7
	if (!introspection_xml)
Packit Service 5956c7
		return NULL;
Packit Service 5956c7
	vrrp_instance_introspection_data = g_dbus_node_info_new_for_xml(introspection_xml, &error);
Packit Service 5956c7
	FREE(introspection_xml);
Packit Service 5956c7
	if (error != NULL) {
Packit Service 5956c7
		log_message(LOG_INFO, "Parsing DBus interface %s from file %s failed: %s",
Packit Service 5956c7
			    DBUS_VRRP_INSTANCE_INTERFACE, DBUS_VRRP_INSTANCE_INTERFACE_FILE_PATH, error->message);
Packit Service 5956c7
		g_clear_error(&error);
Packit Service 5956c7
		return NULL;
Packit Service 5956c7
	}
Packit Service 5956c7
Packit Service 5956c7
	service_name = global_data->dbus_service_name ? global_data->dbus_service_name : DBUS_SERVICE_NAME;
Packit Service 5956c7
	owner_id = g_bus_own_name(G_BUS_TYPE_SYSTEM,
Packit Service 5956c7
				  service_name,
Packit Service 5956c7
				  G_BUS_NAME_OWNER_FLAGS_NONE,
Packit Service 5956c7
				  on_bus_acquired,
Packit Service 5956c7
				  on_name_acquired,
Packit Service 5956c7
				  on_name_lost,
Packit Service 5956c7
				  NULL,  /* user_data */
Packit Service 5956c7
				  NULL); /* user_data_free_func */
Packit Service 5956c7
Packit Service 5956c7
	loop = g_main_loop_new(NULL, FALSE);
Packit Service 5956c7
	g_main_loop_run(loop);
Packit Service 5956c7
Packit Service 5956c7
	/* cleanup after loop terminates */
Packit Service 5956c7
	g_main_loop_unref(loop);
Packit Service 5956c7
	g_bus_unown_name(owner_id);
Packit Service 5956c7
	global_connection = NULL;
Packit Service 5956c7
Packit Service 5956c7
	sem_post(&thread_end);
Packit Service 5956c7
	pthread_exit(0);
Packit Service 5956c7
}
Packit Service 5956c7
Packit Service 5956c7
/* The following functions are run in the context of the main vrrp thread */
Packit Service 5956c7
Packit Service 5956c7
/* send signal VrrpStatusChange
Packit Service 5956c7
 * containing the new state of vrrp */
Packit Service 5956c7
void
Packit Service 5956c7
dbus_send_state_signal(vrrp_t *vrrp)
Packit Service 5956c7
{
Packit Service 5956c7
	gchar *object_path;
Packit Service 5956c7
	GVariant *args;
Packit Service 5956c7
Packit Service 5956c7
	/* the interface will go through the initial state changes before
Packit Service 5956c7
	 * the main loop can be started and global_connection initialised */
Packit Service 5956c7
	if (global_connection == NULL)
Packit Service 5956c7
		return;
Packit Service 5956c7
Packit Service 5956c7
	object_path = dbus_object_create_path_instance(IF_NAME(IF_BASE_IFP(vrrp->ifp)), vrrp->vrid, vrrp->family);
Packit Service 5956c7
Packit Service 5956c7
	args = g_variant_new("(u)", vrrp->state);
Packit Service 5956c7
	dbus_emit_signal(global_connection, object_path, DBUS_VRRP_INSTANCE_INTERFACE, "VrrpStatusChange", args);
Packit Service 5956c7
	g_free(object_path);
Packit Service 5956c7
}
Packit Service 5956c7
Packit Service 5956c7
/* send signal VrrpRestarted */
Packit Service 5956c7
static void
Packit Service 5956c7
dbus_send_reload_signal(void)
Packit Service 5956c7
{
Packit Service 5956c7
	gchar *path;
Packit Service 5956c7
Packit Service 5956c7
	if (global_connection == NULL)
Packit Service 5956c7
		return;
Packit Service 5956c7
Packit Service 5956c7
	path = dbus_object_create_path_vrrp();
Packit Service 5956c7
	dbus_emit_signal(global_connection, path, DBUS_VRRP_INTERFACE, "VrrpReloaded", NULL);
Packit Service 5956c7
	g_free(path);
Packit Service 5956c7
}
Packit Service 5956c7
Packit Service 5956c7
static gboolean
Packit Service 5956c7
dbus_unregister_object(char *str)
Packit Service 5956c7
{
Packit Service 5956c7
	gboolean ret = false;
Packit Service 5956c7
Packit Service 5956c7
	gpointer value = g_hash_table_lookup(objects, str);
Packit Service 5956c7
	if (value) {
Packit Service 5956c7
		ret = unregister_object(str, value, NULL);
Packit Service 5956c7
		log_message(LOG_INFO, "Deleted DBus object for instance %s", str);
Packit Service 5956c7
	}
Packit Service 5956c7
#ifdef DBUS_DEBUG
Packit Service 5956c7
	else
Packit Service 5956c7
		log_message(LOG_INFO, "DBus object not found for instance %s", str);
Packit Service 5956c7
#endif
Packit Service 5956c7
Packit Service 5956c7
	return ret;
Packit Service 5956c7
}
Packit Service 5956c7
Packit Service 5956c7
void
Packit Service 5956c7
dbus_remove_object(vrrp_t *vrrp)
Packit Service 5956c7
{
Packit Service 5956c7
	dbus_unregister_object(vrrp->iname);
Packit Service 5956c7
}
Packit Service 5956c7
Packit Service 5956c7
static int
Packit Service 5956c7
handle_dbus_msg(__attribute__((unused)) thread_t *thread)
Packit Service 5956c7
{
Packit Service 5956c7
	dbus_queue_ent_t *ent;
Packit Service 5956c7
	char recv_buf;
Packit Service 5956c7
	vrrp_t *vrrp;
Packit Service 5956c7
#ifdef _WITH_DBUS_CREATE_INSTANCE_
Packit Service 5956c7
	gchar *name;
Packit Service 5956c7
#endif
Packit Service 5956c7
Packit Service 5956c7
	if (read(dbus_in_pipe[0], &recv_buf, 1) != 1)
Packit Service 5956c7
		log_message(LOG_INFO, "Read from DBus thread to vrrp thread failed");
Packit Service 5956c7
Packit Service 5956c7
	if ((ent = ent_ptr) != NULL) {
Packit Service 5956c7
		ent->reply = DBUS_SUCCESS;
Packit Service 5956c7
Packit Service 5956c7
		if (ent->action == DBUS_PRINT_DATA) {
Packit Service 5956c7
			log_message(LOG_INFO, "Printing VRRP data on DBus request");
Packit Service 5956c7
			vrrp_print_data();
Packit Service 5956c7
Packit Service 5956c7
		}
Packit Service 5956c7
		else if (ent->action == DBUS_PRINT_STATS) {
Packit Service 5956c7
			log_message(LOG_INFO, "Printing VRRP stats on DBus request");
Packit Service 5956c7
			vrrp_print_stats();
Packit Service 5956c7
		}
Packit Service 5956c7
#ifdef _WITH_DBUS_CREATE_INSTANCE_
Packit Service 5956c7
		else if (ent->action == DBUS_CREATE_INSTANCE) {
Packit Service 5956c7
			g_variant_get(ent->args, "(s)", &name);
Packit Service 5956c7
			ent->reply = dbus_create_object_params(name, ent->ifname, ent->vrid, ent->family, true);
Packit Service 5956c7
		}
Packit Service 5956c7
		else if (ent->action == DBUS_DESTROY_INSTANCE) {
Packit Service 5956c7
			g_variant_get(ent->args, "(s)", &name);
Packit Service 5956c7
			if (!dbus_unregister_object(name))
Packit Service 5956c7
				ent->reply = DBUS_INSTANCE_NOT_FOUND;
Packit Service 5956c7
		}
Packit Service 5956c7
#endif
Packit Service 5956c7
		else if (ent->action == DBUS_SEND_GARP) {
Packit Service 5956c7
			ent->reply = DBUS_INTERFACE_NOT_FOUND;
Packit Service 5956c7
			vrrp = get_vrrp_instance(ent->ifname, ent->vrid, ent->family);
Packit Service 5956c7
			if (vrrp) {
Packit Service 5956c7
				log_message(LOG_INFO, "Sending garps on %s on DBus request", vrrp->iname);
Packit Service 5956c7
				vrrp_send_link_update(vrrp, 1);
Packit Service 5956c7
				ent->reply = DBUS_SUCCESS;
Packit Service 5956c7
			}
Packit Service 5956c7
		}
Packit Service 5956c7
		else if (ent->action == DBUS_GET_NAME ||
Packit Service 5956c7
			 ent->action == DBUS_GET_STATUS) {
Packit Service 5956c7
			/* we look for the vrrp instance object that corresponds to our interface and group */
Packit Service 5956c7
			ent->reply = DBUS_INTERFACE_NOT_FOUND;
Packit Service 5956c7
Packit Service 5956c7
			vrrp = get_vrrp_instance(ent->ifname, ent->vrid, ent->family);
Packit Service 5956c7
Packit Service 5956c7
			if (vrrp) {
Packit Service 5956c7
				/* the property_name argument is the property we want to Get */
Packit Service 5956c7
				if (ent->action == DBUS_GET_NAME)
Packit Service 5956c7
					ent->args = g_variant_new("(s)", vrrp->iname);
Packit Service 5956c7
				else if (ent->action == DBUS_GET_STATUS)
Packit Service 5956c7
					ent->args = g_variant_new("(us)", vrrp->state, state_str(vrrp->state));
Packit Service 5956c7
				else
Packit Service 5956c7
					ent->args = NULL;	 /* How did we get here? */
Packit Service 5956c7
				ent->reply = DBUS_SUCCESS;
Packit Service 5956c7
			}
Packit Service 5956c7
		}
Packit Service 5956c7
		if (write(dbus_out_pipe[1], ent, 1) != 1)
Packit Service 5956c7
			log_message(LOG_INFO, "Write from main thread to DBus thread failed");
Packit Service 5956c7
	}
Packit Service 5956c7
Packit Service 5956c7
	thread_add_read(master, handle_dbus_msg, NULL, dbus_in_pipe[0], TIMER_NEVER);
Packit Service 5956c7
Packit Service 5956c7
	return 0;
Packit Service 5956c7
}
Packit Service 5956c7
Packit Service 5956c7
void
Packit Service 5956c7
dbus_reload(list o, list n)
Packit Service 5956c7
{
Packit Service 5956c7
	element e1, e2, e3;
Packit Service 5956c7
	vrrp_t *vrrp_n, *vrrp_o, *vrrp_n3;
Packit Service 5956c7
Packit Service 5956c7
	if (!LIST_ISEMPTY(n)) {
Packit Service 5956c7
		for (e1 = LIST_HEAD(n); e1; ELEMENT_NEXT(e1)) {
Packit Service 5956c7
			char *n_name;
Packit Service 5956c7
			bool match_found;
Packit Service 5956c7
Packit Service 5956c7
			vrrp_n = ELEMENT_DATA(e1);
Packit Service 5956c7
Packit Service 5956c7
			if (LIST_ISEMPTY(o)) {
Packit Service 5956c7
				dbus_create_object(vrrp_n);
Packit Service 5956c7
				continue;
Packit Service 5956c7
			}
Packit Service 5956c7
Packit Service 5956c7
			n_name = IF_BASE_IFP(vrrp_n->ifp)->ifname;
Packit Service 5956c7
Packit Service 5956c7
			/* Try an find an instance with same vrid/family/interface that existed before and now */
Packit Service 5956c7
			for (e2 = LIST_HEAD(o), match_found = false; e2 && !match_found; ELEMENT_NEXT(e2)) {
Packit Service 5956c7
				vrrp_o = ELEMENT_DATA(e2);
Packit Service 5956c7
Packit Service 5956c7
				if (vrrp_n->vrid == vrrp_o->vrid &&
Packit Service 5956c7
				    vrrp_n->family == vrrp_o->family &&
Packit Service 5956c7
				    !strcmp(n_name, IF_BASE_IFP(vrrp_o->ifp)->ifname)) {
Packit Service 5956c7
					/* If the old instance exists in the new config,
Packit Service 5956c7
					 * then the dbus object will exist */
Packit Service 5956c7
					if (!strcmp(vrrp_n->iname, vrrp_o->iname)) {
Packit Service 5956c7
						match_found = true;
Packit Service 5956c7
						break;
Packit Service 5956c7
					}
Packit Service 5956c7
Packit Service 5956c7
					/* Check if the old instance name we found still exists
Packit Service 5956c7
					 * (but has a different vrid/family/interface) */
Packit Service 5956c7
					for (e3 = LIST_HEAD(n); e3; ELEMENT_NEXT(e3)) {
Packit Service 5956c7
						vrrp_n3 = ELEMENT_DATA(e3);
Packit Service 5956c7
						if (!strcmp(vrrp_o->iname, vrrp_n3->iname)) {
Packit Service 5956c7
							match_found = true;
Packit Service 5956c7
							break;
Packit Service 5956c7
						}
Packit Service 5956c7
					}
Packit Service 5956c7
				}
Packit Service 5956c7
			}
Packit Service 5956c7
Packit Service 5956c7
			if (match_found)
Packit Service 5956c7
				continue;
Packit Service 5956c7
Packit Service 5956c7
			dbus_create_object(vrrp_n);
Packit Service 5956c7
		}
Packit Service 5956c7
	}
Packit Service 5956c7
Packit Service 5956c7
	/* Signal we have reloaded */
Packit Service 5956c7
	dbus_send_reload_signal();
Packit Service 5956c7
Packit Service 5956c7
	/* We need to reinstate the read thread */
Packit Service 5956c7
	thread_add_read(master, handle_dbus_msg, NULL, dbus_in_pipe[0], TIMER_NEVER);
Packit Service 5956c7
}
Packit Service 5956c7
Packit Service 5956c7
bool
Packit Service 5956c7
dbus_start(void)
Packit Service 5956c7
{
Packit Service 5956c7
	pthread_t dbus_thread;
Packit Service 5956c7
	sigset_t sigset, cursigset;
Packit Service 5956c7
Packit Service 5956c7
	if (open_pipe(dbus_in_pipe)) {
Packit Service 5956c7
		log_message(LOG_INFO, "Unable to create inbound dbus pipe - disabling DBus");
Packit Service 5956c7
		return false;
Packit Service 5956c7
	}
Packit Service 5956c7
	if (open_pipe(dbus_out_pipe)) {
Packit Service 5956c7
		log_message(LOG_INFO, "Unable to create outbound dbus pipe - disabling DBus");
Packit Service 5956c7
		close(dbus_in_pipe[0]);
Packit Service 5956c7
		close(dbus_in_pipe[1]);
Packit Service 5956c7
		return false;
Packit Service 5956c7
	}
Packit Service 5956c7
Packit Service 5956c7
	/* We don't want the main thread to block when using the pipes,
Packit Service 5956c7
	 * but the other side of the pipes should block. */
Packit Service 5956c7
	fcntl(dbus_in_pipe[1], F_SETFL, fcntl(dbus_in_pipe[1], F_GETFL) & ~O_NONBLOCK);
Packit Service 5956c7
	fcntl(dbus_out_pipe[0], F_SETFL, fcntl(dbus_out_pipe[0], F_GETFL) & ~O_NONBLOCK);
Packit Service 5956c7
Packit Service 5956c7
	thread_add_read(master, handle_dbus_msg, NULL, dbus_in_pipe[0], TIMER_NEVER);
Packit Service 5956c7
Packit Service 5956c7
	/* Initialise the thread termination semaphore */
Packit Service 5956c7
	sem_init(&thread_end, 0, 0);
Packit Service 5956c7
Packit Service 5956c7
	/* Block signals (all) we don't want the new thread to process */
Packit Service 5956c7
	sigfillset(&sigset);
Packit Service 5956c7
	pthread_sigmask(SIG_SETMASK, &sigset, &cursigset);
Packit Service 5956c7
Packit Service 5956c7
	/* Now create the dbus thread */
Packit Service 5956c7
	pthread_create(&dbus_thread, NULL, &dbus_main, NULL);
Packit Service 5956c7
Packit Service 5956c7
	/* Reenable our signals */
Packit Service 5956c7
	pthread_sigmask(SIG_SETMASK, &cursigset, NULL);
Packit Service 5956c7
Packit Service 5956c7
	return true;
Packit Service 5956c7
}
Packit Service 5956c7
Packit Service 5956c7
void
Packit Service 5956c7
dbus_stop(void)
Packit Service 5956c7
{
Packit Service 5956c7
	struct timespec thread_end_wait;
Packit Service 5956c7
	int ret;
Packit Service 5956c7
	gchar *path;
Packit Service 5956c7
Packit Service 5956c7
	if (global_connection != NULL) {
Packit Service 5956c7
		path = dbus_object_create_path_vrrp();
Packit Service 5956c7
		dbus_emit_signal(global_connection, path, DBUS_VRRP_INTERFACE, "VrrpStopped", NULL);
Packit Service 5956c7
		g_free(path);
Packit Service 5956c7
	}
Packit Service 5956c7
Packit Service 5956c7
	g_main_loop_quit(loop);
Packit Service 5956c7
Packit Service 5956c7
	g_dbus_node_info_unref(vrrp_introspection_data);
Packit Service 5956c7
	g_dbus_node_info_unref(vrrp_instance_introspection_data);
Packit Service 5956c7
Packit Service 5956c7
	clock_gettime(CLOCK_REALTIME, &thread_end_wait);
Packit Service 5956c7
	thread_end_wait.tv_sec += 1;
Packit Service 5956c7
	while ((ret = sem_timedwait(&thread_end, &thread_end_wait)) == -1 && errno == EINTR) ;
Packit Service 5956c7
Packit Service 5956c7
	if (ret == -1 ) {
Packit Service 5956c7
		if (errno == ETIMEDOUT)
Packit Service 5956c7
			log_message(LOG_INFO, "DBus thread termination timed out");
Packit Service 5956c7
		else
Packit Service 5956c7
			log_message(LOG_INFO, "sem_timewait error %d", errno);
Packit Service 5956c7
	}
Packit Service 5956c7
	else {
Packit Service 5956c7
		log_message(LOG_INFO, "Released DBus");
Packit Service 5956c7
		sem_destroy(&thread_end);
Packit Service 5956c7
	}
Packit Service 5956c7
}
Packit Service 5956c7
Packit Service 5956c7
#ifdef THREAD_DUMP
Packit Service 5956c7
void
Packit Service 5956c7
register_vrrp_dbus_addresses(void)
Packit Service 5956c7
{
Packit Service 5956c7
	register_thread_address("handle_dbus_msg", handle_dbus_msg);
Packit Service 5956c7
}
Packit Service 5956c7
#endif