Commit 54b94343 authored by Havoc Pennington's avatar Havoc Pennington

2007-06-18 Havoc Pennington <hp@redhat.com>

	* doc/dbus-specification.xml: document org.freedesktop.DBus.GetId()

	* bus/driver.c (bus_driver_handle_get_id): implement org.freedesktop.DBus.GetId()

	* bus/bus.c (bus_context_new): generate a unique ID for each bus context

	* dbus/dbus-connection.c (dbus_connection_get_server_id): new function

	* dbus/dbus-bus.c (dbus_bus_get_id): new function

	* dbus/dbus-server.c (dbus_server_get_id): new function
parent ded479fd
2007-06-18 Havoc Pennington <hp@redhat.com>
* doc/dbus-specification.xml: document org.freedesktop.DBus.GetId()
* bus/driver.c (bus_driver_handle_get_id): implement org.freedesktop.DBus.GetId()
* bus/bus.c (bus_context_new): generate a unique ID for each bus context
* dbus/dbus-connection.c (dbus_connection_get_server_id): new function
* dbus/dbus-bus.c (dbus_bus_get_id): new function
* dbus/dbus-server.c (dbus_server_get_id): new function
2007-06-18 Havoc Pennington <hp@redhat.com>
* dbus/dbus-sysdeps-unix.c (_dbus_read_credentials_socket): clean
this up a little bit, to try and understand why telnet'ing to a
server and sending a non-nul byte didn't disconnect immediately;
......
......@@ -38,6 +38,7 @@
struct BusContext
{
int refcount;
DBusGUID uuid;
char *config_file;
char *type;
char *address;
......@@ -552,6 +553,8 @@ bus_context_new (const DBusString *config_file,
}
context->refcount = 1;
_dbus_generate_uuid (&context->uuid);
if (!_dbus_string_copy_data (config_file, &context->config_file))
{
BUS_SET_OOM (error);
......@@ -784,6 +787,13 @@ bus_context_new (const DBusString *config_file,
return NULL;
}
dbus_bool_t
bus_context_get_id (BusContext *context,
DBusString *uuid)
{
return _dbus_uuid_encode (&context->uuid, uuid);
}
dbus_bool_t
bus_context_reload_config (BusContext *context,
DBusError *error)
......
......@@ -78,6 +78,8 @@ dbus_bool_t bus_context_reload_config (BusContext
void bus_context_shutdown (BusContext *context);
BusContext* bus_context_ref (BusContext *context);
void bus_context_unref (BusContext *context);
dbus_bool_t bus_context_get_id (BusContext *context,
DBusString *uuid);
const char* bus_context_get_type (BusContext *context);
const char* bus_context_get_address (BusContext *context);
BusRegistry* bus_context_get_registry (BusContext *context);
......
......@@ -1382,6 +1382,61 @@ bus_driver_handle_reload_config (DBusConnection *connection,
return FALSE;
}
static dbus_bool_t
bus_driver_handle_get_id (DBusConnection *connection,
BusTransaction *transaction,
DBusMessage *message,
DBusError *error)
{
BusContext *context;
DBusMessage *reply;
DBusString uuid;
const char *v_STRING;
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
if (!_dbus_string_init (&uuid))
{
BUS_SET_OOM (error);
return FALSE;
}
reply = NULL;
context = bus_connection_get_context (connection);
if (!bus_context_get_id (context, &uuid))
goto oom;
reply = dbus_message_new_method_return (message);
if (reply == NULL)
goto oom;
v_STRING = _dbus_string_get_const_data (&uuid);
if (!dbus_message_append_args (reply,
DBUS_TYPE_STRING, &v_STRING,
DBUS_TYPE_INVALID))
goto oom;
_dbus_assert (dbus_message_has_signature (reply, "s"));
if (! bus_transaction_send_from_driver (transaction, connection, reply))
goto oom;
_dbus_string_free (&uuid);
dbus_message_unref (reply);
return TRUE;
oom:
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
BUS_SET_OOM (error);
if (reply)
dbus_message_unref (reply);
_dbus_string_free (&uuid);
return FALSE;
}
/* For speed it might be useful to sort this in order of
* frequency of use (but doesn't matter with only a few items
* anyhow)
......@@ -1396,6 +1451,10 @@ struct
DBusMessage *message,
DBusError *error);
} message_handlers[] = {
{ "Hello",
"",
DBUS_TYPE_STRING_AS_STRING,
bus_driver_handle_hello },
{ "RequestName",
DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_UINT32_AS_STRING,
DBUS_TYPE_UINT32_AS_STRING,
......@@ -1408,10 +1467,6 @@ struct
DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_UINT32_AS_STRING,
DBUS_TYPE_UINT32_AS_STRING,
bus_driver_handle_activate_service },
{ "Hello",
"",
DBUS_TYPE_STRING_AS_STRING,
bus_driver_handle_hello },
{ "NameHasOwner",
DBUS_TYPE_STRING_AS_STRING,
DBUS_TYPE_BOOLEAN_AS_STRING,
......@@ -1455,7 +1510,11 @@ struct
{ "ReloadConfig",
"",
"",
bus_driver_handle_reload_config }
bus_driver_handle_reload_config },
{ "GetId",
"",
DBUS_TYPE_STRING_AS_STRING,
bus_driver_handle_get_id }
};
static dbus_bool_t
......
......@@ -865,6 +865,85 @@ dbus_bus_get_unix_user (DBusConnection *connection,
return (unsigned long) uid;
}
/**
* Asks the bus to return its globally unique ID, as described in the
* D-Bus specification. For the session bus, this is useful as a way
* to uniquely identify each user session. For the system bus,
* probably the bus ID is not useful; instead, use the machine ID
* since it's accessible without necessarily connecting to the bus and
* may be persistent beyond a single bus instance (across reboots for
* example). See dbus_get_local_machine_id().
*
* In addition to an ID for each bus and an ID for each machine, there is
* an ID for each address that the bus is listening on; that can
* be retrieved with dbus_connection_get_server_id(), though it is
* probably not very useful.
*
* @param connection the connection
* @param error location to store the error
* @returns the bus ID or #NULL if error is set
*/
char*
dbus_bus_get_id (DBusConnection *connection,
DBusError *error)
{
DBusMessage *message, *reply;
char *id;
const char *v_STRING;
_dbus_return_val_if_fail (connection != NULL, NULL);
_dbus_return_val_if_error_is_set (error, NULL);
message = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
DBUS_PATH_DBUS,
DBUS_INTERFACE_DBUS,
"GetId");
if (message == NULL)
{
_DBUS_SET_OOM (error);
return NULL;
}
reply = dbus_connection_send_with_reply_and_block (connection, message, -1,
error);
dbus_message_unref (message);
if (reply == NULL)
{
_DBUS_ASSERT_ERROR_IS_SET (error);
return NULL;
}
if (dbus_set_error_from_message (error, reply))
{
_DBUS_ASSERT_ERROR_IS_SET (error);
dbus_message_unref (reply);
return NULL;
}
v_STRING = NULL;
if (!dbus_message_get_args (reply, error,
DBUS_TYPE_STRING, &v_STRING,
DBUS_TYPE_INVALID))
{
_DBUS_ASSERT_ERROR_IS_SET (error);
dbus_message_unref (reply);
return NULL;
}
id = _dbus_strdup (v_STRING); /* may be NULL */
dbus_message_unref (reply);
if (id == NULL)
_DBUS_SET_OOM (error);
/* FIXME it might be nice to cache the ID locally */
return id;
}
/**
* Asks the bus to assign the given name to this connection by invoking
......
......@@ -49,6 +49,8 @@ const char* dbus_bus_get_unique_name (DBusConnection *connection);
unsigned long dbus_bus_get_unix_user (DBusConnection *connection,
const char *name,
DBusError *error);
char* dbus_bus_get_id (DBusConnection *connection,
DBusError *error);
int dbus_bus_request_name (DBusConnection *connection,
const char *name,
unsigned int flags,
......
......@@ -2844,6 +2844,51 @@ dbus_connection_get_is_anonymous (DBusConnection *connection)
return res;
}
/**
* Gets the ID of the server address we are authenticated to, if this
* connection is on the client side. If the connection is on the
* server side, this will always return #NULL - use dbus_server_get_id()
* to get the ID of your own server, if you are the server side.
*
* If a client-side connection is not authenticated yet, the ID may be
* available if it was included in the server address, but may not be
* available. The only way to be sure the server ID is available
* is to wait for authentication to complete.
*
* In general, each mode of connecting to a given server will have
* its own ID. So for example, if the session bus daemon is listening
* on UNIX domain sockets and on TCP, then each of those modalities
* will have its own server ID.
*
* If you want an ID that identifies an entire session bus, look at
* dbus_bus_get_id() instead (which is just a convenience wrapper
* around the org.freedesktop.DBus.GetId method invoked on the bus).
*
* You can also get a machine ID; see dbus_get_local_machine_id() to
* get the machine you are on. There isn't a convenience wrapper, but
* you can invoke org.freedesktop.DBus.Peer.GetMachineId on any peer
* to get the machine ID on the other end.
*
* The D-Bus specification describes the server ID and other IDs in a
* bit more detail.
*
* @param connection the connection
* @returns the server ID or #NULL if no memory or the connection is server-side
*/
char*
dbus_connection_get_server_id (DBusConnection *connection)
{
char *id;
_dbus_return_val_if_fail (connection != NULL, FALSE);
CONNECTION_LOCK (connection);
id = _dbus_strdup (_dbus_transport_get_server_id (connection->transport));
CONNECTION_UNLOCK (connection);
return id;
}
/**
* Set whether _exit() should be called when the connection receives a
* disconnect signal. The call to _exit() comes after any handlers for
......
......@@ -179,6 +179,7 @@ void dbus_connection_close (DBusConnection
dbus_bool_t dbus_connection_get_is_connected (DBusConnection *connection);
dbus_bool_t dbus_connection_get_is_authenticated (DBusConnection *connection);
dbus_bool_t dbus_connection_get_is_anonymous (DBusConnection *connection);
char* dbus_connection_get_server_id (DBusConnection *connection);
void dbus_connection_set_exit_on_disconnect (DBusConnection *connection,
dbus_bool_t exit_on_disconnect);
void dbus_connection_flush (DBusConnection *connection);
......
......@@ -798,6 +798,43 @@ dbus_server_get_address (DBusServer *server)
return retval;
}
/**
* Returns the unique ID of the server, as a newly-allocated
* string which must be freed by the caller. This ID is
* normally used by clients to tell when two #DBusConnection
* would be equivalent (because the server address passed
* to dbus_connection_open() will have the same guid in the
* two cases). dbus_connection_open() can re-use an existing
* connection with the same ID instead of opening a new
* connection.
*
* This is an ID unique to each #DBusServer. Remember that
* a #DBusServer represents only one mode of connecting,
* so e.g. a bus daemon can listen on multiple addresses
* which will mean it has multiple #DBusServer each with
* their own ID.
*
* The ID is not a UUID in the sense of RFC4122; the details
* are explained in the D-Bus specification.
*
* @param server the server
* @returns the id of the server or #NULL if no memory
*/
char*
dbus_server_get_id (DBusServer *server)
{
char *retval;
_dbus_return_val_if_fail (server != NULL, NULL);
SERVER_LOCK (server);
retval = NULL;
_dbus_string_copy_data (&server->guid_hex, &retval);
SERVER_UNLOCK (server);
return retval;
}
/**
* Sets a function to be used for handling new connections. The given
* function is passed each new connection as the connection is
......@@ -1110,6 +1147,7 @@ dbus_server_get_data (DBusServer *server,
#ifdef DBUS_BUILD_TESTS
#include "dbus-test.h"
#include <string.h>
dbus_bool_t
_dbus_server_test (void)
......@@ -1130,8 +1168,8 @@ _dbus_server_test (void)
for (i = 0; i < _DBUS_N_ELEMENTS (valid_addresses); i++)
{
DBusError error;
/* FIXME um, how are the two tests here different? */
char *address;
char *id;
dbus_error_init (&error);
server = dbus_server_listen (valid_addresses[i], &error);
......@@ -1142,18 +1180,21 @@ _dbus_server_test (void)
_dbus_assert_not_reached ("Failed to listen for valid address.");
}
dbus_server_disconnect (server);
dbus_server_unref (server);
id = dbus_server_get_id (server);
_dbus_assert (id != NULL);
address = dbus_server_get_address (server);
_dbus_assert (address != NULL);
/* Try disconnecting before unreffing */
server = dbus_server_listen (valid_addresses[i], &error);
if (server == NULL)
if (strstr (address, id) == NULL)
{
_dbus_warn ("server listen error: %s: %s\n", error.name, error.message);
dbus_error_free (&error);
_dbus_assert_not_reached ("Failed to listen for valid address.");
_dbus_warn ("server id '%s' is not in the server address '%s'\n",
id, address);
_dbus_assert_not_reached ("bad server id or address");
}
dbus_free (id);
dbus_free (address);
dbus_server_disconnect (server);
dbus_server_unref (server);
}
......
......@@ -55,6 +55,7 @@ void dbus_server_unref (DBusServer *server);
void dbus_server_disconnect (DBusServer *server);
dbus_bool_t dbus_server_get_is_connected (DBusServer *server);
char* dbus_server_get_address (DBusServer *server);
char* dbus_server_get_id (DBusServer *server);
void dbus_server_set_new_connection_function (DBusServer *server,
DBusNewConnectionFunction function,
void *data,
......
......@@ -791,6 +791,22 @@ _dbus_transport_get_address (DBusTransport *transport)
return transport->address;
}
/**
* Gets the id of the server we are connected to (see
* dbus_server_get_id()). Only works on client side.
*
* @param transport the transport
* @returns transport's server's id or #NULL if we are the server side
*/
const char*
_dbus_transport_get_server_id (DBusTransport *transport)
{
if (transport->is_server)
return NULL;
else
return transport->expected_guid;
}
/**
* Handles a watch by reading data, writing data, or disconnecting
* the transport, as appropriate for the given condition.
......
......@@ -41,6 +41,7 @@ dbus_bool_t _dbus_transport_get_is_connected (DBusTransport
dbus_bool_t _dbus_transport_get_is_authenticated (DBusTransport *transport);
dbus_bool_t _dbus_transport_get_is_anonymous (DBusTransport *transport);
const char* _dbus_transport_get_address (DBusTransport *transport);
const char* _dbus_transport_get_server_id (DBusTransport *transport);
dbus_bool_t _dbus_transport_handle_watch (DBusTransport *transport,
DBusWatch *watch,
unsigned int condition);
......
......@@ -3824,6 +3824,42 @@
</para>
</sect3>
<sect3 id="bus-messages-get-id">
<title><literal>org.freedesktop.DBus.GetId</literal></title>
<para>
As a method:
<programlisting>
GetId (out STRING id)
</programlisting>
Reply arguments:
<informaltable>
<tgroup cols="3">
<thead>
<row>
<entry>Argument</entry>
<entry>Type</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>0</entry>
<entry>STRING</entry>
<entry>Unique ID identifying the bus daemon</entry>
</row>
</tbody>
</tgroup>
</informaltable>
Gets the unique ID of the bus. The unique ID here is shared among all addresses the
bus daemon is listening on (TCP, UNIX domain socket, etc.) and its format is described in
<xref linkend="uuids"/>. Each address the bus is listening on also has its own unique
ID, as described in <xref linkend="addresses"/>. The per-bus and per-address IDs are not related.
There is also a per-machine ID, described in <xref linkend="standard-interfaces-peer"/> and returned
by org.freedesktop.DBus.Peer.GetMachineId().
For a desktop session bus, the bus ID can be used as a way to uniquely identify a user's session.
</para>
</sect3>
</sect2>
</sect1>
......
## the "name-test" subdir in fact contains a bunch of tests now that need a temporary bus
## to be running to do stuff with. The directory should be renamed.
SUBDIRS=name-test
DIST_SUBDIRS=name-test
......@@ -6,9 +8,11 @@ INCLUDES=-I$(top_srcdir) $(DBUS_TEST_CFLAGS)
if DBUS_BUILD_TESTS
## break-loader removed for now
## most of these binaries are used in tests but are not themselves tests
TEST_BINARIES=test-service test-names test-shell-service shell-test spawn-test test-segfault test-exit test-sleep-forever
#enable stand alone make check test
## these are the things to run in make check (i.e. they are actual tests)
## (binaries in here must also be in TEST_BINARIES)
TESTS=shell-test
else
TEST_BINARIES=
......
......@@ -16,7 +16,7 @@ if DBUS_BUILD_TESTS
## we use noinst_PROGRAMS not check_PROGRAMS for TESTS so that we
## build even when not doing "make check"
noinst_PROGRAMS=test-names test-pending-call-dispatch test-threads-init
noinst_PROGRAMS=test-names test-pending-call-dispatch test-threads-init test-ids
test_names_SOURCES= \
test-names.c
......@@ -36,5 +36,11 @@ test_threads_init_SOURCES = \
test_threads_init_LDADD=$(top_builddir)/dbus/libdbus-convenience.la $(DBUS_TEST_LIBS)
test_threads_init_LDFLAGS=@R_DYNAMIC_LDFLAG@
test_ids_SOURCES = \
test-ids.c
test_ids_LDADD=$(top_builddir)/dbus/libdbus-convenience.la $(DBUS_TEST_LIBS)
test_ids_LDFLAGS=@R_DYNAMIC_LDFLAG@
endif
#! /bin/sh
ie()
die()
{
if ! test -z "$DBUS_SESSION_BUS_PID" ; then
echo "killing message bus "$DBUS_SESSION_BUS_PID >&2
......@@ -24,11 +24,14 @@ if test -z "$DBUS_TEST_NAME_IN_RUN_TEST"; then
export DBUS_TEST_NAME_IN_RUN_TEST
exec $DBUS_TOP_SRCDIR/tools/run-with-tmp-session-bus.sh $SCRIPTNAME $MODE
fi
echo "running test-ids"
libtool --mode=execute $DEBUG $DBUS_TOP_BUILDDIR/test/name-test/test-ids || die "test-ids failed"
echo "running test-names"
libtool --mode=execute $DEBUG $DBUS_TOP_BUILDDIR/test/name-test/test-names || die "test-client failed"
libtool --mode=execute $DEBUG $DBUS_TOP_BUILDDIR/test/name-test/test-names || die "test-names failed"
echo "running test-pending-call-dispatch"
libtool --mode=execute $DEBUG $DBUS_TOP_BUILDDIR/test/name-test/test-pending-call-dispatch || die "test-client failed"
libtool --mode=execute $DEBUG $DBUS_TOP_BUILDDIR/test/name-test/test-pending-call-dispatch || die "test-pending-call-dispatch failed"
echo "running test-threads-init"
libtool --mode=execute $DEBUG $DBUS_TOP_BUILDDIR/test/name-test/test-threads-init || die "test-client failed"
libtool --mode=execute $DEBUG $DBUS_TOP_BUILDDIR/test/name-test/test-threads-init || die "test-threads-init failed"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dbus/dbus.h>
#include <dbus/dbus-connection-internal.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
static void
die (const char *message)
{
fprintf (stderr, "*** test-ids: %s", message);
exit (1);
}
int
main (int argc,
char **argv)
{
DBusError error;
DBusConnection *connection;
char *id;
char *server_id;
dbus_error_init (&error);
connection = dbus_bus_get (DBUS_BUS_SESSION, &error);
if (connection == NULL)
{
fprintf (stderr, "*** Failed to open connection to system bus: %s\n",
error.message);
dbus_error_free (&error);
return 1;
}
server_id = dbus_connection_get_server_id (connection);
if (server_id == NULL)
die ("No bus server ID retrieved\n");
/* printf("'%s'\n", server_id); */
if (strlen (server_id) != 32)
die ("Bus server id should have length 32\n");
dbus_free (server_id);
id = dbus_bus_get_id (connection, NULL);
if (id == NULL)
die ("No bus ID retrieved\n");
/* printf("'%s'\n", id); */
if (strlen (id) != 32)
die ("Bus ID should have length 32\n");
dbus_free (id);
_dbus_verbose ("*** Test IDs exiting\n");
return 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment