Commit 6ecc14ff authored by Havoc Pennington's avatar Havoc Pennington

2003-03-12 Havoc Pennington <hp@pobox.com>

	Throughout: purge global variables, introduce BusActivation,
	BusConnections, BusRegistry, etc. objects instead.

	* bus/bus.h, bus/bus.c: introduce BusContext as a global
	message bus object

	* test/Makefile.am (TEST_BINARIES): disable bus-test for now,
	going to redo this a bit differently I think
parent 29560adc
2003-03-12 Havoc Pennington <hp@pobox.com>
Throughout: purge global variables, introduce BusActivation,
BusConnections, BusRegistry, etc. objects instead.
* bus/bus.h, bus/bus.c: introduce BusContext as a global
message bus object
* test/Makefile.am (TEST_BINARIES): disable bus-test for now,
going to redo this a bit differently I think
2003-03-12 Havoc Pennington <hp@redhat.com>
Mega-patch that gets the message bus daemon initially handling
......
......@@ -11,6 +11,8 @@ noinst_LTLIBRARIES=libdbus-daemon.la
libdbus_daemon_la_SOURCES= \
activation.c \
activation.h \
bus.c \
bus.h \
connection.c \
connection.h \
desktop-file.c \
......
......@@ -33,8 +33,12 @@
#define DBUS_SERVICE_NAME "Name"
#define DBUS_SERVICE_EXEC "Exec"
static DBusHashTable *activation_entries = NULL;
static char *server_address = NULL;
struct BusActivation
{
int refcount;
DBusHashTable *entries;
char *server_address;
};
typedef struct
{
......@@ -42,12 +46,6 @@ typedef struct
char *exec;
} BusActivationEntry;
static DBusHashTable *pending_activations = NULL;
typedef struct
{
char *service;
} BusPendingActivation;
static void
bus_activation_entry_free (BusActivationEntry *entry)
{
......@@ -59,7 +57,8 @@ bus_activation_entry_free (BusActivationEntry *entry)
}
static dbus_bool_t
add_desktop_file_entry (BusDesktopFile *desktop_file,
add_desktop_file_entry (BusActivation *activation,
BusDesktopFile *desktop_file,
DBusError *error)
{
char *name, *exec;
......@@ -92,7 +91,7 @@ add_desktop_file_entry (BusDesktopFile *desktop_file,
/* FIXME we need a better-defined algorithm for which service file to
* pick than "whichever one is first in the directory listing"
*/
if (_dbus_hash_table_lookup_string (activation_entries, name))
if (_dbus_hash_table_lookup_string (activation->entries, name))
{
dbus_set_error (error, DBUS_ERROR_FAILED,
"Service %s already exists in activation entry list\n", name);
......@@ -109,7 +108,7 @@ add_desktop_file_entry (BusDesktopFile *desktop_file,
entry->name = name;
entry->exec = exec;
if (!_dbus_hash_table_insert_string (activation_entries, entry->name, entry))
if (!_dbus_hash_table_insert_string (activation->entries, entry->name, entry))
{
BUS_SET_OOM (error);
goto failed;
......@@ -131,8 +130,9 @@ add_desktop_file_entry (BusDesktopFile *desktop_file,
* hash entries it already added.
*/
static dbus_bool_t
load_directory (const char *directory,
DBusError *error)
load_directory (BusActivation *activation,
const char *directory,
DBusError *error)
{
DBusDirIter *iter;
DBusString dir, filename;
......@@ -213,7 +213,7 @@ load_directory (const char *directory,
continue;
}
if (!add_desktop_file_entry (desktop_file, &tmp_error))
if (!add_desktop_file_entry (activation, desktop_file, &tmp_error))
{
const char *full_path_c;
......@@ -263,27 +263,34 @@ load_directory (const char *directory,
return FALSE;
}
dbus_bool_t
bus_activation_init (const char *address,
const char **directories,
DBusError *error)
BusActivation*
bus_activation_new (const char *address,
const char **directories,
DBusError *error)
{
int i;
BusActivation *activation;
_dbus_assert (server_address == NULL);
_dbus_assert (activation_entries == NULL);
activation = dbus_new0 (BusActivation, 1);
if (activation == NULL)
{
BUS_SET_OOM (error);
return NULL;
}
activation->refcount = 1;
/* FIXME: We should split up the server addresses. */
server_address = _dbus_strdup (address);
if (server_address == NULL)
activation->server_address = _dbus_strdup (address);
if (activation->server_address == NULL)
{
BUS_SET_OOM (error);
goto failed;
}
activation_entries = _dbus_hash_table_new (DBUS_HASH_STRING, NULL,
activation->entries = _dbus_hash_table_new (DBUS_HASH_STRING, NULL,
(DBusFreeFunction)bus_activation_entry_free);
if (activation_entries == NULL)
if (activation->entries == NULL)
{
BUS_SET_OOM (error);
goto failed;
......@@ -293,39 +300,63 @@ bus_activation_init (const char *address,
i = 0;
while (directories[i] != NULL)
{
if (!load_directory (directories[i], error))
if (!load_directory (activation, directories[i], error))
goto failed;
++i;
}
return TRUE;
return activation;
failed:
dbus_free (server_address);
if (activation_entries)
_dbus_hash_table_unref (activation_entries);
bus_activation_unref (activation);
return NULL;
}
void
bus_activation_ref (BusActivation *activation)
{
_dbus_assert (activation->refcount > 0);
return FALSE;
activation->refcount += 1;
}
void
bus_activation_unref (BusActivation *activation)
{
_dbus_assert (activation->refcount > 0);
activation->refcount -= 1;
if (activation->refcount == 0)
{
dbus_free (activation->server_address);
if (activation->entries)
_dbus_hash_table_unref (activation->entries);
dbus_free (activation);
}
}
static void
child_setup (void *data)
{
BusActivation *activation = data;
/* If no memory, we simply have the child exit, so it won't try
* to connect to the wrong thing.
*/
if (!_dbus_setenv ("DBUS_ADDRESS", server_address))
if (!_dbus_setenv ("DBUS_ADDRESS", activation->server_address))
_dbus_exit (1);
}
dbus_bool_t
bus_activation_activate_service (const char *service_name,
DBusError *error)
bus_activation_activate_service (BusActivation *activation,
const char *service_name,
DBusError *error)
{
BusActivationEntry *entry;
char *argv[2];
entry = _dbus_hash_table_lookup_string (activation_entries, service_name);
entry = _dbus_hash_table_lookup_string (activation->entries, service_name);
if (!entry)
{
......@@ -344,7 +375,7 @@ bus_activation_activate_service (const char *service_name,
argv[1] = NULL;
if (!_dbus_spawn_async (argv,
child_setup, NULL,
child_setup, activation,
error))
return FALSE;
......
......@@ -25,12 +25,17 @@
#define BUS_ACTIVATION_H
#include <dbus/dbus.h>
#include "bus.h"
BusActivation* bus_activation_new (const char *address,
const char **paths,
DBusError *error);
void bus_activation_ref (BusActivation *activation);
void bus_activation_unref (BusActivation *activation);
dbus_bool_t bus_activation_activate_service (BusActivation *activation,
const char *service_name,
DBusError *error);
dbus_bool_t bus_activation_init (const char *address,
const char **paths,
DBusError *error);
dbus_bool_t bus_activation_activate_service (const char *service_name,
DBusError *error);
#endif /* BUS_ACTIVATION_H */
/* -*- mode: C; c-file-style: "gnu" -*- */
/* bus.c message bus context object
*
* Copyright (C) 2003 Red Hat, Inc.
*
* Licensed under the Academic Free License version 1.2
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "bus.h"
#include "loop.h"
#include "activation.h"
#include "connection.h"
#include "services.h"
#include "utils.h"
#include <dbus/dbus-internals.h>
struct BusContext
{
int refcount;
char *address;
DBusServer *server;
BusConnections *connections;
BusActivation *activation;
BusRegistry *registry;
};
static void
server_watch_callback (DBusWatch *watch,
unsigned int condition,
void *data)
{
BusContext *context = data;
dbus_server_handle_watch (context->server, watch, condition);
}
static void
add_server_watch (DBusWatch *watch,
BusContext *context)
{
bus_loop_add_watch (watch, server_watch_callback, context,
NULL);
}
static void
remove_server_watch (DBusWatch *watch,
BusContext *context)
{
bus_loop_remove_watch (watch, server_watch_callback, context);
}
static void
new_connection_callback (DBusServer *server,
DBusConnection *new_connection,
void *data)
{
BusContext *context = data;
if (!bus_connections_setup_connection (context->connections, new_connection))
_dbus_verbose ("No memory to setup new connection\n");
/* on OOM, we won't have ref'd the connection so it will die */
}
BusContext*
bus_context_new (const char *address,
const char **service_dirs,
DBusError *error)
{
BusContext *context;
DBusResultCode result;
context = dbus_new0 (BusContext, 1);
if (context == NULL)
{
BUS_SET_OOM (error);
return NULL;
}
context->refcount = 1;
context->address = _dbus_strdup (address);
if (context->address == NULL)
{
BUS_SET_OOM (error);
goto failed;
}
context->server = dbus_server_listen (address, &result);
if (context->server == NULL)
{
dbus_set_error (error, DBUS_ERROR_FAILED,
"Failed to start server on %s: %s\n",
address, dbus_result_to_string (result));
goto failed;
}
context->activation = bus_activation_new (address, service_dirs,
error);
if (context->activation == NULL)
{
_DBUS_ASSERT_ERROR_IS_SET (error);
goto failed;
}
context->connections = bus_connections_new (context);
if (context->connections == NULL)
{
BUS_SET_OOM (error);
goto failed;
}
context->registry = bus_registry_new ();
if (context->registry == NULL)
{
BUS_SET_OOM (error);
goto failed;
}
dbus_server_set_new_connection_function (context->server,
new_connection_callback,
context, NULL);
dbus_server_set_watch_functions (context->server,
(DBusAddWatchFunction) add_server_watch,
(DBusRemoveWatchFunction) remove_server_watch,
context,
NULL);
return context;
failed:
bus_context_unref (context);
return NULL;
}
void
bus_context_shutdown (BusContext *context)
{
dbus_server_disconnect (context->server);
}
void
bus_context_ref (BusContext *context)
{
_dbus_assert (context->refcount > 0);
context->refcount += 1;
}
void
bus_context_unref (BusContext *context)
{
_dbus_assert (context->refcount > 0);
context->refcount -= 1;
if (context->refcount == 0)
{
if (context->registry)
bus_registry_unref (context->registry);
if (context->connections)
bus_connections_unref (context->connections);
if (context->activation)
bus_activation_unref (context->activation);
if (context->server)
dbus_server_unref (context->server);
dbus_free (context->address);
dbus_free (context);
}
}
BusRegistry*
bus_context_get_registry (BusContext *context)
{
return context->registry;
}
BusConnections*
bus_context_get_connections (BusContext *context)
{
return context->connections;
}
BusActivation*
bus_context_get_activation (BusContext *context)
{
return context->activation;
}
/* -*- mode: C; c-file-style: "gnu" -*- */
/* bus.h message bus context object
*
* Copyright (C) 2003 Red Hat, Inc.
*
* Licensed under the Academic Free License version 1.2
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef BUS_BUS_H
#define BUS_BUS_H
#include <dbus/dbus.h>
#include <dbus/dbus-string.h>
typedef struct BusActivation BusActivation;
typedef struct BusConnections BusConnections;
typedef struct BusContext BusContext;
typedef struct BusRegistry BusRegistry;
typedef struct BusService BusService;
typedef struct BusTransaction BusTransaction;
BusContext* bus_context_new (const char *address,
const char **service_dirs,
DBusError *error);
void bus_context_shutdown (BusContext *context);
void bus_context_ref (BusContext *context);
void bus_context_unref (BusContext *context);
BusRegistry* bus_context_get_registry (BusContext *context);
BusConnections* bus_context_get_connections (BusContext *context);
BusActivation* bus_context_get_activation (BusContext *context);
#endif /* BUS_BUS_H */
......@@ -29,11 +29,18 @@
static void bus_connection_remove_transactions (DBusConnection *connection);
static int connection_data_slot;
static DBusList *connections = NULL;
struct BusConnections
{
int refcount;
DBusList *list; /**< List of all the connections */
BusContext *context;
};
static int connection_data_slot = -1;
typedef struct
{
BusConnections *connections;
DBusConnection *connection;
DBusList *services_owned;
char *name;
......@@ -74,7 +81,7 @@ bus_connection_disconnected (DBusConnection *connection)
transaction = NULL;
while (transaction == NULL)
{
transaction = bus_transaction_new ();
transaction = bus_transaction_new (d->connections->context);
bus_wait_for_memory ();
}
......@@ -107,12 +114,14 @@ bus_connection_disconnected (DBusConnection *connection)
NULL);
bus_connection_remove_transactions (connection);
_dbus_list_remove (&d->connections->list, connection);
/* frees "d" as side effect */
dbus_connection_set_data (connection,
connection_data_slot,
NULL, NULL);
_dbus_list_remove (&connections, connection);
dbus_connection_unref (connection);
}
......@@ -166,19 +175,55 @@ free_connection_data (void *data)
dbus_free (d);
}
dbus_bool_t
bus_connection_init (void)
BusConnections*
bus_connections_new (BusContext *context)
{
connection_data_slot = dbus_connection_allocate_data_slot ();
BusConnections *connections;
if (connection_data_slot < 0)
return FALSE;
{
connection_data_slot = dbus_connection_allocate_data_slot ();
if (connection_data_slot < 0)
return NULL;
}
return TRUE;
connections = dbus_new0 (BusConnections, 1);
if (connections == NULL)
return NULL;
connections->refcount = 1;
connections->context = context;
return connections;
}
void
bus_connections_ref (BusConnections *connections)
{
_dbus_assert (connections->refcount > 0);
connections->refcount += 1;
}
void
bus_connections_unref (BusConnections *connections)
{
_dbus_assert (connections->refcount > 0);
connections->refcount -= 1;
if (connections->refcount == 0)
{
/* FIXME free each connection... */
_dbus_assert_not_reached ("shutting down connections not implemented");
_dbus_list_clear (&connections->list);
dbus_free (connections);
}
}
dbus_bool_t
bus_connection_setup (DBusConnection *connection)
bus_connections_setup_connection (BusConnections *connections,
DBusConnection *connection)
{
BusConnectionData *d;
......@@ -187,6 +232,7 @@ bus_connection_setup (DBusConnection *connection)
if (d == NULL)
return FALSE;
d->connections = connections;
d->connection = connection;
if (!dbus_connection_set_data (connection,
......@@ -197,7 +243,7 @@ bus_connection_setup (DBusConnection *connection)
return FALSE;
}
if (!_dbus_list_append (&connections, connection))
if (!_dbus_list_append (&connections->list, connection))
{
/* this will free our data when connection gets finalized */
dbus_connection_disconnect (connection);
......@@ -219,6 +265,89 @@ bus_connection_setup (DBusConnection *connection)
return TRUE;
}
/**
* Calls function on each connection; if the function returns
* #FALSE, stops iterating.
*
* @param connections the connections object
* @param function the function
* @param data data to pass to it as a second arg
*/
void
bus_connections_foreach (BusConnections *connections,
BusConnectionForeachFunction function,
void *data)
{
DBusList *link;
link = _dbus_list_get_first_link (&connections->list);
while (link != NULL)
{
DBusConnection *connection = link->data;
DBusList *next = _dbus_list_get_next_link (&connections->list, link);
if (!(* function) (connection, data))
break;
link = next;
}
}
BusContext*
bus_connections_get_context (BusConnections *connections)
{
return connections->context;
}
BusContext*
bus_connection_get_context (DBusConnection *connection)
{
BusConnectionData *d;
d = BUS_CONNECTION_DATA (connection);
_dbus_assert (d != NULL);
return d->connections->context;
}
BusConnections*
bus_connection_get_connections (DBusConnection *connection)
{
BusConnectionData *d;
d = BUS_CONNECTION_DATA (connection);
_dbus_assert (d != NULL);
return d->connections;
}
BusRegistry*
bus_connection_get_registry (DBusConnection *connection)
{
BusConnectionData *d;
d = BUS_CONNECTION_DATA (connection);
_dbus_assert (d != NULL);
return bus_context_get_registry (d->connections->context);
}
BusActivation*
bus_connection_get_activation (DBusConnection *connection)
{
BusConnectionData *d;
d = BUS_CONNECTION_DATA (connection);
_dbus_assert (d != NULL);
return bus_context_get_activation (d->connections->context);
}
/**
* Checks whether the connection is registered with the message bus.
*
......@@ -361,32 +490,6 @@ bus_connection_get_name (DBusConnection *connection)
return d->name;
}
/**
* Calls function on each connection; if the function returns
* #FALSE, stops iterating.
*
* @param function the function
* @param data data to pass to it as a second arg
*/
void
bus_connection_foreach (BusConnectionForeachFunction function,
void *data)
{
DBusList *link;
link = _dbus_list_get_first_link (&connections);
while (link != NULL)
{
DBusConnection *connection = link->data;
DBusList *next = _dbus_list_get_next_link (&connections, link);
if (!(* function) (connection, data))
break;
link = next;
}
}
typedef struct
{
BusTransaction *transaction;
......@@ -397,7 +500,7 @@ typedef struct
struct BusTransaction
{