Blame keepalived/vrrp/vrrp_dbus.c

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