summaryrefslogtreecommitdiffstats
path: root/server/sbus/sssd_dbus_connection.c
diff options
context:
space:
mode:
Diffstat (limited to 'server/sbus/sssd_dbus_connection.c')
-rw-r--r--server/sbus/sssd_dbus_connection.c692
1 files changed, 0 insertions, 692 deletions
diff --git a/server/sbus/sssd_dbus_connection.c b/server/sbus/sssd_dbus_connection.c
deleted file mode 100644
index 38ccc6ab1..000000000
--- a/server/sbus/sssd_dbus_connection.c
+++ /dev/null
@@ -1,692 +0,0 @@
-/*
- Authors:
- Simo Sorce <ssorce@redhat.com>
- Stephen Gallagher <sgallagh@redhat.com>
-
- Copyright (C) 2009 Red Hat
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <sys/time.h>
-#include "util/util.h"
-#include "dbus/dbus.h"
-#include "sbus/sssd_dbus.h"
-#include "sbus/sssd_dbus_private.h"
-
-/* Types */
-struct dbus_ctx_list;
-
-struct sbus_interface_p {
- struct sbus_interface_p *prev, *next;
- struct sbus_connection *conn;
- struct sbus_interface *intf;
-};
-
-static bool path_in_interface_list(struct sbus_interface_p *list,
- const char *path);
-static void sbus_unreg_object_paths(struct sbus_connection *conn);
-
-static int sbus_auto_reconnect(struct sbus_connection *conn);
-
-static void sbus_dispatch(struct tevent_context *ev,
- struct tevent_timer *te,
- struct timeval tv, void *data)
-{
- struct tevent_timer *new_event;
- struct sbus_connection *conn;
- DBusConnection *dbus_conn;
- int ret;
-
- if (data == NULL) return;
-
- conn = talloc_get_type(data, struct sbus_connection);
-
- dbus_conn = conn->dbus.conn;
- DEBUG(9, ("dbus conn: %lX\n", dbus_conn));
-
- if (conn->retries > 0) {
- DEBUG(6, ("SBUS is reconnecting. Deferring.\n"));
- /* Currently trying to reconnect, defer dispatch */
- new_event = tevent_add_timer(ev, conn, tv, sbus_dispatch, conn);
- if (new_event == NULL) {
- DEBUG(0,("Could not defer dispatch!\n"));
- }
- return;
- }
-
- if ((!dbus_connection_get_is_connected(dbus_conn)) &&
- (conn->max_retries != 0)) {
- /* Attempt to reconnect automatically */
- ret = sbus_auto_reconnect(conn);
- if (ret == EOK) {
- DEBUG(1, ("Performing auto-reconnect\n"));
- return;
- }
-
- DEBUG(0, ("Cannot start auto-reconnection.\n"));
- conn->reconnect_callback(conn,
- SBUS_RECONNECT_ERROR,
- conn->reconnect_pvt);
- return;
- }
-
- if ((conn->disconnect) ||
- (!dbus_connection_get_is_connected(dbus_conn))) {
- DEBUG(3,("Connection is not open for dispatching.\n"));
- /*
- * Free the connection object.
- * This will invoke the destructor for the connection
- */
- talloc_free(conn);
- conn = NULL;
- return;
- }
-
- /* Dispatch only once each time through the mainloop to avoid
- * starving other features
- */
- ret = dbus_connection_get_dispatch_status(dbus_conn);
- if (ret != DBUS_DISPATCH_COMPLETE) {
- DEBUG(9,("Dispatching.\n"));
- dbus_connection_dispatch(dbus_conn);
- }
-
- /* If other dispatches are waiting, queue up the dispatch function
- * for the next loop.
- */
- ret = dbus_connection_get_dispatch_status(dbus_conn);
- if (ret != DBUS_DISPATCH_COMPLETE) {
- new_event = tevent_add_timer(ev, conn, tv, sbus_dispatch, conn);
- if (new_event == NULL) {
- DEBUG(2,("Could not add dispatch event!\n"));
-
- /* TODO: Calling exit here is bad */
- exit(1);
- }
- }
-}
-
-/* dbus_connection_wakeup_main
- * D-BUS makes a callback to the wakeup_main function when
- * it has data available for dispatching.
- * In order to avoid blocking, this function will create a now()
- * timed event to perform the dispatch during the next iteration
- * through the mainloop
- */
-static void sbus_conn_wakeup_main(void *data)
-{
- struct sbus_connection *conn;
- struct timeval tv;
- struct tevent_timer *te;
-
- conn = talloc_get_type(data, struct sbus_connection);
-
- tv = tevent_timeval_current();
-
- /* D-BUS calls this function when it is time to do a dispatch */
- te = tevent_add_timer(conn->ev, conn, tv, sbus_dispatch, conn);
- if (te == NULL) {
- DEBUG(2,("Could not add dispatch event!\n"));
- /* TODO: Calling exit here is bad */
- exit(1);
- }
-}
-
-static int sbus_conn_set_fns(struct sbus_connection *conn);
-
-/*
- * integrate_connection_with_event_loop
- * Set up a D-BUS connection to use the libevents mainloop
- * for handling file descriptor and timed events
- */
-int sbus_init_connection(TALLOC_CTX *ctx,
- struct tevent_context *ev,
- DBusConnection *dbus_conn,
- struct sbus_interface *intf,
- int connection_type,
- struct sbus_connection **_conn)
-{
- struct sbus_connection *conn;
- int ret;
-
- DEBUG(5,("Adding connection %lX\n", dbus_conn));
- conn = talloc_zero(ctx, struct sbus_connection);
-
- conn->ev = ev;
- conn->type = SBUS_CONNECTION;
- conn->dbus.conn = dbus_conn;
- conn->connection_type = connection_type;
-
- ret = sbus_conn_add_interface(conn, intf);
- if (ret != EOK) {
- talloc_free(conn);
- return ret;
- }
-
- ret = sbus_conn_set_fns(conn);
- if (ret != EOK) {
- talloc_free(conn);
- return ret;
- }
-
- *_conn = conn;
- return ret;
-}
-
-static int sbus_conn_set_fns(struct sbus_connection *conn)
-{
- dbus_bool_t dbret;
-
- /*
- * Set the default destructor
- * Connections can override this with
- * sbus_conn_set_destructor
- */
- sbus_conn_set_destructor(conn, NULL);
-
- /* Set up DBusWatch functions */
- dbret = dbus_connection_set_watch_functions(conn->dbus.conn,
- sbus_add_watch,
- sbus_remove_watch,
- sbus_toggle_watch,
- conn, NULL);
- if (!dbret) {
- DEBUG(2,("Error setting up D-BUS connection watch functions\n"));
- return EIO;
- }
-
- /* Set up DBusTimeout functions */
- dbret = dbus_connection_set_timeout_functions(conn->dbus.conn,
- sbus_add_timeout,
- sbus_remove_timeout,
- sbus_toggle_timeout,
- conn, NULL);
- if (!dbret) {
- DEBUG(2,("Error setting up D-BUS server timeout functions\n"));
- /* FIXME: free resources ? */
- return EIO;
- }
-
- /* Set up dispatch handler */
- dbus_connection_set_wakeup_main_function(conn->dbus.conn,
- sbus_conn_wakeup_main,
- conn, NULL);
-
- /* Set up any method_contexts passed in */
-
- /* Attempt to dispatch immediately in case of opportunistic
- * services connecting before the handlers were all up.
- * If there are no messages to be dispatched, this will do
- * nothing.
- */
- sbus_conn_wakeup_main(conn);
-
- return EOK;
-}
-
-int sbus_new_connection(TALLOC_CTX *ctx, struct tevent_context *ev,
- const char *address, struct sbus_interface *intf,
- struct sbus_connection **_conn)
-{
- struct sbus_connection *conn;
- DBusConnection *dbus_conn;
- DBusError dbus_error;
- int ret;
-
- dbus_error_init(&dbus_error);
-
- /* Open a shared D-BUS connection to the address */
- dbus_conn = dbus_connection_open(address, &dbus_error);
- if (!dbus_conn) {
- DEBUG(1, ("Failed to open connection: name=%s, message=%s\n",
- dbus_error.name, dbus_error.message));
- if (dbus_error_is_set(&dbus_error)) dbus_error_free(&dbus_error);
- return EIO;
- }
-
- ret = sbus_init_connection(ctx, ev, dbus_conn, intf,
- SBUS_CONN_TYPE_SHARED, &conn);
- if (ret != EOK) {
- /* FIXME: release resources */
- }
-
- /* Store the address for later reconnection */
- conn->address = talloc_strdup(conn, address);
-
- dbus_connection_set_exit_on_disconnect(conn->dbus.conn, FALSE);
-
- *_conn = conn;
- return ret;
-}
-
-/*
- * sbus_conn_set_destructor
- * Configures a callback to clean up this connection when it
- * is finalized.
- * @param conn The sbus_connection created
- * when this connection was established
- * @param destructor The destructor function that should be
- * called when the connection is finalized. If passed NULL,
- * this will reset the connection to the default destructor.
- */
-void sbus_conn_set_destructor(struct sbus_connection *conn,
- sbus_conn_destructor_fn destructor)
-{
- if (!conn) return;
-
- conn->destructor = destructor;
- /* TODO: Should we try to handle the talloc_destructor too? */
-}
-
-int sbus_default_connection_destructor(void *ctx)
-{
- struct sbus_connection *conn;
- conn = talloc_get_type(ctx, struct sbus_connection);
-
- DEBUG(5, ("Invoking default destructor on connection %lX\n",
- conn->dbus.conn));
- if (conn->connection_type == SBUS_CONN_TYPE_PRIVATE) {
- /* Private connections must be closed explicitly */
- dbus_connection_close(conn->dbus.conn);
- }
- else if (conn->connection_type == SBUS_CONN_TYPE_SHARED) {
- /* Shared connections are destroyed when their last reference is removed */
- }
- else {
- /* Critical Error! */
- DEBUG(1,("Critical Error, connection_type is neither shared nor private!\n"));
- return -1;
- }
-
- /* Remove object path */
- /* TODO: Remove object paths */
-
- dbus_connection_unref(conn->dbus.conn);
- return 0;
-}
-
-/*
- * sbus_get_connection
- * Utility function to retreive the DBusConnection object
- * from a sbus_connection
- */
-DBusConnection *sbus_get_connection(struct sbus_connection *conn)
-{
- return conn->dbus.conn;
-}
-
-void sbus_disconnect (struct sbus_connection *conn)
-{
- if (conn == NULL) {
- return;
- }
-
- DEBUG(5,("Disconnecting %lX\n", conn->dbus.conn));
-
- /*******************************
- * Referencing conn->dbus.conn */
- dbus_connection_ref(conn->dbus.conn);
-
- conn->disconnect = 1;
-
- /* Invoke the custom destructor, if it exists */
- if (conn->destructor) {
- conn->destructor(conn);
- }
-
- /* Unregister object paths */
- sbus_unreg_object_paths(conn);
-
- /* Disable watch functions */
- dbus_connection_set_watch_functions(conn->dbus.conn,
- NULL, NULL, NULL,
- NULL, NULL);
- /* Disable timeout functions */
- dbus_connection_set_timeout_functions(conn->dbus.conn,
- NULL, NULL, NULL,
- NULL, NULL);
-
- /* Disable dispatch status function */
- dbus_connection_set_dispatch_status_function(conn->dbus.conn,
- NULL, NULL, NULL);
-
- /* Disable wakeup main function */
- dbus_connection_set_wakeup_main_function(conn->dbus.conn,
- NULL, NULL, NULL);
-
- /* Finalize the connection */
- sbus_default_connection_destructor(conn);
-
- dbus_connection_unref(conn->dbus.conn);
- /* Unreferenced conn->dbus_conn *
- ******************************/
-
- DEBUG(5,("Disconnected %lX\n", conn->dbus.conn));
-}
-
-static int sbus_reply_internal_error(DBusMessage *message,
- struct sbus_connection *conn) {
- DBusMessage *reply = dbus_message_new_error(message, DBUS_ERROR_IO_ERROR,
- "Internal Error");
- if (reply) {
- sbus_conn_send_reply(conn, reply);
- dbus_message_unref(reply);
- return DBUS_HANDLER_RESULT_HANDLED;
- }
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-}
-
-/* messsage_handler
- * Receive messages and process them
- */
-DBusHandlerResult sbus_message_handler(DBusConnection *dbus_conn,
- DBusMessage *message,
- void *user_data)
-{
- struct sbus_interface_p *intf_p;
- const char *method;
- const char *path;
- const char *msg_interface;
- DBusMessage *reply = NULL;
- int i, ret;
- int found;
-
- if (!user_data) {
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
- }
- intf_p = talloc_get_type(user_data, struct sbus_interface_p);
-
- method = dbus_message_get_member(message);
- DEBUG(9, ("Received SBUS method [%s]\n", method));
- path = dbus_message_get_path(message);
- msg_interface = dbus_message_get_interface(message);
-
- if (!method || !path || !msg_interface)
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
- /* Validate the D-BUS path */
- if (strcmp(path, intf_p->intf->path) != 0)
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
- /* Validate the method interface */
- if (strcmp(msg_interface, intf_p->intf->interface) == 0) {
- found = 0;
- for (i = 0; intf_p->intf->methods[i].method != NULL; i++) {
- if (strcmp(method, intf_p->intf->methods[i].method) == 0) {
- found = 1;
- ret = intf_p->intf->methods[i].fn(message, intf_p->conn);
- if (ret != EOK) {
- return sbus_reply_internal_error(message, intf_p->conn);
- }
- break;
- }
- }
-
- if (!found) {
- /* Reply DBUS_ERROR_UNKNOWN_METHOD */
- DEBUG(1, ("No matching method found for %s.\n", method));
- reply = dbus_message_new_error(message, DBUS_ERROR_UNKNOWN_METHOD, NULL);
- sbus_conn_send_reply(intf_p->conn, reply);
- dbus_message_unref(reply);
- }
- }
- else {
- /* Special case: check for Introspection request
- * This is usually only useful for system bus connections
- */
- if (strcmp(msg_interface, DBUS_INTROSPECT_INTERFACE) == 0 &&
- strcmp(method, DBUS_INTROSPECT_METHOD) == 0)
- {
- if (intf_p->intf->introspect_fn) {
- /* If we have been asked for introspection data and we have
- * an introspection function registered, user that.
- */
- ret = intf_p->intf->introspect_fn(message, intf_p->conn);
- if (ret != EOK) {
- return sbus_reply_internal_error(message, intf_p->conn);
- }
- }
- }
- else
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
- }
-
- return DBUS_HANDLER_RESULT_HANDLED;
-}
-
-/* Adds a new D-BUS path message handler to the connection
- * Note: this must be a unique path.
- */
-int sbus_conn_add_interface(struct sbus_connection *conn,
- struct sbus_interface *intf)
-{
- struct sbus_interface_p *intf_p;
- dbus_bool_t dbret;
- const char *path;
-
- if (!conn || !intf || !intf->vtable.message_function) {
- return EINVAL;
- }
-
- path = intf->path;
-
- if (path_in_interface_list(conn->intf_list, path)) {
- DEBUG(0, ("Cannot add method context with identical path.\n"));
- return EINVAL;
- }
-
- intf_p = talloc_zero(conn, struct sbus_interface_p);
- if (!intf_p) {
- return ENOMEM;
- }
- intf_p->conn = conn;
- intf_p->intf = intf;
-
- DLIST_ADD(conn->intf_list, intf_p);
-
- dbret = dbus_connection_register_object_path(conn->dbus.conn,
- path, &intf->vtable, intf_p);
- if (!dbret) {
- DEBUG(0, ("Could not register object path to the connection.\n"));
- return ENOMEM;
- }
-
- return EOK;
-}
-
-static bool path_in_interface_list(struct sbus_interface_p *list,
- const char *path)
-{
- struct sbus_interface_p *iter;
-
- if (!list || !path) {
- return false;
- }
-
- iter = list;
- while (iter != NULL) {
- if (strcmp(iter->intf->path, path) == 0) {
- return true;
- }
- iter = iter->next;
- }
-
- return false;
-}
-
-static void sbus_unreg_object_paths(struct sbus_connection *conn)
-{
- struct sbus_interface_p *iter = conn->intf_list;
-
- while (iter != NULL) {
- dbus_connection_unregister_object_path(conn->dbus.conn,
- iter->intf->path);
- iter = iter->next;
- }
-}
-
-void sbus_conn_set_private_data(struct sbus_connection *conn, void *pvt_data)
-{
- conn->pvt_data = pvt_data;
-}
-
-void *sbus_conn_get_private_data(struct sbus_connection *conn)
-{
- return conn->pvt_data;
-}
-
-static void sbus_reconnect(struct tevent_context *ev,
- struct tevent_timer *te,
- struct timeval tv, void *data)
-{
- struct sbus_connection *conn;
- struct sbus_interface_p *iter;
- DBusError dbus_error;
- dbus_bool_t dbret;
- int ret;
-
- conn = talloc_get_type(data, struct sbus_connection);
- dbus_error_init(&dbus_error);
-
- DEBUG(3, ("Making reconnection attempt %d to [%s]\n",
- conn->retries, conn->address));
- conn->dbus.conn = dbus_connection_open(conn->address, &dbus_error);
- if (conn->dbus.conn) {
- /* We successfully reconnected. Set up mainloop integration. */
- DEBUG(3, ("Reconnected to [%s]\n", conn->address));
- ret = sbus_conn_set_fns(conn);
- if (ret != EOK) {
- dbus_connection_unref(conn->dbus.conn);
- goto failed;
- }
-
- /* Re-register object paths */
- iter = conn->intf_list;
- while (iter) {
- dbret = dbus_connection_register_object_path(conn->dbus.conn,
- iter->intf->path,
- &iter->intf->vtable,
- iter);
- if (!dbret) {
- DEBUG(0, ("Could not register object path.\n"));
- dbus_connection_unref(conn->dbus.conn);
- goto failed;
- }
- iter = iter->next;
- }
-
- /* Reset retries to 0 to resume dispatch processing */
- conn->retries = 0;
-
- /* Notify the owner of this connection that the
- * reconnection was successful
- */
- conn->reconnect_callback(conn,
- SBUS_RECONNECT_SUCCESS,
- conn->reconnect_pvt);
- return;
- }
-
-failed:
- /* Reconnection failed, try again in a few seconds */
- DEBUG(1, ("Failed to open connection: name=%s, message=%s\n",
- dbus_error.name, dbus_error.message));
- if (dbus_error_is_set(&dbus_error)) dbus_error_free(&dbus_error);
-
- conn->retries++;
-
- /* Check if we've passed our last chance or if we've lost track of
- * our retry count somehow
- */
- if ((conn->retries > conn->max_retries) || (conn->retries <= 0)) {
- conn->reconnect_callback(conn,
- SBUS_RECONNECT_EXCEEDED_RETRIES,
- conn->reconnect_pvt);
- }
-
- if (conn->retries == 2) {
- /* Wait 3 seconds before the second reconnect attempt */
- tv.tv_sec += 3;
- }
- else if (conn->retries == 3) {
- /* Wait 10 seconds before the third reconnect attempt */
- tv.tv_sec += 10;
- }
- else {
- /* Wait 30 seconds before all subsequent reconnect attempts */
- tv.tv_sec += 30;
- }
-
- te = tevent_add_timer(conn->ev, conn, tv, sbus_reconnect, conn);
- if (!te) {
- conn->reconnect_callback(conn,
- SBUS_RECONNECT_ERROR,
- conn->reconnect_pvt);
- }
-}
-
-/* This function will free and recreate the sbus_connection,
- * calling functions need to be aware of this (and whether
- * they have attached a talloc destructor to the
- * sbus_connection.
- */
-static int sbus_auto_reconnect(struct sbus_connection *conn)
-{
- struct tevent_timer *te = NULL;
- struct timeval tv;
-
- conn->retries++;
- if (conn->retries >= conn->max_retries) {
- /* Return EIO (to tell the calling process it
- * needs to create a new connection from scratch
- */
- return EIO;
- }
-
- gettimeofday(&tv, NULL);
- tv.tv_sec += 1; /* Wait 1 second before the first reconnect attempt */
- te = tevent_add_timer(conn->ev, conn, tv, sbus_reconnect, conn);
- if (!te) {
- return EIO;
- }
-
- return EOK;
-}
-
-/* Max retries */
-void sbus_reconnect_init(struct sbus_connection *conn,
- int max_retries,
- sbus_conn_reconn_callback_fn callback,
- void *pvt)
-{
- if (max_retries < 0 || callback == NULL) return;
-
- conn->retries = 0;
- conn->max_retries = max_retries;
- conn->reconnect_callback = callback;
- conn->reconnect_pvt = pvt;
-}
-
-bool sbus_conn_disconnecting(struct sbus_connection *conn)
-{
- if (conn->disconnect == 1) return true;
- return false;
-}
-
-void sbus_conn_send_reply(struct sbus_connection *conn, DBusMessage *reply)
-{
- dbus_connection_send(conn->dbus.conn, reply, NULL);
-}
-