* dbus/dbus-marshal-validate.c, doc/dbus-specification.xml,
authorWaldo Bastian <bastian@kde.org>
Mon, 12 Sep 2005 08:19:33 +0000 (08:19 +0000)
committerWaldo Bastian <bastian@kde.org>
Mon, 12 Sep 2005 08:19:33 +0000 (08:19 +0000)
test/Makefile.am, test/test-names.c: allow hyphens in bus names.

ChangeLog
dbus/dbus-marshal-validate.c
doc/dbus-specification.xml
test/.cvsignore
test/Makefile.am
test/test-names.c [new file with mode: 0644]

index ebb200f..68507f6 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2005-09-12  Waldo Bastian  <bastian@kde.org>
+
+       * dbus/dbus-marshal-validate.c,
+       doc/dbus-specification.xml, test/Makefile.am,
+       test/test-names.c: allow hyphens in bus names.
+
 2005-09-11  Mark McLoughlin  <mark@skynet.ie>
 
        * test/data/auth/fallback.auth-script: we don't
index 92050a5..e9aa26a 100644 (file)
@@ -677,7 +677,7 @@ _dbus_validate_body_with_reason (const DBusString *expected_signature,
 }
 
 /**
- * Determine wether the given charater is valid as the first charater
+ * Determine wether the given character is valid as the first character
  * in a name.
  */
 #define VALID_INITIAL_NAME_CHARACTER(c)         \
@@ -686,7 +686,7 @@ _dbus_validate_body_with_reason (const DBusString *expected_signature,
     ((c) == '_') )
 
 /**
- * Determine wether the given charater is valid as a second or later
+ * Determine wether the given character is valid as a second or later
  * character in a name
  */
 #define VALID_NAME_CHARACTER(c)                 \
@@ -922,15 +922,47 @@ _dbus_validate_error_name (const DBusString  *str,
   return _dbus_validate_interface (str, start, len);
 }
 
-/* This assumes the first char exists and is ':' */
-static dbus_bool_t
-_dbus_validate_unique_name (const DBusString  *str,
-                            int                start,
-                            int                len)
+/**
+ * Determine wether the given character is valid as the first character
+ * in a bus name.
+ */
+#define VALID_INITIAL_BUS_NAME_CHARACTER(c)         \
+  ( ((c) >= 'A' && (c) <= 'Z') ||               \
+    ((c) >= 'a' && (c) <= 'z') ||               \
+    ((c) == '_') || ((c) == '-'))
+
+/**
+ * Determine wether the given character is valid as a second or later
+ * character in a bus name
+ */
+#define VALID_BUS_NAME_CHARACTER(c)                 \
+  ( ((c) >= '0' && (c) <= '9') ||               \
+    ((c) >= 'A' && (c) <= 'Z') ||               \
+    ((c) >= 'a' && (c) <= 'z') ||               \
+    ((c) == '_') || ((c) == '-'))
+
+/**
+ * Checks that the given range of the string is a valid bus 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 extends past the string end.
+ *
+ * @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_validate_bus_name (const DBusString  *str,
+                         int                start,
+                         int                len)
 {
   const unsigned char *s;
   const unsigned char *end;
-  const unsigned char *name;
+  const unsigned char *iface;
+  const unsigned char *last_dot;
 
   _dbus_assert (start >= 0);
   _dbus_assert (len >= 0);
@@ -942,12 +974,47 @@ _dbus_validate_unique_name (const DBusString  *str,
   if (len > DBUS_MAXIMUM_NAME_LENGTH)
     return FALSE;
 
-  _dbus_assert (len > 0);
+  if (len == 0)
+    return FALSE;
 
-  name = _dbus_string_get_const_data (str) + start;
-  end = name + len;
-  _dbus_assert (*name == ':');
-  s = name + 1;
+  last_dot = NULL;
+  iface = _dbus_string_get_const_data (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 (*s == ':')
+  {
+    /* unique name */
+    ++s;
+    while (s != end)
+      {
+        if (*s == '.')
+          {
+            if (_DBUS_UNLIKELY ((s + 1) == end))
+              return FALSE;
+            if (_DBUS_UNLIKELY (!VALID_BUS_NAME_CHARACTER (*(s + 1))))
+              return FALSE;
+            ++s; /* we just validated the next char, so skip two */
+          }
+        else if (_DBUS_UNLIKELY (!VALID_BUS_NAME_CHARACTER (*s)))
+          {
+            return FALSE;
+          }
+
+        ++s;
+      }
+
+    return TRUE;
+  }
+  else if (_DBUS_UNLIKELY (*s == '.')) /* disallow starting with a . */
+    return FALSE;
+  else if (_DBUS_UNLIKELY (!VALID_INITIAL_BUS_NAME_CHARACTER (*s)))
+    return FALSE;
+  else
+    ++s;
 
   while (s != end)
     {
@@ -955,11 +1022,12 @@ _dbus_validate_unique_name (const DBusString  *str,
         {
           if (_DBUS_UNLIKELY ((s + 1) == end))
             return FALSE;
-          if (_DBUS_UNLIKELY (!VALID_NAME_CHARACTER (*(s + 1))))
+          else if (_DBUS_UNLIKELY (!VALID_INITIAL_BUS_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)))
+      else if (_DBUS_UNLIKELY (!VALID_BUS_NAME_CHARACTER (*s)))
         {
           return FALSE;
         }
@@ -967,33 +1035,10 @@ _dbus_validate_unique_name (const DBusString  *str,
       ++s;
     }
 
-  return TRUE;
-}
-
-/**
- * Checks that the given range of the string is a valid bus 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 extends past the string end.
- *
- * @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_validate_bus_name (const DBusString  *str,
-                         int                start,
-                         int                len)
-{
-  if (_DBUS_UNLIKELY (len == 0))
+  if (_DBUS_UNLIKELY (last_dot == NULL))
     return FALSE;
-  if (_dbus_string_get_byte (str, start) == ':')
-    return _dbus_validate_unique_name (str, start, len);
-  else
-    return _dbus_validate_interface (str, start, len);
+
+  return TRUE;
 }
 
 /**
index 0ea43a8..0194ff4 100644 (file)
           additional restrictions that apply to interface names 
           specifically:
           <itemizedlist>
-            <listitem><para>They are composed of 1 or more elements separated by
+            <listitem><para>Interface names are composed of 1 or more elements separated by
                 a period ('.') character. All elements must contain at least 
                 one character.
                 </para>
                 </para>
             </listitem>
 
-           <listitem><para>They must contain at least one '.' (period)
+           <listitem><para>Interface names 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 the maximum name length.</para></listitem>
+           <listitem><para>Interface names must not begin with a '.' (period) character.</para></listitem>
+           <listitem><para>Interface names must not exceed the maximum name length.</para></listitem>
           </itemizedlist>
         </para>
       </sect3>
       <sect3 id="message-protocol-names-bus">
         <title>Bus names</title>
         <para>
-          Bus names have the same restrictions as interface names, with a
-          special exception for unique connection names. A unique name's first
-          element must start with a colon (':') character. After the colon, any
-          characters in "[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. Bus names not starting with a colon have none of these 
-          exceptions and follow the same rules as interface names.
+          Connections have one or more bus names associated with them.
+          A connection has exactly one bus name that is a unique connection
+          name. The unique connection name remains with the connection for
+          its entire lifetime.
+          A bus name is of type <literal>STRING</literal>,
+          meaning that it must be valid UTF-8. However, there are also
+          some additional restrictions that apply to bus names 
+          specifically:
+          <itemizedlist>
+            <listitem><para>Bus names that start with a colon (':')
+                character are unique connection names.
+                </para>
+            </listitem>
+            <listitem><para>Bus names 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]_-". Only elements that are part of a unique
+                connection name may begin with a digit, elements in
+                other bus names must not begin with a digit.
+                </para>
+            </listitem>
+
+           <listitem><para>Bus names must contain at least one '.' (period)
+              character (and thus at least two elements).
+              </para></listitem>
+
+           <listitem><para>Bus names must not begin with a '.' (period) character.</para></listitem>
+           <listitem><para>Bus names must not exceed the maximum name length.</para></listitem>
+          </itemizedlist>
+        </para>
+        <para>
+          Note that the hyphen ('-') character is allowed in bus names but
+          not in interface names.
         </para>
       </sect3>
       <sect3 id="message-protocol-names-member">
index 20de1a2..f7a6587 100644 (file)
@@ -22,3 +22,4 @@ test-sleep-forever
 decode-gcov
 shell-test
 test-shell-service
+test-names
index e0a25aa..5f90488 100644 (file)
@@ -14,7 +14,7 @@ INCLUDES=-I$(top_srcdir) $(DBUS_TEST_CFLAGS)
 
 if DBUS_BUILD_TESTS
 ## break-loader removed for now
-TEST_BINARIES=test-service test-shell-service shell-test spawn-test test-segfault test-exit test-sleep-forever
+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
 TESTS=shell-test
@@ -36,6 +36,11 @@ test_service_SOURCES=                                \
        test-utils.c                            \
        test-utils.h
 
+test_names_SOURCES=                            \
+       test-names.c                            \
+       test-utils.c                            \
+       test-utils.h
+
 ##break_loader_SOURCES=                                \
 ##     break-loader.c
 
@@ -65,6 +70,7 @@ decode_gcov_SOURCES=                          \
 TEST_LIBS=$(DBUS_TEST_LIBS) $(top_builddir)/dbus/libdbus-convenience.la
 
 test_service_LDADD=$(TEST_LIBS)
+test_names_LDADD=$(TEST_LIBS)
 ## break_loader_LDADD= $(TEST_LIBS)
 test_shell_service_LDADD=$(TEST_LIBS)
 shell_test_LDADD=$(TEST_LIBS)
diff --git a/test/test-names.c b/test/test-names.c
new file mode 100644 (file)
index 0000000..b29648d
--- /dev/null
@@ -0,0 +1,79 @@
+
+#include "test-utils.h"
+
+static DBusLoop *loop;
+
+static void
+die (const char *message)
+{
+  fprintf (stderr, "*** test-names: %s", message);
+  exit (1);
+}
+
+static void
+TestName(DBusConnection *connection, const char *name, int expectedSuccess)
+{
+  DBusError error;
+  dbus_error_init (&error);
+
+  (void) dbus_bus_request_name (connection, name, 0, &error);
+  if (dbus_error_is_set (&error))
+    {
+      if (expectedSuccess)
+        fprintf (stderr, "Error acquiring name '%s': %s\n", name, error.message);
+      else
+        fprintf (stdout, "Expected Error acquiring name '%s': %s\n", name, error.message);
+      _dbus_verbose ("*** Failed to acquire name '%s': %s\n", name,
+                     error.message);
+      dbus_error_free (&error);
+      if (expectedSuccess)
+        exit (1);
+    }
+  else 
+    {
+      if (!expectedSuccess)
+        fprintf (stderr, "Unexpected Success acquiring name '%s'\n", name);
+      else
+        fprintf (stdout, "Successfully acquired name '%s'\n", name);
+      _dbus_verbose ("*** Managed to acquire name '%s'\n", name);
+      if (!expectedSuccess)
+        exit (1);
+    }
+}
+
+int
+main (int    argc,
+      char **argv)
+{
+  DBusError error;
+  int result;
+  DBusConnection *connection;
+  
+  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;
+    }
+
+  loop = _dbus_loop_new ();
+  if (loop == NULL)
+    die ("No memory\n");
+  
+  if (!test_connection_setup (loop, connection))
+    die ("No memory\n");
+
+  TestName(connection, "org.freedesktop.DBus.Test", TRUE);
+  TestName(connection, "org.freedesktop.DBus.Test-2", TRUE);
+  TestName(connection, "org.freedesktop.DBus.Test_2", TRUE);
+#if 0
+  TestName(connection, "Test_2", TRUE);
+#endif
+
+  _dbus_verbose ("*** Test service name exiting\n");
+  
+  return 0;
+}