/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-bus.c Convenience functions for communicating with the bus.
*
*
* Licensed under the Academic Free License version 2.1
*
* 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 "dbus-bus.h"
#include "dbus-protocol.h"
#include "dbus-internals.h"
#include "dbus-message.h"
#include "dbus-marshal-validate.h"
#include "dbus-threads-internal.h"
#include "dbus-connection-internal.h"
#include <string.h>
/**
* @defgroup DBusBus Message bus APIs
* @ingroup DBus
* @brief Functions for communicating with the message bus
*
* dbus_bus_get() allows all modules and libraries in a given
* process to share the same connection to the bus daemon by storing
* the connection globally.
*
* All other functions in this module are just convenience functions;
* most of them invoke methods on the bus daemon, by sending method
* call messages to #DBUS_SERVICE_DBUS. These convenience functions
* often make blocking method calls. If you don't want to block,
* you can send the method call messages manually in the same way
* you would any other method call message.
*
* This module is the only one in libdbus that's specific to
* communicating with the message bus daemon. The rest of the API can
* also be used for connecting to another application directly.
*
* @todo right now the default address of the system bus is hardcoded,
* so if you change it in the global config file suddenly you have to
* set DBUS_SYSTEM_BUS_ADDRESS env variable. Might be nice if the
* client lib somehow read the config file, or if the bus on startup
* somehow wrote out its address to a well-known spot, but might also
* not be worth it.
*/
/**
* @defgroup DBusBusInternals Message bus APIs internals
* @ingroup DBusInternals
* @brief Internals of functions for communicating with the message bus
*
* @{
*/
/**
* Block of message-bus-related data we attach to each
* #DBusConnection used with these convenience functions.
*
*/
typedef struct
{
DBusConnection *connection; /**< Connection we're associated with */
char *unique_name; /**< Unique name of this connection */
unsigned int is_well_known : 1; /**< Is one of the well-known connections in our global array */
} BusData;
/** The slot we have reserved to store BusData.
*/
static dbus_int32_t bus_data_slot = -1;
/** Number of bus types */
#define N_BUS_TYPES 3
static DBusConnection *bus_connections[N_BUS_TYPES];
static char *bus_connection_addresses[N_BUS_TYPES] = { NULL, NULL, NULL };
static DBusBusType activation_bus_type = DBUS_BUS_STARTER;
static dbus_bool_t initialized = FALSE;
/**
* Lock for globals in this file
*/
_DBUS_DEFINE_GLOBAL_LOCK (bus);
/**
* Global lock covering all BusData on any connection. The bet is
* that some lock contention is better than more memory
* for a per-connection lock, but it's tough to imagine it mattering
* either way.
*/
_DBUS_DEFINE_GLOBAL_LOCK (bus_datas);
static void
addresses_shutdown_func (void *data)
{
int i;
i = 0;
while (i < N_BUS_TYPES)
{
if (bus_connections[i] != NULL)
_dbus_warn_check_failed ("dbus_shutdown() called but connections were still live. This probably means the application did not drop all its references to bus connections.\n");
dbus_free (bus_connection_addresses[i]);
bus_connection_addresses[i] = NULL;
++i;
}
activation_bus_type = DBUS_BUS_STARTER;
}
static dbus_bool_t
get_from_env (char **connection_p,
const char *env_var)
{
const char *s;
_dbus_assert (*connection_p == NULL);
s = _dbus_getenv (env_var);
if (s == NULL || *s == '\0')
return TRUE; /* successfully didn't use the env var */
else
{
*connection_p = _dbus_strdup (s);
return *connection_p != NULL;
}
}
static dbus_bool_t
init_connections_unlocked (void)
{
if (!initialized)
{
const char *s;
int i;
i = 0;
while (i < N_BUS_TYPES)
{
bus_connections[i] = NULL;
++i;
}
/* Don't init these twice, we may run this code twice if
* init_connections_unlocked() fails midway through.
* In practice, each block below should contain only one
* "return FALSE" or running through twice may not
* work right.
*/
if (bus_connection_addresses[DBUS_BUS_SYSTEM] == NULL)
{
_dbus_verbose ("Filling in system bus address...\n");
if (!get_from_env (&bus_connection_addresses[DBUS_BUS_SYSTEM],
"DBUS_SYSTEM_BUS_ADDRESS"))
return FALSE;
}
if (bus_connection_addresses[DBUS_BUS_SYSTEM] == NULL)
{
/* Use default system bus address if none set in environment */
bus_connection_addresses[DBUS_BUS_SYSTEM] =
_dbus_strdup (DBUS_SYSTEM_BUS_DEFAULT_ADDRESS);
if (bus_connection_addresses[DBUS_BUS_SYSTEM] == NULL)
return FALSE;
_dbus_verbose (" used default system bus \"%s\"\n",
bus_connection_addresses[DBUS_BUS_SYSTEM]);
}
else
_dbus_verbose (" used env var system bus \"%s\"\n",
bus_connection_addresses[DBUS_BUS_SYSTEM]);
if (bus_connection_addresses[DBUS_BUS_SESSION] == NULL)
{
_dbus_verbose ("Filling in session bus address...\n");
if (!get_from_env (&bus_connection_addresses[DBUS_BUS_SESSION],
"DBUS_SESSION_BUS_ADDRESS"))
return FALSE;
if (bus_connection_addresses[DBUS_BUS_SESSION] == NULL)
bus_connection_addresses[DBUS_BUS_SESSION] =
_dbus_strdup (DBUS_SESSION_BUS_DEFAULT_ADDRESS);
if (bus_connection_addresses[DBUS_BUS_SESSION] == NULL)
return FALSE;
_dbus_verbose (" \"%s\"\n", bus_connection_addresses[DBUS_BUS_SESSION] ?
bus_connection_addresses[DBUS_BUS_SESSION] : "none set");
}
if (bus_connection_addresses[DBUS_BUS_STARTER] == NULL)
{
_dbus_verbose ("Filling in activation bus address...\n");
if (!get_from_env (&bus_connection_addresses[DBUS_BUS_STARTER],
"DBUS_STARTER_ADDRESS"))
return FALSE;
_dbus_verbose (" \"%s\"\n", bus_connection_addresses[DBUS_BUS_STARTER] ?
bus_connection_addresses[DBUS_BUS_STARTER] : "none set");
}
if (bus_connection_addresses[DBUS_BUS_STARTER] != NULL)
{
s = _dbus_getenv ("DBUS_STARTER_BUS_TYPE");
if (s != NULL)
{
_dbus_verbose ("Bus activation type was set to \"%s\"\n", s);
if (strcmp (s, "system") == 0)
activation_bus_type = DBUS_BUS_SYSTEM;
else if (strcmp (s, "session") == 0)
activation_bus_type = DBUS_BUS_SESSION;
}
}
else
{
/* Default to the session bus instead if available */
if (bus_connection_addresses[DBUS_BUS_SESSION] != NULL)
{
bus_connection_addresses[DBUS_BUS_STARTER] =