hmm, make check is currently not passing.
* doc/dbus-specification.xml: add requirement that custom type
names follow the same rules as interface names.
* dbus/dbus-protocol.h: change some of the byte codes, to avoid
duplication and allow 'c' to be 'custom'; dict is now 'm' for
'map'
* doc/dbus-specification.xml: update type codes to match
dbus-protocol.h, using the ASCII byte values. Rename type NAMED to
CUSTOM. Add type OBJECT_PATH to the spec.
2003-10-17 Havoc Pennington <hp@redhat.com>
* bus/driver.c (create_unique_client_name): use "." as separator
in base service names instead of '-'
* dbus/dbus-string.c (_dbus_string_get_byte): allow getting nul
byte at the end of the string
* dbus/dbus-internals.h (_DBUS_LIKELY, _DBUS_UNLIKELY): add
optimization macros since string validation seems to be a slow
point.
* doc/dbus-specification.xml: restrict valid
service/interface/member/error names. Add test suite code for the
name validation.
* dbus/dbus-string.c: limit service/interface/member/error names
to [0-9][A-Z][a-z]_
* dbus/dbus-connection.c (dbus_connection_dispatch): add missing
format arg to verbose spew
* glib/dbus-gproxy.c (dbus_gproxy_call_no_reply): if not out of
memory, return instead of g_error
* test/test-service.c (path_message_func): support emitting a
signal on request
* dbus/dbus-bus.c (init_connections_unlocked): only fill in
activation bus type if DBUS_BUS_ACTIVATION was set; default to
assuming the activation bus was the session bus so that services
started manually will still register.
(init_connections_unlocked): fix so that in OOM situation we get
the same semantics when retrying the function
* test/test-service.c (main): change to use path registration, to
test those codepaths; register with DBUS_BUS_ACTIVATION rather
than DBUS_BUS_SESSION
+2003-10-20 Havoc Pennington <hp@redhat.com>
+
+ hmm, make check is currently not passing.
+
+ * doc/dbus-specification.xml: add requirement that custom type
+ names follow the same rules as interface names.
+
+ * dbus/dbus-protocol.h: change some of the byte codes, to avoid
+ duplication and allow 'c' to be 'custom'; dict is now 'm' for
+ 'map'
+
+ * doc/dbus-specification.xml: update type codes to match
+ dbus-protocol.h, using the ASCII byte values. Rename type NAMED to
+ CUSTOM. Add type OBJECT_PATH to the spec.
+
+2003-10-17 Havoc Pennington <hp@redhat.com>
+
+ * bus/driver.c (create_unique_client_name): use "." as separator
+ in base service names instead of '-'
+
+ * dbus/dbus-string.c (_dbus_string_get_byte): allow getting nul
+ byte at the end of the string
+
+ * dbus/dbus-internals.h (_DBUS_LIKELY, _DBUS_UNLIKELY): add
+ optimization macros since string validation seems to be a slow
+ point.
+
+ * doc/dbus-specification.xml: restrict valid
+ service/interface/member/error names. Add test suite code for the
+ name validation.
+
+ * dbus/dbus-string.c: limit service/interface/member/error names
+ to [0-9][A-Z][a-z]_
+
+ * dbus/dbus-connection.c (dbus_connection_dispatch): add missing
+ format arg to verbose spew
+
+ * glib/dbus-gproxy.c (dbus_gproxy_call_no_reply): if not out of
+ memory, return instead of g_error
+
+ * test/test-service.c (path_message_func): support emitting a
+ signal on request
+
+ * dbus/dbus-bus.c (init_connections_unlocked): only fill in
+ activation bus type if DBUS_BUS_ACTIVATION was set; default to
+ assuming the activation bus was the session bus so that services
+ started manually will still register.
+ (init_connections_unlocked): fix so that in OOM situation we get
+ the same semantics when retrying the function
+
+ * test/test-service.c (main): change to use path registration, to
+ test those codepaths; register with DBUS_BUS_ACTIVATION rather
+ than DBUS_BUS_SESSION
+
2003-10-16 Havoc Pennington <hp@redhat.com>
* glib/dbus-gtest-main.c: bracket with #ifdef DBUS_BUILD_TESTS
type = dbus_message_get_type (message);
/* dispatch.c was supposed to ensure these invariants */
+ /* FIXME this assertion is failing in make check */
_dbus_assert (dbus_message_get_destination (message) != NULL ||
type == DBUS_MESSAGE_TYPE_SIGNAL);
_dbus_assert (type == DBUS_MESSAGE_TYPE_SIGNAL ||
#endif /* DBUS_ENABLE_VERBOSE_MODE */
/* If service_name is NULL, if it's a signal we send it to all
- * connections with a match rule. If it's not a signal, it goes to
- * the bus daemon but doesn't go "on the bus"; e.g. a peer-to-peer
- * ping. Handle these immediately, especially disconnection
- * messages. There are no security policy checks on these.
+ * connections with a match rule. If it's not a signal, there
+ * are some special cases here but mostly we just bail out.
*/
if (service_name == NULL)
{
if (!_dbus_string_append_int (str, next_major_number))
return FALSE;
- if (!_dbus_string_append (str, "-"))
+ if (!_dbus_string_append (str, "."))
return FALSE;
if (!_dbus_string_append_int (str, next_minor_number))
TEST_PATH(SERVICE_DIR, data/valid-service-files)
TEST_PATH(SERVICE_BINARY, test-service)
+TEST_PATH(GLIB_SERVICE_BINARY, test-service-glib)
TEST_PATH(EXIT_BINARY, test-exit)
TEST_PATH(SEGFAULT_BINARY, test-segfault)
TEST_PATH(SLEEP_FOREVER_BINARY, test-sleep-forever)
/* 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)
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)
- {
- /* 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]);
+ 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)
{
if (!get_from_env (&bus_connection_addresses[DBUS_BUS_ACTIVATION],
"DBUS_ACTIVATION_ADDRESS"))
return FALSE;
-
+
_dbus_verbose (" \"%s\"\n", bus_connection_addresses[DBUS_BUS_ACTIVATION] ?
bus_connection_addresses[DBUS_BUS_ACTIVATION] : "none set");
}
- s = _dbus_getenv ("DBUS_ACTIVATION_BUS_TYPE");
- if (s != NULL)
+ if (bus_connection_addresses[DBUS_BUS_ACTIVATION] != 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;
+ s = _dbus_getenv ("DBUS_ACTIVATION_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_ACTIVATION] =
+ _dbus_strdup (bus_connection_addresses[DBUS_BUS_SESSION]);
+ if (bus_connection_addresses[DBUS_BUS_ACTIVATION] == NULL)
+ return FALSE;
+ }
+ }
+
/* If we return FALSE we have to be sure that restarting
* the above code will work right
*/
* the whole message queue for example) and has thread issues,
* see comments in source
*
+ * Does not re-enter the main loop or run filter/path-registered
+ * callbacks. The reply to the message will not be seen by
+ * filter callbacks.
+ *
* @param connection the connection
* @param client_serial the reply serial to wait for
* @param timeout_milliseconds timeout in milliseconds or -1 for default
* @todo some FIXME in here about handling DBUS_HANDLER_RESULT_NEED_MEMORY
*
* @todo right now a message filter gets run on replies to a pending
- * call in here, but not in the case where we block without
- * entering the main loop.
+ * call in here, but not in the case where we block without entering
+ * the main loop. Simple solution might be to just have the pending
+ * call stuff run before the filters.
+ *
+ * @todo FIXME what if we call out to application code to handle a
+ * message, holding the dispatch lock, and the application code runs
+ * the main loop and dispatches again? Probably deadlocks at the
+ * moment. Maybe we want a dispatch status of DBUS_DISPATCH_IN_PROGRESS,
+ * and then the GSource etc. could handle the situation?
*
* @param connection the connection
* @returns dispatch status
dbus_message_get_type (message),
dbus_message_get_interface (message) ?
dbus_message_get_interface (message) :
- "no interface");
+ "no interface",
+ dbus_message_get_signature (message));
result = _dbus_object_tree_dispatch_and_unlock (connection->objects,
message);
*
* @todo we don't run filters on messages while blocking without
* entering the main loop, since filters are run as part of
- * dbus_connection_dispatch().
+ * dbus_connection_dispatch(). This is probably a feature, as filters
+ * could create arbitrary reentrancy. But kind of sucks if you're
+ * trying to filter METHOD_RETURN for some reason.
*
* @param connection the connection
* @param function function to handle messages
return "double";
case DBUS_TYPE_STRING:
return "string";
- case DBUS_TYPE_NAMED:
- return "named";
+ case DBUS_TYPE_CUSTOM:
+ return "custom";
case DBUS_TYPE_ARRAY:
return "array";
case DBUS_TYPE_DICT:
const char *file,
int line)
{
- if (!condition)
+ if (_DBUS_UNLIKELY (!condition))
{
_dbus_warn ("%lu: assertion failed \"%s\" file \"%s\" line %d\n",
_dbus_getpid (), condition_text, file, line);
#define _DBUS_FUNCTION_NAME "unknown function"
#endif
+/*
+ * (code from GLib)
+ *
+ * The _DBUS_LIKELY and _DBUS_UNLIKELY macros let the programmer give hints to
+ * the compiler about the expected result of an expression. Some compilers
+ * can use this information for optimizations.
+ *
+ * The _DBUS_BOOLEAN_EXPR macro is intended to trigger a gcc warning when
+ * putting assignments in the macro arg
+ */
+#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__)
+#define _DBUS_BOOLEAN_EXPR(expr) \
+ __extension__ ({ \
+ int _dbus_boolean_var_; \
+ if (expr) \
+ _dbus_boolean_var_ = 1; \
+ else \
+ _dbus_boolean_var_ = 0; \
+ _dbus_boolean_var_; \
+})
+#define _DBUS_LIKELY(expr) (__builtin_expect (_DBUS_BOOLEAN_EXPR(expr), 1))
+#define _DBUS_UNLIKELY(expr) (__builtin_expect (_DBUS_BOOLEAN_EXPR(expr), 0))
+#else
+#define _DBUS_LIKELY(expr) (expr)
+#define _DBUS_UNLIKELY(expr) (expr)
+#endif
+
#ifdef DBUS_ENABLE_VERBOSE_MODE
# define _dbus_verbose _dbus_verbose_real
# define _dbus_verbose_reset _dbus_verbose_reset_real
}
break;
- case DBUS_TYPE_NAMED:
+ case DBUS_TYPE_CUSTOM:
{
int len;
case DBUS_TYPE_OBJECT_PATH:
case DBUS_TYPE_STRING:
- case DBUS_TYPE_NAMED:
+ case DBUS_TYPE_CUSTOM:
case DBUS_TYPE_ARRAY:
case DBUS_TYPE_DICT:
/* This clean recursion to validate_arg is what we
}
break;
- case DBUS_TYPE_NAMED:
+ case DBUS_TYPE_CUSTOM:
{
int len;
case DBUS_TYPE_UINT64:
case DBUS_TYPE_DOUBLE:
case DBUS_TYPE_STRING:
- case DBUS_TYPE_NAMED:
+ case DBUS_TYPE_CUSTOM:
case DBUS_TYPE_ARRAY:
case DBUS_TYPE_DICT:
case DBUS_TYPE_OBJECT_PATH:
code = DBUS_TYPE_STRING;
else if (_dbus_string_starts_with_c_str (&line, "OBJECT_PATH"))
code = DBUS_TYPE_OBJECT_PATH;
- else if (_dbus_string_starts_with_c_str (&line, "NAMED"))
- code = DBUS_TYPE_NAMED;
+ else if (_dbus_string_starts_with_c_str (&line, "CUSTOM"))
+ code = DBUS_TYPE_CUSTOM;
else if (_dbus_string_starts_with_c_str (&line, "ARRAY"))
code = DBUS_TYPE_ARRAY;
else if (_dbus_string_starts_with_c_str (&line, "DICT"))
case DBUS_TYPE_DOUBLE:
padding = _DBUS_ALIGN_VALUE (pos, 8) - pos;
break;
- case DBUS_TYPE_NAMED:
+ case DBUS_TYPE_CUSTOM:
case DBUS_TYPE_ARRAY:
case DBUS_TYPE_DICT:
/* FIXME This is no good; we have to handle undefined header fields
* also. SECURITY and spec compliance issue.
*/
- _dbus_assert_not_reached ("no defined header fields may contain a named, array or dict value");
+ _dbus_assert_not_reached ("no defined header fields may contain a custom, array or dict value");
break;
case DBUS_TYPE_INVALID:
default:
dbus_message_append_iter_init (message, &iter);
- while (type != 0)
+ while (type != DBUS_TYPE_INVALID)
{
switch (type)
{
case DBUS_TYPE_OBJECT_PATH:
break;
- case DBUS_TYPE_NAMED:
+ case DBUS_TYPE_CUSTOM:
{
const char *name;
unsigned char *data;
data = va_arg (var_args, unsigned char *);
len = va_arg (var_args, int);
- if (!dbus_message_iter_append_named (&iter, name, data, len))
+ if (!dbus_message_iter_append_custom (&iter, name, data, len))
goto errorout;
break;
}
break;
case DBUS_TYPE_NIL:
case DBUS_TYPE_ARRAY:
- case DBUS_TYPE_NAMED:
+ case DBUS_TYPE_CUSTOM:
case DBUS_TYPE_DICT:
_dbus_warn ("dbus_message_append_args_valist doesn't support recursive arrays\n");
goto errorout;
break;
}
- case DBUS_TYPE_NAMED:
+ case DBUS_TYPE_CUSTOM:
{
char **name;
unsigned char **data;
data = va_arg (var_args, unsigned char **);
len = va_arg (var_args, int *);
- if (!dbus_message_iter_get_named (iter, name, data, len))
+ if (!dbus_message_iter_get_custom (iter, name, data, len))
{
dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
goto out;
break;
case DBUS_TYPE_NIL:
case DBUS_TYPE_ARRAY:
- case DBUS_TYPE_NAMED:
+ case DBUS_TYPE_CUSTOM:
case DBUS_TYPE_DICT:
_dbus_warn ("dbus_message_get_args_valist doesn't support recursive arrays\n");
dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED, NULL);
#endif
/**
- * Returns the name and data from a named type that an
- * iterator may point to. Note that you need to check that
- * the iterator points to a named type before using this
- * function.
+ * Returns the name and data from a custom type that an iterator may
+ * point to. Note that you need to check that the iterator points to a
+ * custom type before using this function.
*
* @see dbus_message_iter_get_arg_type
* @param iter the message iter
- * @param name return location for the name
+ * @param name return location for the name of the custom type
* @param value return location for data
* @param len return location for length of data
* @returns TRUE if get succeed
*
*/
dbus_bool_t
-dbus_message_iter_get_named (DBusMessageIter *iter,
- char **name,
- unsigned char **value,
- int *len)
+dbus_message_iter_get_custom (DBusMessageIter *iter,
+ char **name,
+ unsigned char **value,
+ int *len)
{
DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
int type, pos;
pos = dbus_message_iter_get_data_start (real, &type);
- _dbus_assert (type == DBUS_TYPE_NAMED);
+ _dbus_assert (type == DBUS_TYPE_CUSTOM);
_name = _dbus_demarshal_string (&real->message->body, real->message->byte_order,
pos, &pos);
}
/**
- * Appends a named type data chunk to the message. A named
+ * Appends a custom type data chunk to the message. A custom
* type is simply an arbitrary UTF-8 string used as a type
* tag, plus an array of arbitrary bytes to be interpreted
* according to the type tag.
* @returns #TRUE on success
*/
dbus_bool_t
-dbus_message_iter_append_named (DBusMessageIter *iter,
- const char *name,
- const unsigned char *data,
- int len)
+dbus_message_iter_append_custom (DBusMessageIter *iter,
+ const char *name,
+ const unsigned char *data,
+ int len)
{
DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
_dbus_return_val_if_fail (dbus_message_iter_append_check (real), FALSE);
- if (!dbus_message_iter_append_type (real, DBUS_TYPE_NAMED))
+ if (!dbus_message_iter_append_type (real, DBUS_TYPE_CUSTOM))
return FALSE;
if (!_dbus_marshal_string (&real->message->body, real->message->byte_order, name))
return TRUE;
}
+/* FIXME because the service/interface/member/error names are already
+ * validated to be in the particular ASCII subset, UTF-8 validating
+ * them could be skipped as a probably-interesting optimization.
+ * The UTF-8 validation definitely shows up in profiles.
+ */
static dbus_bool_t
decode_header_data (const DBusString *data,
int header_len,
#ifdef DBUS_BUILD_TESTS
#include "dbus-test.h"
#include <stdio.h>
+#include <stdlib.h>
static void
message_iter_test (DBusMessage *message)
if (!dbus_message_iter_next (&iter))
_dbus_assert_not_reached ("Reached end of arguments");
- if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_NAMED)
+ if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_CUSTOM)
_dbus_assert_not_reached ("wrong type after dict");
- if (!dbus_message_iter_get_named (&iter, &str, &data, &len))
- _dbus_assert_not_reached ("failed to get named");
+ if (!dbus_message_iter_get_custom (&iter, &str, &data, &len))
+ _dbus_assert_not_reached ("failed to get custom type");
- _dbus_assert (strcmp (str, "named")==0);
+ _dbus_assert (strcmp (str, "MyTypeName")==0);
_dbus_assert (len == 5);
_dbus_assert (strcmp (data, "data")==0);
dbus_free (str);
dbus_free (str);
}
break;
- case DBUS_TYPE_NAMED:
+ case DBUS_TYPE_CUSTOM:
{
char *name;
unsigned char *data;
int len;
- if (!dbus_message_iter_get_named (iter, &name, &data, &len))
+ if (!dbus_message_iter_get_custom (iter, &name, &data, &len))
{
- _dbus_warn ("error reading name from named type\n");
+ _dbus_warn ("error reading name from custom type\n");
return FALSE;
}
dbus_free (data);
dbus_message_iter_append_nil (&iter);
- dbus_message_iter_append_named (&iter, "named",
- "data", 5);
+ dbus_message_iter_append_custom (&iter, "MyTypeName",
+ "data", 5);
message_iter_test (message);
/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-message.h DBusMessage object
*
- * Copyright (C) 2002 Red Hat Inc.
+ * Copyright (C) 2002, 2003 Red Hat Inc.
*
* Licensed under the Academic Free License version 1.2
*
char * dbus_message_iter_get_string (DBusMessageIter *iter);
char * dbus_message_iter_get_object_path (DBusMessageIter *iter);
char * dbus_message_iter_get_dict_key (DBusMessageIter *iter);
-dbus_bool_t dbus_message_iter_get_named (DBusMessageIter *iter,
+dbus_bool_t dbus_message_iter_get_custom (DBusMessageIter *iter,
char **name,
unsigned char **value,
int *len);
double value);
dbus_bool_t dbus_message_iter_append_string (DBusMessageIter *iter,
const char *value);
-dbus_bool_t dbus_message_iter_append_named (DBusMessageIter *iter,
+dbus_bool_t dbus_message_iter_append_custom (DBusMessageIter *iter,
const char *name,
const unsigned char *data,
int len);
#define DBUS_TYPE_UINT64 ((int) 't')
#define DBUS_TYPE_DOUBLE ((int) 'd')
#define DBUS_TYPE_STRING ((int) 's')
-#define DBUS_TYPE_NAMED ((int) 'n')
+#define DBUS_TYPE_CUSTOM ((int) 'c')
#define DBUS_TYPE_ARRAY ((int) 'a')
-#define DBUS_TYPE_DICT ((int) 'c')
+#define DBUS_TYPE_DICT ((int) 'm')
#define DBUS_TYPE_OBJECT_PATH ((int) 'o')
#define DBUS_NUMBER_OF_TYPES (13)
}
/**
- * Gets the byte at the given position.
+ * Gets the byte at the given position. It is
+ * allowed to ask for the nul byte at the end of
+ * the string.
*
* @param str the string
* @param start the position
int start)
{
DBUS_CONST_STRING_PREAMBLE (str);
- _dbus_assert (start < real->len);
+ _dbus_assert (start <= real->len);
_dbus_assert (start >= 0);
return real->str[start];
end = s + len;
while (s != end)
{
- if (*s == '\0' ||
- ((*s & ~0x7f) != 0))
+ if (_DBUS_UNLIKELY (*s == '\0' ||
+ ((*s & ~0x7f) != 0)))
return FALSE;
++s;
_dbus_assert (start <= real->len);
_dbus_assert (len >= 0);
- if (len > real->len - start)
+ /* we are doing _DBUS_UNLIKELY() here which might be
+ * dubious in a generic library like GLib, but in D-BUS
+ * we know we're validating messages and that it would
+ * only be evil/broken apps that would have invalid
+ * UTF-8. Also, this function seems to be a performance
+ * bottleneck in profiles.
+ */
+
+ if (_DBUS_UNLIKELY (len > real->len - start))
return FALSE;
p = real->str + start;
UTF8_COMPUTE (c, mask, char_len);
- if (char_len == -1)
+ if (_DBUS_UNLIKELY (char_len == -1))
break;
/* check that the expected number of bytes exists in the remaining length */
- if ((end - p) < char_len)
+ if (_DBUS_UNLIKELY ((end - p) < char_len))
break;
UTF8_GET (result, p, i, mask, char_len);
- if (UTF8_LENGTH (result) != char_len) /* Check for overlong UTF-8 */
+ if (_DBUS_UNLIKELY (UTF8_LENGTH (result) != char_len)) /* Check for overlong UTF-8 */
break;
- if (result == (dbus_unichar_t)-1)
+ if (_DBUS_UNLIKELY (result == (dbus_unichar_t)-1))
break;
- if (!UNICODE_VALID (result))
+ if (_DBUS_UNLIKELY (!UNICODE_VALID (result)))
break;
p += char_len;
/* See that we covered the entire length if a length was
* passed in
*/
- if (p != end)
+ if (_DBUS_UNLIKELY (p != end))
return FALSE;
else
return TRUE;
end = s + len;
while (s != end)
{
- if (*s != '\0')
+ if (_DBUS_UNLIKELY (*s != '\0'))
return FALSE;
++s;
}
return TRUE;
}
+#define VALID_INITIAL_NAME_CHARACTER(c) \
+ ( ((c) >= 'A' && (c) <= 'Z') || \
+ ((c) >= 'a' && (c) <= 'z') || \
+ ((c) == '_') )
+
+#define VALID_NAME_CHARACTER(c) \
+ ( ((c) >= '0' && (c) <= '9') || \
+ ((c) >= 'A' && (c) <= 'Z') || \
+ ((c) >= 'a' && (c) <= 'z') || \
+ ((c) == '_') )
+
/**
* Checks that the given range of the string is a valid interface name
- * in the D-BUS protocol. This includes a length restriction, etc.,
- * see the specification. It does not validate UTF-8, that has to be
- * done separately for now.
+ * in the D-BUS protocol. This includes a length restriction and an
+ * ASCII subset, see the specification.
*
* @todo this is inconsistent with most of DBusString in that
* it allows a start,len range that isn't in the string.
- *
- * @todo change spec to disallow more things, such as spaces in the
- * interface name
*
* @param str the string
* @param start first byte index to check
_dbus_string_validate_interface (const DBusString *str,
int start,
int len)
-{
+{
const unsigned char *s;
const unsigned char *end;
- dbus_bool_t saw_dot;
+ const unsigned char *iface;
+ const unsigned char *last_dot;
DBUS_CONST_STRING_PREAMBLE (str);
_dbus_assert (start >= 0);
if (len == 0)
return FALSE;
- saw_dot = FALSE;
- s = real->str + start;
- end = s + len;
+ last_dot = NULL;
+ iface = real->str + start;
+ end = iface + len;
+ s = iface;
+
+ /* check special cases of first char so it doesn't have to be done
+ * in the loop. Note we know len > 0
+ */
+ if (_DBUS_UNLIKELY (*s == '.')) /* disallow starting with a . */
+ return FALSE;
+ else if (_DBUS_UNLIKELY (!VALID_INITIAL_NAME_CHARACTER (*s)))
+ return FALSE;
+ else
+ ++s;
+
while (s != end)
{
if (*s == '.')
{
- saw_dot = TRUE;
- break;
+ if (_DBUS_UNLIKELY ((s + 1) == end))
+ return FALSE;
+ else if (_DBUS_UNLIKELY (!VALID_INITIAL_NAME_CHARACTER (*(s + 1))))
+ return FALSE;
+ last_dot = s;
+ ++s; /* we just validated the next char, so skip two */
+ }
+ else if (_DBUS_UNLIKELY (!VALID_NAME_CHARACTER (*s)))
+ {
+ return FALSE;
}
++s;
}
- if (!saw_dot)
+ if (_DBUS_UNLIKELY (last_dot == NULL))
return FALSE;
return TRUE;
/**
* Checks that the given range of the string is a valid member name
* in the D-BUS protocol. This includes a length restriction, etc.,
- * see the specification. It does not validate UTF-8, that has to be
- * done separately for now.
+ * see the specification.
*
* @todo this is inconsistent with most of DBusString in that
* it allows a start,len range that isn't in the string.
*
- * @todo change spec to disallow more things, such as spaces in the
- * member name
- *
* @param str the string
* @param start first byte index to check
* @param len number of bytes to check
{
const unsigned char *s;
const unsigned char *end;
- dbus_bool_t saw_dot;
+ const unsigned char *member;
DBUS_CONST_STRING_PREAMBLE (str);
_dbus_assert (start >= 0);
if (len == 0)
return FALSE;
- saw_dot = FALSE;
- s = real->str + start;
- end = s + len;
+ member = real->str + start;
+ end = member + len;
+ s = member;
+
+ /* check special cases of first char so it doesn't have to be done
+ * in the loop. Note we know len > 0
+ */
+
+ if (_DBUS_UNLIKELY (!VALID_INITIAL_NAME_CHARACTER (*s)))
+ return FALSE;
+ else
+ ++s;
+
while (s != end)
{
- if (*s == '.')
+ if (_DBUS_UNLIKELY (!VALID_NAME_CHARACTER (*s)))
{
- saw_dot = TRUE;
- break;
+ return FALSE;
}
++s;
}
-
- /* No dot allowed in member names */
- if (saw_dot)
- return FALSE;
return TRUE;
}
/**
* Checks that the given range of the string is a valid error name
* in the D-BUS protocol. This includes a length restriction, etc.,
- * see the specification. It does not validate UTF-8, that has to be
- * done separately for now.
+ * see the specification.
*
* @todo this is inconsistent with most of DBusString in that
* it allows a start,len range that isn't in the string.
return _dbus_string_validate_interface (str, start, len);
}
-/**
- * Checks that the given range of the string is a valid service name
- * in the D-BUS protocol. This includes a length restriction, etc.,
- * see the specification. It does not validate UTF-8, that has to be
- * done separately for now.
- *
- * @todo this is inconsistent with most of DBusString in that
- * it allows a start,len range that isn't in the string.
- *
- * @todo change spec to disallow more things, such as spaces in the
- * service name
- *
- * @param str the string
- * @param start first byte index to check
- * @param len number of bytes to check
- * @returns #TRUE if the byte range exists and is a valid name
- */
-dbus_bool_t
-_dbus_string_validate_service (const DBusString *str,
- int start,
- int len)
+/* This assumes the first char exists and is ':' */
+static dbus_bool_t
+_dbus_string_validate_base_service (const DBusString *str,
+ int start,
+ int len)
{
const unsigned char *s;
const unsigned char *end;
- dbus_bool_t saw_dot;
- dbus_bool_t is_base_service;
+ const unsigned char *service;
DBUS_CONST_STRING_PREAMBLE (str);
_dbus_assert (start >= 0);
if (len > DBUS_MAXIMUM_NAME_LENGTH)
return FALSE;
- if (len == 0)
- return FALSE;
+ _dbus_assert (len > 0);
- is_base_service = _dbus_string_get_byte (str, start) == ':';
- if (is_base_service)
- return TRUE; /* can have any content */
-
- /* non-base-service must have the '.' indicating a namespace */
+ service = real->str + start;
+ end = service + len;
+ _dbus_assert (*service == ':');
+ s = service + 1;
- saw_dot = FALSE;
- s = real->str + start;
- end = s + len;
while (s != end)
{
if (*s == '.')
{
- saw_dot = TRUE;
- break;
+ if (_DBUS_UNLIKELY ((s + 1) == end))
+ return FALSE;
+ if (_DBUS_UNLIKELY (!VALID_NAME_CHARACTER (*(s + 1))))
+ return FALSE;
+ ++s; /* we just validated the next char, so skip two */
+ }
+ else if (_DBUS_UNLIKELY (!VALID_NAME_CHARACTER (*s)))
+ {
+ return FALSE;
}
++s;
}
- return saw_dot;
+ return TRUE;
+}
+
+/**
+ * Checks that the given range of the string is a valid service name
+ * in the D-BUS protocol. This includes a length restriction, etc.,
+ * see the specification.
+ *
+ * @todo this is inconsistent with most of DBusString in that
+ * it allows a start,len range that isn't in the string.
+ *
+ * @param str the string
+ * @param start first byte index to check
+ * @param len number of bytes to check
+ * @returns #TRUE if the byte range exists and is a valid name
+ */
+dbus_bool_t
+_dbus_string_validate_service (const DBusString *str,
+ int start,
+ int len)
+{
+ if (_DBUS_UNLIKELY (len == 0))
+ return FALSE;
+ if (_dbus_string_get_byte (str, start) == ':')
+ return _dbus_string_validate_base_service (str, start, len);
+ else
+ return _dbus_string_validate_interface (str, start, len);
}
/**
"//",
"///",
"foo///blah/",
- "Hello World"
+ "Hello World",
+ "",
+ " ",
+ "foo bar"
+ };
+
+ const char *valid_interfaces[] = {
+ "org.freedesktop.Foo",
+ "Bar.Baz",
+ "Blah.Blah.Blah.Blah.Blah",
+ "a.b",
+ "a.b.c.d.e.f.g",
+ "a0.b1.c2.d3.e4.f5.g6",
+ "abc123.foo27"
+ };
+ const char *invalid_interfaces[] = {
+ ".",
+ "",
+ "..",
+ ".Foo.Bar",
+ "..Foo.Bar",
+ "Foo.Bar.",
+ "Foo.Bar..",
+ "Foo",
+ "9foo.bar.baz",
+ "foo.bar..baz",
+ "foo.bar...baz",
+ "foo.bar.b..blah",
+ ":",
+ ":0-1",
+ "10",
+ ":11.34324",
+ "0.0.0",
+ "0..0",
+ "foo.Bar.%",
+ "foo.Bar!!",
+ "!Foo.bar.bz",
+ "foo.$.blah",
+ "",
+ " ",
+ "foo bar"
+ };
+
+ const char *valid_base_services[] = {
+ ":0",
+ ":a",
+ ":",
+ ":.a",
+ ":.1",
+ ":0.1",
+ ":000.2222",
+ ":.blah",
+ ":abce.freedesktop.blah"
+ };
+ const char *invalid_base_services[] = {
+ ":-",
+ ":!",
+ ":0-10",
+ ":blah.",
+ ":blah.",
+ ":blah..org",
+ ":blah.org..",
+ ":..blah.org",
+ "",
+ " ",
+ "foo bar"
+ };
+
+ const char *valid_members[] = {
+ "Hello",
+ "Bar",
+ "foobar",
+ "_foobar",
+ "foo89"
+ };
+
+ const char *invalid_members[] = {
+ "9Hello",
+ "10",
+ "1",
+ "foo-bar",
+ "blah.org",
+ ".blah",
+ "blah.",
+ "Hello.",
+ "!foo",
+ "",
+ " ",
+ "foo bar"
};
i = 0;
++i;
}
-
+
+ /* Interface validation */
+ i = 0;
+ while (i < (int) _DBUS_N_ELEMENTS (valid_interfaces))
+ {
+ _dbus_string_init_const (&str, valid_interfaces[i]);
+
+ if (!_dbus_string_validate_interface (&str, 0,
+ _dbus_string_get_length (&str)))
+ {
+ _dbus_warn ("Interface \"%s\" should have been valid\n", valid_interfaces[i]);
+ _dbus_assert_not_reached ("invalid interface");
+ }
+
+ ++i;
+ }
+
+ i = 0;
+ while (i < (int) _DBUS_N_ELEMENTS (invalid_interfaces))
+ {
+ _dbus_string_init_const (&str, invalid_interfaces[i]);
+
+ if (_dbus_string_validate_interface (&str, 0,
+ _dbus_string_get_length (&str)))
+ {
+ _dbus_warn ("Interface \"%s\" should have been invalid\n", invalid_interfaces[i]);
+ _dbus_assert_not_reached ("valid interface");
+ }
+
+ ++i;
+ }
+
+ /* Service validation (check that valid interfaces are valid services,
+ * and invalid interfaces are invalid services except if they start with ':')
+ */
+ i = 0;
+ while (i < (int) _DBUS_N_ELEMENTS (valid_interfaces))
+ {
+ _dbus_string_init_const (&str, valid_interfaces[i]);
+
+ if (!_dbus_string_validate_service (&str, 0,
+ _dbus_string_get_length (&str)))
+ {
+ _dbus_warn ("Service \"%s\" should have been valid\n", valid_interfaces[i]);
+ _dbus_assert_not_reached ("invalid service");
+ }
+
+ ++i;
+ }
+
+ i = 0;
+ while (i < (int) _DBUS_N_ELEMENTS (invalid_interfaces))
+ {
+ if (invalid_interfaces[i][0] != ':')
+ {
+ _dbus_string_init_const (&str, invalid_interfaces[i]);
+
+ if (_dbus_string_validate_service (&str, 0,
+ _dbus_string_get_length (&str)))
+ {
+ _dbus_warn ("Service \"%s\" should have been invalid\n", invalid_interfaces[i]);
+ _dbus_assert_not_reached ("valid service");
+ }
+ }
+
+ ++i;
+ }
+
+ /* Base service validation */
+ i = 0;
+ while (i < (int) _DBUS_N_ELEMENTS (valid_base_services))
+ {
+ _dbus_string_init_const (&str, valid_base_services[i]);
+
+ if (!_dbus_string_validate_service (&str, 0,
+ _dbus_string_get_length (&str)))
+ {
+ _dbus_warn ("Service \"%s\" should have been valid\n", valid_base_services[i]);
+ _dbus_assert_not_reached ("invalid base service");
+ }
+
+ ++i;
+ }
+
+ i = 0;
+ while (i < (int) _DBUS_N_ELEMENTS (invalid_base_services))
+ {
+ _dbus_string_init_const (&str, invalid_base_services[i]);
+
+ if (_dbus_string_validate_service (&str, 0,
+ _dbus_string_get_length (&str)))
+ {
+ _dbus_warn ("Service \"%s\" should have been invalid\n", invalid_base_services[i]);
+ _dbus_assert_not_reached ("valid base service");
+ }
+
+ ++i;
+ }
+
+
+ /* Error name validation (currently identical to interfaces)
+ */
+ i = 0;
+ while (i < (int) _DBUS_N_ELEMENTS (valid_interfaces))
+ {
+ _dbus_string_init_const (&str, valid_interfaces[i]);
+
+ if (!_dbus_string_validate_error_name (&str, 0,
+ _dbus_string_get_length (&str)))
+ {
+ _dbus_warn ("Error name \"%s\" should have been valid\n", valid_interfaces[i]);
+ _dbus_assert_not_reached ("invalid error name");
+ }
+
+ ++i;
+ }
+
+ i = 0;
+ while (i < (int) _DBUS_N_ELEMENTS (invalid_interfaces))
+ {
+ if (invalid_interfaces[i][0] != ':')
+ {
+ _dbus_string_init_const (&str, invalid_interfaces[i]);
+
+ if (_dbus_string_validate_error_name (&str, 0,
+ _dbus_string_get_length (&str)))
+ {
+ _dbus_warn ("Error name \"%s\" should have been invalid\n", invalid_interfaces[i]);
+ _dbus_assert_not_reached ("valid error name");
+ }
+ }
+
+ ++i;
+ }
+
+ /* Member validation */
+ i = 0;
+ while (i < (int) _DBUS_N_ELEMENTS (valid_members))
+ {
+ _dbus_string_init_const (&str, valid_members[i]);
+
+ if (!_dbus_string_validate_member (&str, 0,
+ _dbus_string_get_length (&str)))
+ {
+ _dbus_warn ("Member \"%s\" should have been valid\n", valid_members[i]);
+ _dbus_assert_not_reached ("invalid member");
+ }
+
+ ++i;
+ }
+
+ i = 0;
+ while (i < (int) _DBUS_N_ELEMENTS (invalid_members))
+ {
+ _dbus_string_init_const (&str, invalid_members[i]);
+
+ if (_dbus_string_validate_member (&str, 0,
+ _dbus_string_get_length (&str)))
+ {
+ _dbus_warn ("Member \"%s\" should have been invalid\n", invalid_members[i]);
+ _dbus_assert_not_reached ("valid member");
+ }
+
+ ++i;
+ }
+
+ /* Validate claimed length longer than real length */
+ _dbus_string_init_const (&str, "abc.efg");
+ if (_dbus_string_validate_service (&str, 0, 8))
+ _dbus_assert_not_reached ("validated too-long string");
+ if (_dbus_string_validate_interface (&str, 0, 8))
+ _dbus_assert_not_reached ("validated too-long string");
+ if (_dbus_string_validate_error_name (&str, 0, 8))
+ _dbus_assert_not_reached ("validated too-long string");
+
+ _dbus_string_init_const (&str, "abc");
+ if (_dbus_string_validate_member (&str, 0, 4))
+ _dbus_assert_not_reached ("validated too-long string");
+
+ /* Validate string exceeding max name length */
+ if (!_dbus_string_init (&str))
+ _dbus_assert_not_reached ("no memory");
+
+ while (_dbus_string_get_length (&str) <= DBUS_MAXIMUM_NAME_LENGTH)
+ if (!_dbus_string_append (&str, "abc.def"))
+ _dbus_assert_not_reached ("no memory");
+
+ if (_dbus_string_validate_service (&str, 0, _dbus_string_get_length (&str)))
+ _dbus_assert_not_reached ("validated overmax string");
+ if (_dbus_string_validate_interface (&str, 0, _dbus_string_get_length (&str)))
+ _dbus_assert_not_reached ("validated overmax string");
+ if (_dbus_string_validate_error_name (&str, 0, _dbus_string_get_length (&str)))
+ _dbus_assert_not_reached ("validated overmax string");
+
+ /* overlong member */
+ _dbus_string_set_length (&str, 0);
+ while (_dbus_string_get_length (&str) <= DBUS_MAXIMUM_NAME_LENGTH)
+ if (!_dbus_string_append (&str, "abc"))
+ _dbus_assert_not_reached ("no memory");
+
+ if (_dbus_string_validate_member (&str, 0, _dbus_string_get_length (&str)))
+ _dbus_assert_not_reached ("validated overmax string");
+
+ /* overlong base service */
+ _dbus_string_set_length (&str, 0);
+ _dbus_string_append (&str, ":");
+ while (_dbus_string_get_length (&str) <= DBUS_MAXIMUM_NAME_LENGTH)
+ if (!_dbus_string_append (&str, "abc"))
+ _dbus_assert_not_reached ("no memory");
+
+ if (_dbus_string_validate_service (&str, 0, _dbus_string_get_length (&str)))
+ _dbus_assert_not_reached ("validated overmax string");
+
+ _dbus_string_free (&str);
+
return TRUE;
}
/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-string.h String utility class (internal to D-BUS implementation)
*
- * Copyright (C) 2002 Red Hat, Inc.
+ * Copyright (C) 2002, 2003 Red Hat, Inc.
*
* Licensed under the Academic Free License version 1.2
*
which of these functions to include, in light of the fact that
GLib/Qt native stubs will probably also exist.
- - The message handler interface needs rethinking, perhaps handlers should be able
- to return an error that automatically gets turned into a message; most likely
- some basic spec'ing out of the GLib/Qt level stubs/skels stuff will be
- needed to understand the right approach.
-
- assorted _-prefixed symbols in libdbus aren't actually used by
libdbus, only by the message bus. These bloat up the library
size. Not sure how to fix, really.
- - if you send a message to a service then block for reply, and the service exits/crashes
- after the message bus has processed your message but before the service has replied,
- it would be nice if the message bus sent you an error reply.
-
- build and install the Doxygen manual in Makefile when --enable-docs
- if you send the same message to multiple connections, the serial number
- add dbus_message_has_path(), maybe has_member/interface
- - The OBJECT_PATH type is not documented in the spec.
-
- re_align_field_recurse() in dbus-message.c is broken because it
crashes on some types of header field values. security problem.
be coded to handle it restarting
- modify the wire protocol to keep the args signature separate
- from the args themselves. Make the name of TYPE_NAMED part
+ from the args themselves. Make the name of TYPE_CUSTOM part
of the type signature, rather than part of the value.
Then you have the full typecheck in a single string.
- - rename TYPE_NAMED to TYPE_CUSTOM, probably a clearer name.
-
- dbus_message_iter_init_array_iterator has "iter" and "iterator"
in the same function name
- the GLib bindings varargs take DBUS_TYPE_WHATEVER and
return stuff allocated with dbus_malloc(); should this
be made more "G" at some expense in code duplication?
+ You also still have to use some D-BUS functions such as
+ dbus_message_get_args() which takes a DBusError.
+ Probably we need to either fully encapsulate and hide
+ dbus/dbus.h, or encapsulate it slightly less e.g. no
+ GError.
- need to define bus behavior if you send a message to
yourself; is it an error, or allowed? If allowed,
- the varargs dbus_message_get_args() needs to support OBJECT_PATH
and OBJECT_PATH_ARRAY
+
+ - recursive dispatch, see dbus_connection_dispatch()
+
+ - the auth protocol may as well use hex encoding instead of
+ base64, then we can dump the base64 implementation and
+ save some bloat.
<row>
<entry>PATH</entry>
<entry>1</entry>
- <entry>STRING</entry>
+ <entry>OBJECT_PATH</entry>
<entry>The object to send the message to; objects are identified by
a path, "/foo/bar"</entry>
</row>
<tbody>
<row>
<entry>INVALID</entry>
- <entry>0</entry>
+ <entry>0 (ASCII NUL)</entry>
<entry>Not a valid type code (error if it appears in a message)</entry>
</row><row>
<entry>NIL</entry>
- <entry>1</entry>
- <entry>Marks an "unset" or "nonexistent" argument</entry>
+ <entry>118 (ASCII 'v') </entry>
+ <entry>Marks a "void"/"unset"/"nonexistent"/"null" argument</entry>
</row><row>
<entry>BYTE</entry>
- <entry>2</entry>
+ <entry>121 (ASCII 'y')</entry>
<entry>8-bit unsigned integer</entry>
</row><row>
<entry>BOOLEAN</entry>
- <entry>3</entry>
+ <entry>98 (ASCII 'b')</entry>
<entry>Boolean value, 0 is FALSE and 1 is TRUE. Everything else is invalid.</entry>
</row><row>
<entry>INT32</entry>
- <entry>4</entry>
+ <entry>105 (ASCII 'i')</entry>
<entry>32-bit signed integer</entry>
</row><row>
<entry>UINT32</entry>
- <entry>5</entry>
+ <entry>117 (ASCII 'u')</entry>
<entry>32-bit unsigned integer</entry>
</row><row>
<entry>INT64</entry>
- <entry>6</entry>
+ <entry>120 (ASCII 'x')</entry>
<entry>64-bit signed integer</entry>
</row><row>
<entry>UINT64</entry>
- <entry>7</entry>
+ <entry>116 (ASCII 't')</entry>
<entry>64-bit unsigned integer</entry>
</row><row>
<entry>DOUBLE</entry>
- <entry>8</entry>
+ <entry>100 (ASCII 'd')</entry>
<entry>IEEE 754 double</entry>
</row><row>
<entry>STRING</entry>
- <entry>9</entry>
+ <entry>115 (ASCII 's')</entry>
<entry>UTF-8 string (<emphasis>must</emphasis> be valid UTF-8). Must be zero terminated. </entry>
</row><row>
- <entry>NAMED</entry>
- <entry>10</entry>
+ <entry>CUSTOM</entry>
+ <entry>99 (ASCII 'c')</entry>
<entry>A named byte array, used for custom types</entry>
</row><row>
<entry>ARRAY</entry>
- <entry>11</entry>
+ <entry>97 (ASCII 'a')</entry>
<entry>Array</entry>
</row><row>
<entry>DICT</entry>
- <entry>12</entry>
+ <entry>109 (ASCII 'm')</entry>
<entry>A dictionary of key/value pairs</entry>
+ </row><row>
+ <entry>OBJECT_PATH</entry>
+ <entry>111 (ASCII 'o')</entry>
+ <entry>Name of an object</entry>
</row>
</tbody>
</tgroup>
byte.
</entry>
</row><row>
- <entry>NAMED</entry>
+ <entry>CUSTOM</entry>
<entry>A string (encoded as the STRING type above) giving the
name of the type followed by an UINT32 aligned to 4-byte boundary
indicating the data length in bytes, followed by the data.
+ The string has some restrictions on its content, see
+ <xref linkend="message-protocol-names"/>.
</entry>
</row><row>
<entry>ARRAY</entry>
as a byte with typecode and how that type normally would be encoded
alone.
</entry>
+ </row><row>
+ <entry>OBJECT_PATH</entry>
+ <entry>Encoded as if it were a STRING.
+ </entry>
</row>
</tbody>
</tgroup>
<sect2 id="message-protocol-names">
<title>Valid names</title>
<para>
- The various header fields of type STRING have some restrictions
- on the string's format.
+ The various names in D-BUS messages have some restrictions.
</para>
- <sect3 id="message-protocol-names-service">
- <title>Service names</title>
+ <sect3 id="message-protocol-names-interface">
+ <title>Interface names</title>
<para>
- Services have names with type STRING, meaning that
+ Interfaces have names with type STRING, meaning that
they must be valid UTF-8. However, there are also some
- additional restrictions that apply to service names
+ additional restrictions that apply to interface names
specifically:
<itemizedlist>
- <listitem><para>They must contain at least one '.' (period) character</para></listitem>
- <listitem><para>They must not begin with a '.' (period) character</para></listitem>
- <listitem><para>They must not exceed 256 bytes in length</para></listitem>
- <listitem><para>They must be at least 1 byte in length</para></listitem>
+ <listitem><para>They are composed of 1 or more elements separated by
+ a period ('.') character. All elements must contain at least
+ one character.
+ </para>
+ </listitem>
+ <listitem><para>Each element must only contain the ASCII characters
+ "[A-Z][a-z][0-9]_" and must not begin with a digit.
+ </para>
+ </listitem>
+
+ <listitem><para>They must contain at least one '.' (period)
+ character (and thus at least two elements).
+ </para></listitem>
+
+ <listitem><para>They must not begin with a '.' (period) character.</para></listitem>
+ <listitem><para>They must not exceed 256 bytes in length.</para></listitem>
+ <listitem><para>They must be at least 1 byte in length.</para></listitem>
</itemizedlist>
-
- As a special exception, base service names (those beginning with a colon
- (':') character) need not contain a period.
- </para>
- <para>
- FIXME really, shouldn't we ban basically everything non-alphanumeric
- so the name will work in all programming languages?
</para>
</sect3>
- <sect3 id="message-protocol-names-interface">
- <title>Interface names</title>
- <para>
- Interface names have the same restrictions as service names,
- but do not have the special exception for names beginning with
- a colon.
- </para>
+ <sect3 id="message-protocol-names-service">
+ <title>Service names</title>
<para>
- FIXME really, shouldn't we ban basically everything non-alphanumeric
- so the name will work in all programming languages?
+ Service names have the same restrictions as interface names, with a
+ special exception for base services. A base service name's first
+ element must start with a colon (':') character. After the colon, any
+ characters in the range "[A-Z][a-z][0-9]_" may appear. Elements after
+ the first must follow the usual rules, except that they may start with
+ a digit. Service names not starting with a colon have none of these
+ exceptions and follow the same rules as interface names.
</para>
</sect3>
<sect3 id="message-protocol-names-method">
<para>
Method names:
<itemizedlist>
- <listitem><para>May not contain the '.' (period) character</para></listitem>
+ <listitem><para>Must only contain the ASCII characters
+ "[A-Z][a-z][0-9]_" and may not begin with a
+ digit.</para></listitem>
+ <listitem><para>Must not contain the '.' (period) character</para></listitem>
<listitem><para>Must not exceed 256 bytes in length</para></listitem>
<listitem><para>Must be at least 1 byte in length</para></listitem>
</itemizedlist>
</para>
- <para>
- FIXME really, shouldn't we ban basically everything non-alphanumeric
- so the name will work in all programming languages?
- </para>
</sect3>
<sect3 id="message-protocol-names-path">
<title>Path names</title>
<para>
- A path must begin with an ASCII '/' (slash) character. Paths may not
- end with a slash character unless the path is the one-byte string
- "/". Two slash characters may not appear adjacent to one another (the
- empty string is not a valid "subdirectory"). Paths may not exceed
- 256 bytes in length.
+ A path (type OBJECT_PATH) must begin with an ASCII '/' (slash)
+ character. Paths may not end with a slash character unless the path is
+ the one-byte string "/". Two slash characters may not appear adjacent
+ to one another (the empty string is not a valid "subdirectory"). Paths
+ may not exceed 256 bytes in length.
</para>
</sect3>
<sect3 id="message-protocol-names-error">
<para>
Error names have the same restrictions as interface names.
</para>
+ </sect3>
+ <sect3 id="message-protocol-names-custom">
+ <title>Custom types</title>
<para>
- FIXME really, shouldn't we ban basically everything non-alphanumeric
- so the name will work in all programming languages?
+ Custom type names for values of type CUSTOM follow the same
+ restrictions as interface names.
</para>
</sect3>
</sect2>
return "double";
case DBUS_TYPE_STRING:
return "string";
- case DBUS_TYPE_NAMED:
- return "named";
+ case DBUS_TYPE_CUSTOM:
+ return "custom";
case DBUS_TYPE_ARRAY:
return "array";
case DBUS_TYPE_DICT:
static char*
gproxy_get_match_rule (DBusGProxy *proxy)
{
- /* FIXME Some sort of escaping is required here I think */
+ /* FIXME Escaping is required here */
if (proxy->service)
return g_strdup_printf ("type='signal',sender='%s',path='%s',interface='%s'",
else
list = NULL;
+#if 0
+ g_print ("proxy got %s,%s,%s = list %p\n",
+ tri,
+ tri + strlen (tri) + 1,
+ tri + strlen (tri) + 1 + strlen (tri + strlen (tri) + 1) + 1,
+ list);
+#endif
+
g_free (tri);
/* Emit the signal */
NULL))
goto oom;
+ return;
+
oom:
g_error ("Out of memory");
}
DBUS_TYPE_UINT64,
DBUS_TYPE_DOUBLE,
DBUS_TYPE_STRING,
- DBUS_TYPE_NAMED,
+ DBUS_TYPE_CUSTOM,
DBUS_TYPE_ARRAY,
DBUS_TYPE_DICT,
DBUS_TYPE_OBJECT_PATH
TYPE ARRAY
TYPE STRING
STRING_ARRAY { 'Hello', 'This', 'Is', 'A', 'String', 'Array!' }
-TYPE NAMED
+TYPE CUSTOM
STRING 'named type'
BYTE_ARRAY { 'b', 'i', 'n', 'a', 'r', 'y', 'd', 'a', 't', 'a' }
--- /dev/null
+[D-BUS Service]
+Name=org.freedesktop.DBus.TestSuiteGLibService
+Exec=@TEST_GLIB_SERVICE_BINARY@
## we use noinst_PROGRAMS not check_PROGRAMS for TESTS so that we
## build even when not doing "make check"
-noinst_PROGRAMS= test-dbus-glib $(THREAD_APPS)
+noinst_PROGRAMS= test-dbus-glib test-service-glib $(THREAD_APPS)
test_dbus_glib_SOURCES= \
test-dbus-glib.c
test_dbus_glib_LDADD= $(top_builddir)/glib/libdbus-glib-1.la
+test_service_glib_SOURCES= \
+ test-service-glib.c
+
+test_service_glib_LDADD= $(top_builddir)/glib/libdbus-glib-1.la
+
else
### not building tests
function die()
{
if ! test -z "$DBUS_SESSION_BUS_PID" ; then
+ echo "killing message bus"
kill -9 $DBUS_SESSION_BUS_PID
fi
echo $SCRIPTNAME: $* >&2
echo "Started test bus pid $DBUS_SESSION_BUS_PID at $DBUS_SESSION_BUS_ADDRESS"
-$DBUS_TOP_BUILDDIR/test/glib/test-dbus-glib || die "test-dbus-glib failed"
+$DEBUG $DBUS_TOP_BUILDDIR/test/glib/test-dbus-glib || die "test-dbus-glib failed"
## we kill -TERM so gcov data can be written out
#include <stdlib.h>
#include <string.h>
+static GMainLoop *loop = NULL;
+static int n_times_foo_received = 0;
+
+static void
+foo_signal_handler (DBusGProxy *proxy,
+ DBusMessage *signal,
+ void *user_data)
+{
+ double d;
+ DBusError derror;
+
+ if (!dbus_message_is_signal (signal,
+ "org.freedesktop.TestSuite",
+ "Foo"))
+ {
+ g_printerr ("Signal handler received the wrong message\n");
+ exit (1);
+ }
+
+ dbus_error_init (&derror);
+ if (!dbus_message_get_args (signal, &derror, DBUS_TYPE_DOUBLE,
+ &d, DBUS_TYPE_INVALID))
+ {
+ g_printerr ("failed to get signal args: %s\n", derror.message);
+ dbus_error_free (&derror);
+ exit (1);
+ }
+
+ n_times_foo_received += 1;
+
+ g_main_loop_quit (loop);
+}
+
int
main (int argc, char **argv)
{
DBusConnection *connection;
- GMainLoop *loop;
GError *error;
DBusGProxy *driver;
DBusGProxy *proxy;
proxy = dbus_gproxy_new_for_service (connection,
"org.freedesktop.DBus.TestSuiteEchoService",
- "/fixme/the/test/service/ignores/this", /* FIXME */
+ "/org/freedesktop/TestSuite",
"org.freedesktop.TestSuite");
call = dbus_gproxy_begin_call (proxy, "Echo",
g_print ("String echoed = \"%s\"\n", str);
dbus_free (str);
+
+ /* Test oneway call and signal handling */
+
+ dbus_gproxy_connect_signal (proxy, "Foo",
+ foo_signal_handler,
+ NULL, NULL);
+
+ dbus_gproxy_call_no_reply (proxy, "EmitFoo",
+ DBUS_TYPE_INVALID);
+
+ dbus_connection_flush (connection);
+
+ g_main_loop_run (loop);
+
+ if (n_times_foo_received != 1)
+ {
+ g_printerr ("Foo signal received %d times, should have been 1\n",
+ n_times_foo_received);
+ exit (1);
+ }
g_object_unref (G_OBJECT (driver));
g_object_unref (G_OBJECT (proxy));
DBusError error;
DBusMessage *reply;
char *s;
+
+ _dbus_verbose ("sending reply to Echo method\n");
dbus_error_init (&error);
return DBUS_HANDLER_RESULT_HANDLED;
}
+static void
+path_unregistered_func (DBusConnection *connection,
+ void *user_data)
+{
+ /* connection was finalized */
+}
+
static DBusHandlerResult
-filter_func (DBusConnection *connection,
- DBusMessage *message,
- void *user_data)
-{
+path_message_func (DBusConnection *connection,
+ DBusMessage *message,
+ void *user_data)
+{
if (dbus_message_is_method_call (message,
"org.freedesktop.TestSuite",
"Echo"))
return handle_echo (connection, message);
else if (dbus_message_is_method_call (message,
"org.freedesktop.TestSuite",
- "Exit") ||
- dbus_message_is_signal (message,
- DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL,
- "Disconnected"))
+ "Exit"))
+ {
+ dbus_connection_disconnect (connection);
+ quit ();
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+ else if (dbus_message_is_method_call (message,
+ "org.freedesktop.TestSuite",
+ "EmitFoo"))
+ {
+ /* Emit the Foo signal */
+ DBusMessage *signal;
+
+ _dbus_verbose ("emitting signal Foo\n");
+
+ signal = dbus_message_new_signal ("/org/freedesktop/TestSuite",
+ "org.freedesktop.TestSuite",
+ "Foo");
+ if (signal == NULL)
+ die ("No memory\n");
+
+ if (!dbus_message_append_args (signal,
+ DBUS_TYPE_DOUBLE, 42.6,
+ DBUS_TYPE_INVALID))
+ die ("No memory");
+
+ if (!dbus_connection_send (connection, signal, NULL))
+ die ("No memory\n");
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+ else
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static DBusObjectPathVTable
+echo_vtable = {
+ path_unregistered_func,
+ path_message_func,
+ NULL,
+};
+
+/* Pre-exploded path, "/org/freedesktop/TestSuite" */
+static const char* echo_path[] = { "org", "freedesktop", "TestSuite", NULL };
+
+static DBusHandlerResult
+filter_func (DBusConnection *connection,
+ DBusMessage *message,
+ void *user_data)
+{
+ if (dbus_message_is_signal (message,
+ DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL,
+ "Disconnected"))
{
dbus_connection_disconnect (connection);
quit ();
int result;
dbus_error_init (&error);
- connection = dbus_bus_get (DBUS_BUS_SESSION, &error);
+ connection = dbus_bus_get (DBUS_BUS_ACTIVATION, &error);
if (connection == NULL)
{
- _dbus_verbose ("*** Failed to open connection to activating message bus: %s\n",
- error.message);
+ fprintf (stderr, "*** Failed to open connection to activating message bus: %s\n",
+ error.message);
dbus_error_free (&error);
return 1;
}
filter_func, NULL, NULL))
die ("No memory");
+ if (!dbus_connection_register_object_path (connection,
+ echo_path,
+ &echo_vtable,
+ NULL))
+ die ("No memory");
+
printf ("Acquiring service\n");
result = dbus_bus_acquire_service (connection, "org.freedesktop.DBus.TestSuiteEchoService",
0, &error);
if (dbus_error_is_set (&error))
{
- printf ("Error %s", error.message);
+ fprintf (stderr, "Error %s", error.message);
_dbus_verbose ("*** Failed to acquire service: %s\n",
error.message);
dbus_error_free (&error);