summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Zeuthen <davidz@redhat.com>2010-05-02 09:20:39 -0400
committerDavid Zeuthen <davidz@redhat.com>2010-05-02 09:20:39 -0400
commit114680658d61cddf2878af3d519d44131364b61e (patch)
tree6c44a08ac5b3f79a83eec365bdca031d7df742f1
parentfd981112644d9709f6ecaa66278a189be897dc04 (diff)
Add back GDBusServer
-rw-r--r--docs/reference/gdbus/gdbus-docs.xml1
-rw-r--r--docs/reference/gdbus/gdbus-standalone-sections.txt20
-rw-r--r--docs/reference/gdbus/gdbus-standalone.types1
-rw-r--r--gdbus/Makefile.am7
-rw-r--r--gdbus/example-peer.c220
-rw-r--r--gdbus/gdbus.c82
-rw-r--r--gdbus/gdbus.h1
-rw-r--r--gdbus/gdbusaddress.c532
-rw-r--r--gdbus/gdbusaddress.h4
-rw-r--r--gdbus/gdbusenums.h18
-rw-r--r--gdbus/gdbusprivate.h7
-rw-r--r--gdbus/gdbusserver.c890
-rw-r--r--gdbus/gdbusserver.h95
-rw-r--r--gdbus/gdbustypes.h1
-rw-r--r--gdbus/tests/addresses.c80
15 files changed, 1804 insertions, 155 deletions
diff --git a/docs/reference/gdbus/gdbus-docs.xml b/docs/reference/gdbus/gdbus-docs.xml
index 542eb13..6ab50a8 100644
--- a/docs/reference/gdbus/gdbus-docs.xml
+++ b/docs/reference/gdbus/gdbus-docs.xml
@@ -23,6 +23,7 @@
<xi:include href="xml/gdbusconnection.xml"/>
<xi:include href="xml/gdbusmethodinvocation.xml"/>
<xi:include href="xml/gdbusproxy.xml"/>
+ <xi:include href="xml/gdbusserver.xml"/>
</chapter>
<chapter id="convenience">
<title>GDBus Convenience</title>
diff --git a/docs/reference/gdbus/gdbus-standalone-sections.txt b/docs/reference/gdbus/gdbus-standalone-sections.txt
index e98b4b9..abc04c4 100644
--- a/docs/reference/gdbus/gdbus-standalone-sections.txt
+++ b/docs/reference/gdbus/gdbus-standalone-sections.txt
@@ -1,5 +1,7 @@
<SECTION>
<FILE>gdbusaddress</FILE>
+g_dbus_is_address
+g_dbus_is_supported_address
g_dbus_address_get_stream
g_dbus_address_get_stream_finish
g_dbus_address_get_stream_sync
@@ -18,6 +20,24 @@ g_dbus_is_interface_name
</SECTION>
<SECTION>
+<FILE>gdbusserver</FILE>
+<TITLE>GDBusServer</TITLE>
+GDBusServer
+GDBusServerClass
+GDBusServerFlags
+g_dbus_server_new_sync
+g_dbus_server_get_client_address
+<SUBSECTION Standard>
+G_DBUS_SERVER
+G_IS_DBUS_SERVER
+G_TYPE_DBUS_SERVER
+g_dbus_server_get_gtype
+G_DBUS_SERVER_CLASS
+G_IS_DBUS_SERVER_CLASS
+G_DBUS_SERVER_GET_CLASS
+</SECTION>
+
+<SECTION>
<FILE>gdbusmessage</FILE>
<TITLE>GDBusMessage</TITLE>
GDBusMessageType
diff --git a/docs/reference/gdbus/gdbus-standalone.types b/docs/reference/gdbus/gdbus-standalone.types
index 5fc593c..4c1cc86 100644
--- a/docs/reference/gdbus/gdbus-standalone.types
+++ b/docs/reference/gdbus/gdbus-standalone.types
@@ -5,3 +5,4 @@ g_bus_name_owner_flags_get_type
g_dbus_error_get_type
g_dbus_proxy_get_type
g_dbus_method_invocation_get_type
+g_dbus_server_get_type
diff --git a/gdbus/Makefile.am b/gdbus/Makefile.am
index 3122307..20faee5 100644
--- a/gdbus/Makefile.am
+++ b/gdbus/Makefile.am
@@ -46,6 +46,7 @@ gdbus_headers = \
gdbusproxy.h \
gdbusintrospection.h \
gdbusmethodinvocation.h \
+ gdbusserver.h \
$(NULL)
libgdbus_standalone_la_SOURCES = \
@@ -70,6 +71,7 @@ libgdbus_standalone_la_SOURCES = \
gdbusprivate.h gdbusprivate.c \
gdbusintrospection.h gdbusintrospection.c \
gdbusmethodinvocation.h gdbusmethodinvocation.c \
+ gdbusserver.h gdbusserver.c \
$(NULL)
$(libgdbus_standalone_la_OBJECTS): $(marshal_sources)
@@ -144,6 +146,7 @@ noinst_PROGRAMS += example-watch-proxy
noinst_PROGRAMS += example-server
noinst_PROGRAMS += example-unix-fd-client
noinst_PROGRAMS += example-subtree
+noinst_PROGRAMS += example-peer
example_watch_name_SOURCES = example-watch-name.c
example_watch_name_CFLAGS = $(GLIB2_CFLAGS) $(GOBJECT2_CFLAGS) $(GIO2_CFLAGS) $(GIO_UNIX2_CFLAGS)
@@ -169,6 +172,10 @@ example_subtree_SOURCES = example-subtree.c
example_subtree_CFLAGS = $(GLIB2_CFLAGS) $(GOBJECT2_CFLAGS) $(GIO2_CFLAGS) $(GIO_UNIX2_CFLAGS)
example_subtree_LDADD = libgdbus-standalone.la $(GLIB2_LIBS) $(GOBJECT2_LIBS) $(GIO2_LIBS) $(GIO_UNIX2_LIBS)
+example_peer_SOURCES = example-peer.c
+example_peer_CFLAGS = $(GLIB2_CFLAGS) $(GOBJECT2_CFLAGS) $(GIO2_CFLAGS) $(GIO_UNIX2_CFLAGS)
+example_peer_LDADD = libgdbus-standalone.la $(GLIB2_LIBS) $(GOBJECT2_LIBS) $(GIO2_LIBS) $(GIO_UNIX2_LIBS)
+
bin_PROGRAMS = gdbus
gdbus_SOURCES = gdbus.c
diff --git a/gdbus/example-peer.c b/gdbus/example-peer.c
new file mode 100644
index 0000000..1a180ee
--- /dev/null
+++ b/gdbus/example-peer.c
@@ -0,0 +1,220 @@
+
+#include <gdbus/gdbus.h>
+#include <stdlib.h>
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static GDBusNodeInfo *introspection_data = NULL;
+
+/* Introspection data for the service we are exporting */
+static const gchar introspection_xml[] =
+ "<node>"
+ " <interface name='org.gtk.GDBus.TestPeerInterface'>"
+ " <method name='HelloWorld'>"
+ " <arg type='s' name='greeting' direction='in'/>"
+ " <arg type='s' name='response' direction='out'/>"
+ " </method>"
+ " <method name='GimmeStdout'/>"
+ " </interface>"
+ "</node>";
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+handle_method_call (GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *method_name,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ if (g_strcmp0 (method_name, "HelloWorld") == 0)
+ {
+ const gchar *greeting;
+ gchar *response;
+
+ g_variant_get (parameters, "(s)", &greeting);
+ response = g_strdup_printf ("You said '%s'. KTHXBYE!", greeting);
+ g_dbus_method_invocation_return_value (invocation,
+ g_variant_new ("(s)", response));
+ g_free (response);
+ g_print ("Client said: %s\n", greeting);
+ }
+}
+
+static const GDBusInterfaceVTable interface_vtable =
+{
+ handle_method_call,
+ NULL,
+ NULL,
+};
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+on_new_connection (GDBusServer *server,
+ GDBusConnection *connection,
+ gpointer user_data)
+{
+ guint registration_id;
+
+ g_print ("Client connected. Negotiated capabilities: unix-fd-passing=%d\n",
+ g_dbus_connection_get_capabilities (connection) & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING);
+
+ g_object_ref (connection);
+ registration_id = g_dbus_connection_register_object (connection,
+ "/org/gtk/GDBus/TestObject",
+ "org.gtk.GDBus.TestPeerInterface",
+ &introspection_data->interfaces[0],
+ &interface_vtable,
+ NULL, /* user_data */
+ NULL, /* user_data_free_func */
+ NULL); /* GError** */
+ g_assert (registration_id > 0);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+int
+main (int argc, char *argv[])
+{
+ gint ret;
+ gboolean opt_server;
+ gchar *opt_address;
+ GOptionContext *opt_context;
+ gboolean opt_allow_anonymous;
+ GError *error;
+ GOptionEntry opt_entries[] =
+ {
+ { "server", 's', 0, G_OPTION_ARG_NONE, &opt_server, "Start a server instead of a client", NULL },
+ { "address", 'a', 0, G_OPTION_ARG_STRING, &opt_address, "D-Bus address to use", NULL },
+ { "allow-anonymous", 'n', 0, G_OPTION_ARG_NONE, &opt_allow_anonymous, "Allow anonymous authentication", NULL },
+ { NULL}
+ };
+
+ ret = 1;
+
+ g_type_init ();
+
+ error = NULL;
+ opt_address = NULL;
+ opt_server = FALSE;
+ opt_context = g_option_context_new ("peer-to-peer example");
+ g_option_context_add_main_entries (opt_context, opt_entries, NULL);
+ if (!g_option_context_parse (opt_context, &argc, &argv, &error))
+ {
+ g_printerr ("Error parsing options: %s\n", error->message);
+ g_error_free (error);
+ goto out;
+ }
+ if (opt_address == NULL)
+ {
+ g_printerr ("Incorrect usage, try --help.\n");
+ goto out;
+ }
+ if (!opt_server && opt_allow_anonymous)
+ {
+ g_printerr ("The --allow-anonymous option only makes sense when used with --server.\n");
+ goto out;
+ }
+
+ /* We are lazy here - we don't want to manually provide
+ * the introspection data structures - so we just build
+ * them from XML.
+ */
+ introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
+ g_assert (introspection_data != NULL);
+
+ if (opt_server)
+ {
+ GDBusServer *server;
+ gchar *guid;
+ GMainLoop *loop;
+ GDBusServerFlags server_flags;
+
+ guid = g_dbus_generate_guid ();
+
+ server_flags = G_DBUS_SERVER_FLAGS_NONE;
+ if (opt_allow_anonymous)
+ server_flags |= G_DBUS_SERVER_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS;
+
+ error = NULL;
+ server = g_dbus_server_new_sync (opt_address,
+ server_flags,
+ guid,
+ NULL,
+ &error);
+ g_free (guid);
+
+ if (server == NULL)
+ {
+ g_printerr ("Error creating server at address %s: %s\n", opt_address, error->message);
+ g_error_free (error);
+ goto out;
+ }
+ g_print ("Server is listening at: %s\n", g_dbus_server_get_client_address (server));
+ g_signal_connect (server,
+ "new-connection",
+ G_CALLBACK (on_new_connection),
+ NULL);
+
+ loop = g_main_loop_new (NULL, FALSE);
+ g_main_loop_run (loop);
+
+ g_object_unref (server);
+ g_main_loop_unref (loop);
+ }
+ else
+ {
+ GDBusConnection *connection;
+ const gchar *greeting_response;
+ GVariant *value;
+ gchar *greeting;
+
+ error = NULL;
+ connection = g_dbus_connection_new_for_address_sync (opt_address,
+ G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
+ NULL, /* GCancellable */
+ &error);
+ if (connection == NULL)
+ {
+ g_printerr ("Error connecting to D-Bus address %s: %s\n", opt_address, error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ g_print ("Connected. Negotiated capabilities: unix-fd-passing=%d\n",
+ g_dbus_connection_get_capabilities (connection) & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING);
+
+ greeting = g_strdup_printf ("Hey, it's %" G_GUINT64_FORMAT " already!", (guint64) time (NULL));
+ value = g_dbus_connection_invoke_method_sync (connection,
+ NULL, /* bus_name */
+ "/org/gtk/GDBus/TestObject",
+ "org.gtk.GDBus.TestPeerInterface",
+ "HelloWorld",
+ g_variant_new ("(s)", greeting),
+ G_DBUS_INVOKE_METHOD_FLAGS_NONE,
+ -1,
+ NULL,
+ &error);
+ if (value == NULL)
+ {
+ g_printerr ("Error invoking HelloWorld(): %s\n", error->message);
+ g_error_free (error);
+ goto out;
+ }
+ g_variant_get (value, "(s)", &greeting_response);
+ g_print ("Server said: %s\n", greeting_response);
+ g_variant_unref (value);
+
+ g_object_unref (connection);
+ }
+ g_dbus_node_info_free (introspection_data);
+
+ ret = 0;
+
+ out:
+ return ret;
+}
diff --git a/gdbus/gdbus.c b/gdbus/gdbus.c
index 7e66d73..91ee2f5 100644
--- a/gdbus/gdbus.c
+++ b/gdbus/gdbus.c
@@ -420,11 +420,10 @@ connection_get_dbus_connection (GError **error)
}
else if (opt_connection_address != NULL)
{
- g_set_error (error,
- G_IO_ERROR,
- G_IO_ERROR_FAILED,
- _("--address is currently not implemented `%s', sorry"),
- opt_connection_address);
+ c = g_dbus_connection_new_for_address_sync (opt_connection_address,
+ G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
+ NULL, /* GCancellable */
+ error);
}
out:
@@ -656,23 +655,27 @@ handle_call (gint *argc,
}
/* validate and complete destination (bus name) */
- if (complete_names)
- {
- print_names (c, FALSE);
- goto out;
- }
- if (opt_call_dest == NULL)
- {
- if (request_completion)
- g_print ("--dest \n");
- else
- g_printerr (_("Error: Destination is not specified\n"));
- goto out;
- }
- if (request_completion && g_strcmp0 ("--dest", completion_prev) == 0)
+ if (g_dbus_connection_get_unique_name (c) != NULL)
{
- print_names (c, g_str_has_prefix (opt_call_dest, ":"));
- goto out;
+ /* this only makes sense on message bus connections */
+ if (complete_names)
+ {
+ print_names (c, FALSE);
+ goto out;
+ }
+ if (opt_call_dest == NULL)
+ {
+ if (request_completion)
+ g_print ("--dest \n");
+ else
+ g_printerr (_("Error: Destination is not specified\n"));
+ goto out;
+ }
+ if (request_completion && g_strcmp0 ("--dest", completion_prev) == 0)
+ {
+ print_names (c, g_str_has_prefix (opt_call_dest, ":"));
+ goto out;
+ }
}
/* validate and complete object path */
@@ -1176,25 +1179,28 @@ handle_introspect (gint *argc,
goto out;
}
- if (complete_names)
- {
- print_names (c, FALSE);
- goto out;
- }
- if (opt_introspect_dest == NULL)
+ if (g_dbus_connection_get_unique_name (c) != NULL)
{
- if (request_completion)
- g_print ("--dest \n");
- else
- g_printerr (_("Error: Destination is not specified\n"));
- goto out;
- }
- if (request_completion && g_strcmp0 ("--dest", completion_prev) == 0)
- {
- print_names (c, g_str_has_prefix (opt_introspect_dest, ":"));
- goto out;
+ if (complete_names)
+ {
+ print_names (c, FALSE);
+ goto out;
+ }
+ /* this only makes sense on message bus connections */
+ if (opt_introspect_dest == NULL)
+ {
+ if (request_completion)
+ g_print ("--dest \n");
+ else
+ g_printerr (_("Error: Destination is not specified\n"));
+ goto out;
+ }
+ if (request_completion && g_strcmp0 ("--dest", completion_prev) == 0)
+ {
+ print_names (c, g_str_has_prefix (opt_introspect_dest, ":"));
+ goto out;
+ }
}
-
if (complete_paths)
{
print_paths (c, opt_introspect_dest, "/");
diff --git a/gdbus/gdbus.h b/gdbus/gdbus.h
index 69e15f3..69ee0f1 100644
--- a/gdbus/gdbus.h
+++ b/gdbus/gdbus.h
@@ -38,6 +38,7 @@
#include <gdbus/gdbusproxy.h>
#include <gdbus/gdbusintrospection.h>
#include <gdbus/gdbusmethodinvocation.h>
+#include <gdbus/gdbusserver.h>
#undef __G_DBUS_G_DBUS_H_INSIDE__
diff --git a/gdbus/gdbusaddress.c b/gdbus/gdbusaddress.c
index 0d0c2dc..3534562 100644
--- a/gdbus/gdbusaddress.c
+++ b/gdbus/gdbusaddress.c
@@ -26,9 +26,11 @@
#include <glib/gi18n.h>
+#include "gdbusutils.h"
#include "gdbusaddress.h"
#include "gdbuserror.h"
#include "gdbusenumtypes.h"
+#include "gdbusprivate.h"
#ifdef G_OS_UNIX
#include <gio/gunixsocketaddress.h>
@@ -45,6 +47,430 @@
/* ---------------------------------------------------------------------------------------------------- */
+/**
+ * g_dbus_is_address:
+ * @string: A string.
+ *
+ * Checks if @string is a D-Bus address.
+ *
+ * This doesn't check if @string is actually supported by #GDBusServer
+ * or #GDBusConnection - use g_dbus_is_supported_address() to do more
+ * checks.
+ *
+ * Returns: %TRUE if @string is a valid D-Bus address, %FALSE otherwise.
+ */
+gboolean
+g_dbus_is_address (const gchar *string)
+{
+ guint n;
+ gchar **a;
+ gboolean ret;
+
+ ret = FALSE;
+
+ g_return_val_if_fail (string != NULL, FALSE);
+
+ a = g_strsplit (string, ";", 0);
+ for (n = 0; a[n] != NULL; n++)
+ {
+ if (!_g_dbus_address_parse_entry (a[n],
+ NULL,
+ NULL,
+ NULL))
+ goto out;
+ }
+
+ ret = TRUE;
+
+ out:
+ g_strfreev (a);
+ return ret;
+}
+
+static gboolean
+is_valid_unix (const gchar *address_entry,
+ GHashTable *key_value_pairs,
+ GError **error)
+{
+ gboolean ret;
+ GList *keys;
+ GList *l;
+ const gchar *path;
+ const gchar *tmpdir;
+ const gchar *abstract;
+
+ ret = FALSE;
+ keys = NULL;
+ path = NULL;
+ tmpdir = NULL;
+ abstract = NULL;
+
+ keys = g_hash_table_get_keys (key_value_pairs);
+ for (l = keys; l != NULL; l = l->next)
+ {
+ const gchar *key = l->data;
+ if (g_strcmp0 (key, "path") == 0)
+ path = g_hash_table_lookup (key_value_pairs, key);
+ else if (g_strcmp0 (key, "tmpdir") == 0)
+ tmpdir = g_hash_table_lookup (key_value_pairs, key);
+ else if (g_strcmp0 (key, "abstract") == 0)
+ abstract = g_hash_table_lookup (key_value_pairs, key);
+ else
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_ARGUMENT,
+ _("Unsupported key `%s' in address entry `%s'"),
+ key,
+ address_entry);
+ goto out;
+ }
+ }
+
+ if (path != NULL)
+ {
+ if (tmpdir != NULL || abstract != NULL)
+ goto meaningless;
+ /* TODO: validate path */
+ }
+ else if (tmpdir != NULL)
+ {
+ if (path != NULL || abstract != NULL)
+ goto meaningless;
+ /* TODO: validate tmpdir */
+ }
+ else if (abstract != NULL)
+ {
+ if (path != NULL || tmpdir != NULL)
+ goto meaningless;
+ /* TODO: validate abstract */
+ }
+ else
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_ARGUMENT,
+ _("Address `%s' is invalid (need exactly one of path, tmpdir or abstract keys"),
+ address_entry);
+ goto out;
+ }
+
+
+ ret= TRUE;
+ goto out;
+
+ meaningless:
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_ARGUMENT,
+ _("Meaningless key/value pair combination in address entry `%s'"),
+ address_entry);
+
+ out:
+ g_list_free (keys);
+
+ return ret;
+}
+
+static gboolean
+is_valid_nonce_tcp (const gchar *address_entry,
+ GHashTable *key_value_pairs,
+ GError **error)
+{
+ gboolean ret;
+ GList *keys;
+ GList *l;
+ const gchar *host;
+ const gchar *port;
+ const gchar *family;
+ const gchar *nonce_file;
+ gint port_num;
+ gchar *endp;
+
+ ret = FALSE;
+ keys = NULL;
+ host = NULL;
+ port = NULL;
+ family = NULL;
+ nonce_file = NULL;
+
+ keys = g_hash_table_get_keys (key_value_pairs);
+ for (l = keys; l != NULL; l = l->next)
+ {
+ const gchar *key = l->data;
+ if (g_strcmp0 (key, "host") == 0)
+ host = g_hash_table_lookup (key_value_pairs, key);
+ else if (g_strcmp0 (key, "port") == 0)
+ port = g_hash_table_lookup (key_value_pairs, key);
+ else if (g_strcmp0 (key, "family") == 0)
+ family = g_hash_table_lookup (key_value_pairs, key);
+ else if (g_strcmp0 (key, "noncefile") == 0)
+ nonce_file = g_hash_table_lookup (key_value_pairs, key);
+ else
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_ARGUMENT,
+ _("Unsupported key `%s' in address entry `%s'"),
+ key,
+ address_entry);
+ goto out;
+ }
+ }
+
+ if (port != NULL)
+ {
+ port_num = strtol (port, &endp, 10);
+ if ((*port == '\0' || *endp != '\0') || port_num < 0 || port_num >= 65536)
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_ARGUMENT,
+ _("Error in address `%s' - the port attribute is malformed"),
+ address_entry);
+ goto out;
+ }
+ }
+
+ if (family != NULL && !(g_strcmp0 (family, "ipv4") == 0 || g_strcmp0 (family, "ipv6") == 0))
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_ARGUMENT,
+ _("Error in address `%s' - the family attribute is malformed"),
+ address_entry);
+ goto out;
+ }
+
+ ret= TRUE;
+
+ out:
+ g_list_free (keys);
+
+ return ret;
+}
+
+static gboolean
+is_valid_tcp (const gchar *address_entry,
+ GHashTable *key_value_pairs,
+ GError **error)
+{
+ gboolean ret;
+ GList *keys;
+ GList *l;
+ const gchar *host;
+ const gchar *port;
+ const gchar *family;
+ gint port_num;
+ gchar *endp;
+
+ ret = FALSE;
+ keys = NULL;
+ host = NULL;
+ port = NULL;
+ family = NULL;
+
+ keys = g_hash_table_get_keys (key_value_pairs);
+ for (l = keys; l != NULL; l = l->next)
+ {
+ const gchar *key = l->data;
+ if (g_strcmp0 (key, "host") == 0)
+ host = g_hash_table_lookup (key_value_pairs, key);
+ else if (g_strcmp0 (key, "port") == 0)
+ port = g_hash_table_lookup (key_value_pairs, key);
+ else if (g_strcmp0 (key, "family") == 0)
+ family = g_hash_table_lookup (key_value_pairs, key);
+ else
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_ARGUMENT,
+ _("Unsupported key `%s' in address entry `%s'"),
+ key,
+ address_entry);
+ goto out;
+ }
+ }
+
+ if (port != NULL)
+ {
+ port_num = strtol (port, &endp, 10);
+ if ((*port == '\0' || *endp != '\0') || port_num < 0 || port_num >= 65536)
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_ARGUMENT,
+ _("Error in address `%s' - the port attribute is malformed"),
+ address_entry);
+ goto out;
+ }
+ }
+
+ if (family != NULL && !(g_strcmp0 (family, "ipv4") == 0 || g_strcmp0 (family, "ipv6") == 0))
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_ARGUMENT,
+ _("Error in address `%s' - the family attribute is malformed"),
+ address_entry);
+ goto out;
+ }
+
+ ret= TRUE;
+
+ out:
+ g_list_free (keys);
+
+ return ret;
+}
+
+/**
+ * g_dbus_is_supported_address:
+ * @string: A string.
+ * @error: Return location for error or %NULL.
+ *
+ * Like g_dbus_is_address() but also checks if the library suppors the
+ * transports in @string and that key/value pairs for each transport
+ * are valid.
+ *
+ * Returns: %TRUE if @string is a valid D-Bus address that is
+ * supported by this library, %FALSE if @error is set.
+ */
+gboolean
+g_dbus_is_supported_address (const gchar *string,
+ GError **error)
+{
+ guint n;
+ gchar **a;
+ gboolean ret;
+
+ ret = FALSE;
+
+ g_return_val_if_fail (string != NULL, FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ a = g_strsplit (string, ";", 0);
+ for (n = 0; a[n] != NULL; n++)
+ {
+ gchar *transport_name;
+ GHashTable *key_value_pairs;
+ gboolean supported;
+
+ if (!_g_dbus_address_parse_entry (a[n],
+ &transport_name,
+ &key_value_pairs,
+ error))
+ goto out;
+
+ supported = FALSE;
+ if (g_strcmp0 (transport_name, "unix") == 0)
+ supported = is_valid_unix (a[n], key_value_pairs, error);
+ else if (g_strcmp0 (transport_name, "tcp") == 0)
+ supported = is_valid_tcp (a[n], key_value_pairs, error);
+ else if (g_strcmp0 (transport_name, "nonce-tcp") == 0)
+ supported = is_valid_nonce_tcp (a[n], key_value_pairs, error);
+
+ g_free (transport_name);
+ g_hash_table_unref (key_value_pairs);
+
+ if (!supported)
+ goto out;
+ }
+
+ ret = TRUE;
+
+ out:
+ g_strfreev (a);
+
+ g_assert (ret || (!ret && (error == NULL || *error != NULL)));
+
+ return ret;
+}
+
+gboolean
+_g_dbus_address_parse_entry (const gchar *address_entry,
+ gchar **out_transport_name,
+ GHashTable **out_key_value_pairs,
+ GError **error)
+{
+ gboolean ret;
+ GHashTable *key_value_pairs;
+ gchar *transport_name;
+ gchar **kv_pairs;
+ const gchar *s;
+ guint n;
+
+ ret = FALSE;
+ kv_pairs = NULL;
+ transport_name = NULL;
+ key_value_pairs = NULL;
+
+ s = strchr (address_entry, ':');
+ if (s == NULL)
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_ARGUMENT,
+ _("Address element `%s', does not contain a colon (:)"),
+ address_entry);
+ goto out;
+ }
+
+ transport_name = g_strndup (address_entry, s - address_entry);
+ key_value_pairs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+
+ kv_pairs = g_strsplit (s + 1, ",", 0);
+ for (n = 0; kv_pairs != NULL && kv_pairs[n] != NULL; n++)
+ {
+ const gchar *kv_pair = kv_pairs[n];
+ gchar *key;
+ gchar *value;
+
+ s = strchr (kv_pair, '=');
+ if (s == NULL)
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_ARGUMENT,
+ _("Key/Value pair %d, `%s', in address element `%s', does not contain an equal sign"),
+ n,
+ kv_pair,
+ address_entry);
+ goto out;
+ }
+
+ /* TODO: actually validate that no illegal characters are present before and after then '=' sign */
+ key = g_uri_unescape_segment (kv_pair, s, NULL);
+ value = g_uri_unescape_segment (s + 1, kv_pair + strlen (kv_pair), NULL);
+ g_hash_table_insert (key_value_pairs, key, value);
+ }
+
+ ret = TRUE;
+
+out:
+ g_strfreev (kv_pairs);
+ if (ret)
+ {
+ if (out_transport_name != NULL)
+ *out_transport_name = transport_name;
+ else
+ g_free (transport_name);
+ if (out_key_value_pairs != NULL)
+ *out_key_value_pairs = key_value_pairs;
+ else if (key_value_pairs != NULL)
+ g_hash_table_unref (key_value_pairs);
+ }
+ else
+ {
+ g_free (transport_name);
+ if (key_value_pairs != NULL)
+ g_hash_table_unref (key_value_pairs);
+ }
+ return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
/* TODO: Declare an extension point called GDBusTransport (or similar)
* and move code below to extensions implementing said extension
* point. That way we can implement a D-Bus transport over X11 without
@@ -100,12 +526,15 @@ g_dbus_address_connect (const gchar *address_entry,
}
}
#endif
- else if (g_strcmp0 (transport_name, "nonce-tcp") == 0)
+ else if (g_strcmp0 (transport_name, "tcp") == 0 || g_strcmp0 (transport_name, "nonce-tcp") == 0)
{
const gchar *s;
const gchar *host;
guint port;
gchar *endp;
+ gboolean is_nonce;
+
+ is_nonce = (g_strcmp0 (transport_name, "nonce-tcp") == 0);
host = g_hash_table_lookup (key_value_pairs, "host");
if (host == NULL)
@@ -122,7 +551,7 @@ g_dbus_address_connect (const gchar *address_entry,
if (s == NULL)
s = "0";
port = strtol (s, &endp, 10);
- if ((*s == '\0' || *endp != '\0') || port == 0 || port >= 65536)
+ if ((*s == '\0' || *endp != '\0') || port < 0 || port >= 65536)
{
g_set_error (error,
G_IO_ERROR,
@@ -132,18 +561,22 @@ g_dbus_address_connect (const gchar *address_entry,
goto out;
}
- nonce_file = g_hash_table_lookup (key_value_pairs, "noncefile");
- if (nonce_file == NULL)
+
+ if (is_nonce)
{
- g_set_error (error,
- G_IO_ERROR,
- G_IO_ERROR_INVALID_ARGUMENT,
- _("Error in address `%s' - the noncefile attribute is missing or malformed"),
- address_entry);
- goto out;
+ nonce_file = g_hash_table_lookup (key_value_pairs, "noncefile");
+ if (nonce_file == NULL)
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_ARGUMENT,
+ _("Error in address `%s' - the noncefile attribute is missing or malformed"),
+ address_entry);
+ goto out;
+ }
}
- /* TODO: deal with family? */
+ /* TODO: deal with family */
connectable = g_network_address_new (host, port);
}
else
@@ -167,12 +600,12 @@ g_dbus_address_connect (const gchar *address_entry,
connectable,
cancellable,
error);
- if (connection != NULL)
- {
- ret = G_IO_STREAM (connection);
- }
g_object_unref (connectable);
g_object_unref (client);
+ if (connection == NULL)
+ goto out;
+
+ ret = G_IO_STREAM (connection);
if (nonce_file != NULL)
{
@@ -236,70 +669,35 @@ g_dbus_address_try_connect_one (const gchar *address_entry,
GIOStream *ret;
GHashTable *key_value_pairs;
gchar *transport_name;
- gchar **kv_pairs;
- const gchar *s;
- guint n;
+ const gchar *guid;
ret = NULL;
+ transport_name = NULL;
+ key_value_pairs = NULL;
- s = strchr (address_entry, ':');
- if (s == NULL)
- {
- g_set_error (error,
- G_IO_ERROR,
- G_IO_ERROR_INVALID_ARGUMENT,
- _("Address element `%s', does not contain a colon (:)"),
- address_entry);
- goto out;
- }
-
- transport_name = g_strndup (address_entry, s - address_entry);
- key_value_pairs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
-
- kv_pairs = g_strsplit (s + 1, ",", 0);
- for (n = 0; kv_pairs != NULL && kv_pairs[n] != NULL; n++)
- {
- const gchar *kv_pair = kv_pairs[n];
- gchar *key;
- gchar *value;
-
- s = strchr (kv_pair, '=');
- if (s == NULL)
- {
- g_set_error (error,
- G_IO_ERROR,
- G_IO_ERROR_INVALID_ARGUMENT,
- _("Key/Value pair %d, `%s', in address element `%s', does not contain an equal sign"),
- n,
- kv_pair,
- address_entry);
- goto out;
- }
-
- /* TODO: actually validate that no illegal characters are present before and after then '=' sign */
- key = g_uri_unescape_segment (kv_pair, s, NULL);
- value = g_uri_unescape_segment (s + 1, kv_pair + strlen (kv_pair), NULL);
- g_hash_table_insert (key_value_pairs, key, value);
- }
+ if (!_g_dbus_address_parse_entry (address_entry,
+ &transport_name,
+ &key_value_pairs,
+ error))
+ goto out;
ret = g_dbus_address_connect (address_entry,
transport_name,
key_value_pairs,
cancellable,
error);
- if (ret != NULL)
- {
- const gchar *guid;
- /* TODO: validate that guid is of correct format */
- guid = g_hash_table_lookup (key_value_pairs, "guid");
- if (guid != NULL && out_guid != NULL)
- *out_guid = g_strdup (guid);
- }
+ if (ret == NULL)
+ goto out;
+
+ /* TODO: validate that guid is of correct format */
+ guid = g_hash_table_lookup (key_value_pairs, "guid");
+ if (guid != NULL && out_guid != NULL)
+ *out_guid = g_strdup (guid);
out:
- g_strfreev (kv_pairs);
g_free (transport_name);
- g_hash_table_unref (key_value_pairs);
+ if (key_value_pairs != NULL)
+ g_hash_table_unref (key_value_pairs);
return ret;
}
diff --git a/gdbus/gdbusaddress.h b/gdbus/gdbusaddress.h
index bdb9b5d..7a1bd48 100644
--- a/gdbus/gdbusaddress.h
+++ b/gdbus/gdbusaddress.h
@@ -31,6 +31,10 @@
G_BEGIN_DECLS
+gboolean g_dbus_is_address (const gchar *string);
+gboolean g_dbus_is_supported_address (const gchar *string,
+ GError **error);
+
void g_dbus_address_get_stream (const gchar *address,
GCancellable *cancellable,
GAsyncReadyCallback callback,
diff --git a/gdbus/gdbusenums.h b/gdbus/gdbusenums.h
index a2ede8d..11f681d 100644
--- a/gdbus/gdbusenums.h
+++ b/gdbus/gdbusenums.h
@@ -387,6 +387,24 @@ typedef enum
G_DBUS_SUBTREE_FLAGS_DISPATCH_TO_UNENUMERATED_NODES = (1<<0),
} GDBusSubtreeFlags;
+/**
+ * GDBusServerFlags:
+ * @G_DBUS_SERVER_FLAGS_NONE: No flags set.
+ * @G_DBUS_SERVER_FLAGS_RUN_IN_THREAD: All #GDBusServer::new-connection
+ * signals will run in separated dedicated threads (see signal for
+ * details).
+ * @G_DBUS_SERVER_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS: Allow the anonymous
+ * authentication method.
+ *
+ * Flags used when creating a #GDBusServer.
+ */
+typedef enum
+{
+ G_DBUS_SERVER_FLAGS_NONE = 0,
+ G_DBUS_SERVER_FLAGS_RUN_IN_THREAD = (1<<0),
+ G_DBUS_SERVER_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS = (1<<1)
+} GDBusServerFlags;
+
G_END_DECLS
#endif /* __G_DBUS_ENUMS_H__ */
diff --git a/gdbus/gdbusprivate.h b/gdbus/gdbusprivate.h
index 6050169..becad23 100644
--- a/gdbus/gdbusprivate.h
+++ b/gdbus/gdbusprivate.h
@@ -62,8 +62,15 @@ void _g_dbus_worker_send_message (GDBusWorker *worker,
/* can be called from any thread */
void _g_dbus_worker_stop (GDBusWorker *worker);
+/* ---------------------------------------------------------------------------------------------------- */
+
void _g_dbus_initialize (void);
+gboolean _g_dbus_address_parse_entry (const gchar *address_entry,
+ gchar **out_transport_name,
+ GHashTable **out_key_value_pairs,
+ GError **error);
+
/* ---------------------------------------------------------------------------------------------------- */
G_END_DECLS
diff --git a/gdbus/gdbusserver.c b/gdbus/gdbusserver.c
new file mode 100644
index 0000000..5acd46b
--- /dev/null
+++ b/gdbus/gdbusserver.c
@@ -0,0 +1,890 @@
+/* GDBus - GLib D-Bus Library
+ *
+ * Copyright (C) 2008-2009 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz@redhat.com>
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <glib/gi18n.h>
+#include <unistd.h>
+#include <errno.h>
+
+#ifdef G_OS_UNIX
+#include <gio/gunixsocketaddress.h>
+#endif
+
+#include "gdbustypes.h"
+#include "gdbusaddress.h"
+#include "gdbusutils.h"
+#include "gdbusconnection.h"
+#include "gdbusserver.h"
+#include "gdbusenumtypes.h"
+#include "gdbus-marshal.h"
+#include "gdbusprivate.h"
+
+/**
+ * SECTION:gdbusserver
+ * @short_description: Helper for accepting connections
+ * @include: gdbus/gdbus.h
+ *
+ * #GDBusServer is a helper for listening to and accepting D-Bus
+ * connections.
+ */
+
+struct _GDBusServerPrivate
+{
+ GDBusServerFlags flags;
+ gchar *address;
+ gchar *guid;
+
+ guchar *nonce;
+ gchar *nonce_file;
+
+ gchar *client_address;
+
+ GSocketListener *listener;
+ gboolean is_using_listener;
+
+ /* The result of g_main_context_get_thread_default() when the object
+ * was created (the GObject _init() function) - this is used for delivery
+ * of the :new-connection GObject signal.
+ */
+ GMainContext *main_context_at_construction;
+};
+
+enum
+{
+ PROP_0,
+ PROP_ADDRESS,
+ PROP_CLIENT_ADDRESS,
+ PROP_FLAGS,
+ PROP_GUID,
+};
+
+enum
+{
+ NEW_CONNECTION_SIGNAL,
+ LAST_SIGNAL,
+};
+
+guint _signals[LAST_SIGNAL] = {0};
+
+static void initable_iface_init (GInitableIface *initable_iface);
+
+G_DEFINE_TYPE_WITH_CODE (GDBusServer, g_dbus_server, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initable_iface_init)
+ );
+
+static void
+g_dbus_server_finalize (GObject *object)
+{
+ GDBusServer *server = G_DBUS_SERVER (object);
+
+ if (server->priv->listener != NULL)
+ g_object_unref (server->priv->listener);
+
+ g_free (server->priv->address);
+ g_free (server->priv->guid);
+ g_free (server->priv->client_address);
+ if (server->priv->nonce != NULL)
+ {
+ memset (server->priv->nonce, '\0', 16);
+ g_free (server->priv->nonce);
+ }
+ /* we could unlink the nonce file but I don't
+ * think it's really worth the effort/risk
+ */
+ g_free (server->priv->nonce_file);
+
+ if (server->priv->main_context_at_construction != NULL)
+ g_main_context_unref (server->priv->main_context_at_construction);
+
+ if (G_OBJECT_CLASS (g_dbus_server_parent_class)->finalize != NULL)
+ G_OBJECT_CLASS (g_dbus_server_parent_class)->finalize (object);
+}
+
+static void
+g_dbus_server_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GDBusServer *server = G_DBUS_SERVER (object);
+
+ switch (prop_id)
+ {
+ case PROP_FLAGS:
+ g_value_set_flags (value, server->priv->flags);
+ break;
+
+ case PROP_GUID:
+ g_value_set_string (value, server->priv->guid);
+ break;
+
+ case PROP_ADDRESS:
+ g_value_set_string (value, server->priv->address);
+ break;
+
+ case PROP_CLIENT_ADDRESS:
+ g_value_set_string (value, server->priv->client_address);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+g_dbus_server_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GDBusServer *server = G_DBUS_SERVER (object);
+
+ switch (prop_id)
+ {
+ case PROP_FLAGS:
+ server->priv->flags = g_value_get_flags (value);
+ break;
+
+ case PROP_GUID:
+ server->priv->guid = g_value_dup_string (value);
+ break;
+
+ case PROP_ADDRESS:
+ server->priv->address = g_value_dup_string (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+g_dbus_server_class_init (GDBusServerClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->finalize = g_dbus_server_finalize;
+ gobject_class->set_property = g_dbus_server_set_property;
+ gobject_class->get_property = g_dbus_server_get_property;
+
+ /**
+ * GDBusServer:flags:
+ *
+ * Flags from the #GDBusServerFlags enumeration.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_FLAGS,
+ g_param_spec_flags ("flags",
+ _("Flags"),
+ _("Flags for the server"),
+ G_TYPE_DBUS_SERVER_FLAGS,
+ G_DBUS_SERVER_FLAGS_NONE,
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_BLURB |
+ G_PARAM_STATIC_NICK));
+
+ /**
+ * GDBusServer:guid:
+ *
+ * The guid of the server.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_GUID,
+ g_param_spec_string ("guid",
+ _("GUID"),
+ _("The guid of the server"),
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_BLURB |
+ G_PARAM_STATIC_NICK));
+
+ /**
+ * GDBusServer:address:
+ *
+ * The D-Bus address to listen on.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_ADDRESS,
+ g_param_spec_string ("address",
+ _("Address"),
+ _("The address to listen on"),
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_BLURB |
+ G_PARAM_STATIC_NICK));
+
+ /**
+ * GDBusServer:client-address:
+ *
+ * The D-Bus address that clients can use.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_CLIENT_ADDRESS,
+ g_param_spec_string ("client-address",
+ _("Client Address"),
+ _("The address clients can use"),
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_BLURB |
+ G_PARAM_STATIC_NICK));
+
+ /**
+ * GDBusServer::new-connection:
+ * @server: The #GDBusServer emitting the signal.
+ * @connection: A #GDBusConnection for the new connection.
+ *
+ * Emitted when a new authenticated connection has been made.
+ *
+ * If you want to accept the connection, simply ref the @connection
+ * object and call g_dbus_connection_close() + unref it when you are
+ * done with it.
+ *
+ * If #GDBusServer:flags contains %G_DBUS_SERVER_FLAGS_RUN_IN_THREAD
+ * then the signal is emitted in a new thread dedicated to the
+ * connection. Otherwise the signal is emitted in the <link
+ * linkend="g-main-context-push-thread-default">thread-default main
+ * loop</link> of the thread where @server was constructed in.
+ */
+ _signals[NEW_CONNECTION_SIGNAL] = g_signal_new ("new-connection",
+ G_TYPE_DBUS_SERVER,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GDBusServerClass, new_connection),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_DBUS_CONNECTION);
+
+
+ g_type_class_add_private (klass, sizeof (GDBusServerPrivate));
+}
+
+static void
+g_dbus_server_init (GDBusServer *server)
+{
+ server->priv = G_TYPE_INSTANCE_GET_PRIVATE (server, G_TYPE_DBUS_SERVER, GDBusServerPrivate);
+
+ server->priv->main_context_at_construction = g_main_context_get_thread_default ();
+ if (server->priv->main_context_at_construction != NULL)
+ g_main_context_ref (server->priv->main_context_at_construction);
+}
+
+static gboolean
+on_run (GSocketService *service,
+ GSocketConnection *socket_connection,
+ GObject *source_object,
+ gpointer user_data);
+
+/**
+ * g_dbus_server_new_sync:
+ * @address: A D-Bus address.
+ * @flags: Flags from the #GDBusServerFlags enumeration.
+ * @guid: A D-Bus GUID.
+ * @cancellable: A #GCancellable or %NULL.
+ * @error: Return location for server or %NULL.
+ *
+ * Creates a new D-Bus server that listens on the first address in
+ * @address that works.
+ *
+ * Once constructed, you can use g_dbus_server_get_client_address() to
+ * get a D-Bus address string that clients can use to connect.
+ *
+ * Connect to the #GDBusServer::new-connection signal to handle
+ * incoming connections.
+ *
+ * This is a synchronous failable constructor. See
+ * g_dbus_server_new() for the asynchronous version.
+ *
+ * Returns: A #GDBusServer or %NULL if @error is set. Free with
+ * g_object_unref().
+ */
+GDBusServer *
+g_dbus_server_new_sync (const gchar *address,
+ GDBusServerFlags flags,
+ const gchar *guid,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GDBusServer *server;
+
+ g_return_val_if_fail (address != NULL, NULL);
+ g_return_val_if_fail (g_dbus_is_guid (guid), NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ server = g_initable_new (G_TYPE_DBUS_SERVER,
+ cancellable,
+ error,
+ "address", address,
+ "flags", flags,
+ "guid", guid,
+ NULL);
+ if (server != NULL)
+ {
+ /* Right now we don't have any transport not using the listener... */
+ g_assert (server->priv->is_using_listener);
+ g_socket_service_start (G_SOCKET_SERVICE (server->priv->listener));
+ g_signal_connect (G_SOCKET_SERVICE (server->priv->listener),
+ "run",
+ G_CALLBACK (on_run),
+ server);
+ }
+
+ return server;
+}
+
+/**
+ * g_dbus_server_get_client_address:
+ * @server: A #GDBusServer.
+ *
+ * Gets a D-Bus address string that can be used by clients to connect
+ * to @server.
+ *
+ * Returns: A D-Bus address string. Do not free, the string is owned
+ * by @server.
+ */
+const gchar *
+g_dbus_server_get_client_address (GDBusServer *server)
+{
+ g_return_val_if_fail (G_IS_DBUS_SERVER (server), NULL);
+ return server->priv->client_address;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+#ifdef G_OS_UNIX
+
+static gint
+random_ascii (void)
+{
+ gint ret;
+ ret = g_random_int_range (0, 60);
+ if (ret < 25)
+ ret += 'A';
+ else if (ret < 50)
+ ret += 'a' - 25;
+ else
+ ret += '0' - 50;
+ return ret;
+}
+
+/* note that address_entry has already been validated => exactly one of path, tmpdir or abstract keys are set */
+static gboolean
+try_unix (GDBusServer *server,
+ const gchar *address_entry,
+ GHashTable *key_value_pairs,
+ GError **error)
+{
+ gboolean ret;
+ const gchar *path;
+ const gchar *tmpdir;
+ const gchar *abstract;
+ GSocketAddress *address;
+
+ ret = FALSE;
+ address = NULL;
+
+ path = g_hash_table_lookup (key_value_pairs, "path");
+ tmpdir = g_hash_table_lookup (key_value_pairs, "tmpdir");
+ abstract = g_hash_table_lookup (key_value_pairs, "abstract");
+
+ if (path != NULL)
+ {
+ address = g_unix_socket_address_new (path);
+ }
+ else if (tmpdir != NULL)
+ {
+ gint n;
+ GString *s;
+ GError *local_error;
+
+ retry:
+ s = g_string_new (tmpdir);
+ g_string_append (s, "/dbus-");
+ for (n = 0; n < 8; n++)
+ g_string_append_c (s, random_ascii ());
+
+ /* prefer abstract namespace if available */
+ if (g_unix_socket_address_abstract_names_supported ())
+ address = g_unix_socket_address_new_with_type (s->str,
+ -1,
+ G_UNIX_SOCKET_ADDRESS_ABSTRACT);
+ else
+ address = g_unix_socket_address_new (s->str);
+ g_string_free (s, TRUE);
+
+ local_error = NULL;
+ if (!g_socket_listener_add_address (server->priv->listener,
+ address,
+ G_SOCKET_TYPE_STREAM,
+ G_SOCKET_PROTOCOL_DEFAULT,
+ NULL, /* source_object */
+ NULL, /* effective_address */
+ &local_error))
+ {
+ if (local_error->domain == G_IO_ERROR && local_error->code == G_IO_ERROR_ADDRESS_IN_USE)
+ {
+ g_error_free (local_error);
+ goto retry;
+ }
+ g_propagate_error (error, local_error);
+ goto out;
+ }
+ ret = TRUE;
+ goto out;
+ }
+ else if (abstract != NULL)
+ {
+ if (!g_unix_socket_address_abstract_names_supported ())
+ {
+ g_set_error_literal (error,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ _("Abstract name space not supported"));
+ goto out;
+ }
+ address = g_unix_socket_address_new_with_type (abstract,
+ -1,
+ G_UNIX_SOCKET_ADDRESS_ABSTRACT);
+ }
+ else
+ {
+ g_assert_not_reached ();
+ }
+
+ if (!g_socket_listener_add_address (server->priv->listener,
+ address,
+ G_SOCKET_TYPE_STREAM,
+ G_SOCKET_PROTOCOL_DEFAULT,
+ NULL, /* source_object */
+ NULL, /* effective_address */
+ error))
+ goto out;
+
+ ret = TRUE;
+
+ out:
+
+ if (address != NULL)
+ {
+ /* Fill out client_address if the connection attempt worked */
+ if (ret)
+ {
+ server->priv->is_using_listener = TRUE;
+
+ switch (g_unix_socket_address_get_address_type (G_UNIX_SOCKET_ADDRESS (address)))
+ {
+ case G_UNIX_SOCKET_ADDRESS_ABSTRACT:
+ server->priv->client_address = g_strdup_printf ("unix:abstract=%s",
+ g_unix_socket_address_get_path (G_UNIX_SOCKET_ADDRESS (address)));
+ break;
+
+ case G_UNIX_SOCKET_ADDRESS_PATH:
+ server->priv->client_address = g_strdup_printf ("unix:path=%s",
+ g_unix_socket_address_get_path (G_UNIX_SOCKET_ADDRESS (address)));
+ break;
+
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ }
+ g_object_unref (address);
+ }
+ return ret;
+}
+#endif
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+/* note that address_entry has already been validated =>
+ * both host and port (guranteed to be a number in [0, 65535]) are set (family is optional)
+ */
+static gboolean
+try_tcp (GDBusServer *server,
+ const gchar *address_entry,
+ GHashTable *key_value_pairs,
+ gboolean do_nonce,
+ GError **error)
+{
+ gboolean ret;
+ const gchar *host;
+ const gchar *port;
+ const gchar *family;
+ gint port_num;
+ GSocketAddress *address;
+ GResolver *resolver;
+ GList *resolved_addresses;
+ GList *l;
+
+ ret = FALSE;
+ address = NULL;
+ resolver = NULL;
+ resolved_addresses = NULL;
+
+ host = g_hash_table_lookup (key_value_pairs, "host");
+ port = g_hash_table_lookup (key_value_pairs, "port");
+ family = g_hash_table_lookup (key_value_pairs, "family");
+ if (g_hash_table_lookup (key_value_pairs, "noncefile") != NULL)
+ {
+ g_set_error_literal (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_ARGUMENT,
+ _("Cannot specify nonce file when creating a server"));
+ goto out;
+ }
+
+ if (host == NULL)
+ host = "localhost";
+ if (port == NULL)
+ port = "0";
+ port_num = strtol (port, NULL, 10);
+
+ resolver = g_resolver_get_default ();
+ resolved_addresses = g_resolver_lookup_by_name (resolver,
+ host,
+ NULL,
+ error);
+ if (resolved_addresses == NULL)
+ {
+ goto out;
+ }
+ /* TODO: handle family */
+ for (l = resolved_addresses; l != NULL; l = l->next)
+ {
+ GInetAddress *address = G_INET_ADDRESS (l->data);
+ GSocketAddress *socket_address;
+ GSocketAddress *effective_address;
+
+ socket_address = g_inet_socket_address_new (address, port_num);
+ if (!g_socket_listener_add_address (server->priv->listener,
+ socket_address,
+ G_SOCKET_TYPE_STREAM,
+ G_SOCKET_PROTOCOL_TCP,
+ NULL, /* GObject *source_object */
+ &effective_address,
+ error))
+ {
+ g_object_unref (socket_address);
+ goto out;
+ }
+ if (port_num == 0)
+ {
+ /* make sure we allocate the same port number for other listeners */
+ port_num = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (effective_address));
+ }
+ g_object_unref (effective_address);
+ g_object_unref (socket_address);
+ }
+
+ if (do_nonce)
+ {
+ gint fd;
+ guint n;
+ gsize bytes_written;
+ gsize bytes_remaining;
+
+ server->priv->nonce = g_new0 (guchar, 16);
+ for (n = 0; n < 16; n++)
+ server->priv->nonce[n] = g_random_int_range (0, 256);
+ fd = g_file_open_tmp ("gdbus-nonce-file-XXXXXX",
+ &server->priv->nonce_file,
+ error);
+ if (fd == -1)
+ {
+ g_socket_listener_close (server->priv->listener);
+ goto out;
+ }
+ again:
+ bytes_written = 0;
+ bytes_remaining = 16;
+ while (bytes_remaining > 0)
+ {
+ gssize ret;
+ ret = write (fd, server->priv->nonce + bytes_written, bytes_remaining);
+ if (ret == -1)
+ {
+ if (errno == EINTR)
+ goto again;
+ g_set_error (error,
+ G_IO_ERROR,
+ g_io_error_from_errno (errno),
+ _("Error writing nonce file at `%s': %s"),
+ server->priv->nonce_file,
+ strerror (errno));
+ goto out;
+ }
+ bytes_written += ret;
+ bytes_remaining -= ret;
+ }
+ close (fd);
+ server->priv->client_address = g_strdup_printf ("nonce-tcp:host=%s,port=%d,noncefile=%s",
+ host,
+ port_num,
+ server->priv->nonce_file);
+ }
+ else
+ {
+ server->priv->client_address = g_strdup_printf ("tcp:host=%s,port=%d", host, port_num);
+ }
+ server->priv->is_using_listener = TRUE;
+ ret = TRUE;
+
+ out:
+ g_list_foreach (resolved_addresses, (GFunc) g_object_unref, NULL);
+ g_list_free (resolved_addresses);
+ g_object_unref (resolver);
+ return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+typedef struct
+{
+ GDBusServer *server;
+ GDBusConnection *connection;
+} EmitIdleData;
+
+static void
+emit_idle_data_free (EmitIdleData *data)
+{
+ g_object_unref (data->server);
+ g_object_unref (data->connection);
+ g_free (data);
+}
+
+static gboolean
+emit_new_connection_in_idle (gpointer user_data)
+{
+ EmitIdleData *data = user_data;
+
+ g_signal_emit (data->server,
+ _signals[NEW_CONNECTION_SIGNAL],
+ 0,
+ data->connection);
+ g_object_unref (data->connection);
+
+ return FALSE;
+}
+
+/* Called in new thread */
+static gboolean
+on_run (GSocketService *service,
+ GSocketConnection *socket_connection,
+ GObject *source_object,
+ gpointer user_data)
+{
+ GDBusServer *server = G_DBUS_SERVER (user_data);
+ GDBusConnection *connection;
+ GDBusConnectionFlags connection_flags;
+
+ if (server->priv->nonce != NULL)
+ {
+ gchar buf[16];
+ gsize bytes_read;
+
+ if (!g_input_stream_read_all (g_io_stream_get_input_stream (G_IO_STREAM (socket_connection)),
+ buf,
+ 16,
+ &bytes_read,
+ NULL, /* GCancellable */
+ NULL)) /* GError */
+ goto out;
+
+ if (bytes_read != 16)
+ goto out;
+
+ if (memcmp (buf, server->priv->nonce, 16) != 0)
+ goto out;
+ }
+
+ connection_flags = G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER;
+ if (server->priv->flags & G_DBUS_SERVER_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS)
+ connection_flags |= G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS;
+
+ connection = g_dbus_connection_new_sync (G_IO_STREAM (socket_connection),
+ server->priv->guid,
+ connection_flags,
+ NULL, /* GCancellable */
+ NULL); /* GError */
+ if (connection == NULL)
+ goto out;
+
+ if (server->priv->flags & G_DBUS_SERVER_FLAGS_RUN_IN_THREAD)
+ {
+ g_signal_emit (server,
+ _signals[NEW_CONNECTION_SIGNAL],
+ 0,
+ connection);
+ g_object_unref (connection);
+ }
+ else
+ {
+ GSource *idle_source;
+ EmitIdleData *data;
+
+ data = g_new0 (EmitIdleData, 1);
+ data->server = g_object_ref (server);
+ data->connection = g_object_ref (connection);
+
+ idle_source = g_idle_source_new ();
+ g_source_set_priority (idle_source, G_PRIORITY_DEFAULT);
+ g_source_set_callback (idle_source,
+ emit_new_connection_in_idle,
+ data,
+ (GDestroyNotify) emit_idle_data_free);
+ g_source_attach (idle_source, server->priv->main_context_at_construction);
+ g_source_unref (idle_source);
+ }
+
+ out:
+ return TRUE;
+}
+
+static gboolean
+initable_init (GInitable *initable,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GDBusServer *server = G_DBUS_SERVER (initable);
+ gboolean ret;
+ guint n;
+ gchar **addr_array;
+ GError *last_error;
+
+ ret = FALSE;
+ last_error = NULL;
+
+ if (!g_dbus_is_guid (server->priv->guid))
+ {
+ g_set_error (&last_error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_ARGUMENT,
+ _("The string `%s' is not a valid D-Bus GUID"),
+ server->priv->guid);
+ goto out;
+ }
+
+ server->priv->listener = G_SOCKET_LISTENER (g_threaded_socket_service_new (-1));
+
+ addr_array = g_strsplit (server->priv->address, ";", 0);
+ last_error = NULL;
+ for (n = 0; addr_array != NULL && addr_array[n] != NULL; n++)
+ {
+ const gchar *address_entry = addr_array[n];
+ GHashTable *key_value_pairs;
+ gchar *transport_name;
+ GError *this_error;
+
+ this_error = NULL;
+ if (g_dbus_is_supported_address (address_entry,
+ &this_error) &&
+ _g_dbus_address_parse_entry (address_entry,
+ &transport_name,
+ &key_value_pairs,
+ &this_error))
+ {
+
+ if (FALSE)
+ {
+ }
+#ifdef G_OS_UNIX
+ else if (g_strcmp0 (transport_name, "unix") == 0)
+ {
+ ret = try_unix (server, address_entry, key_value_pairs, &this_error);
+ }
+#endif
+ else if (g_strcmp0 (transport_name, "tcp") == 0)
+ {
+ ret = try_tcp (server, address_entry, key_value_pairs, FALSE, &this_error);
+ }
+ else if (g_strcmp0 (transport_name, "nonce-tcp") == 0)
+ {
+ ret = try_tcp (server, address_entry, key_value_pairs, TRUE, &this_error);
+ }
+ else
+ {
+ g_set_error (&this_error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_ARGUMENT,
+ _("Cannot listen on unsupported transport `%s'"),
+ transport_name);
+ }
+
+ g_free (transport_name);
+ if (key_value_pairs != NULL)
+ g_hash_table_unref (key_value_pairs);
+
+ if (ret)
+ {
+ g_assert (this_error == NULL);
+ goto out;
+ }
+ }
+
+ if (this_error != NULL)
+ {
+ if (last_error != NULL)
+ g_error_free (last_error);
+ last_error = this_error;
+ }
+ }
+
+ if (!ret)
+ goto out;
+
+ out:
+ if (ret)
+ {
+ if (last_error != NULL)
+ g_error_free (last_error);
+ }
+ else
+ {
+ g_assert (last_error != NULL);
+ g_propagate_error (error, last_error);
+ }
+ return ret;
+}
+
+
+static void
+initable_iface_init (GInitableIface *initable_iface)
+{
+ initable_iface->init = initable_init;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
diff --git a/gdbus/gdbusserver.h b/gdbus/gdbusserver.h
new file mode 100644
index 0000000..18b9e26
--- /dev/null
+++ b/gdbus/gdbusserver.h
@@ -0,0 +1,95 @@
+/* GDBus - GLib D-Bus Library
+ *
+ * Copyright (C) 2008-2009 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz@redhat.com>
+ */
+
+#if !defined (__G_DBUS_G_DBUS_H_INSIDE__) && !defined (G_DBUS_COMPILATION)
+#error "Only <gdbus/gdbus.h> can be included directly."
+#endif
+
+#ifndef __G_DBUS_SERVER_H__
+#define __G_DBUS_SERVER_H__
+
+#include <gdbus/gdbustypes.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_DBUS_SERVER (g_dbus_server_get_type ())
+#define G_DBUS_SERVER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_DBUS_SERVER, GDBusServer))
+#define G_DBUS_SERVER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_DBUS_SERVER, GDBusServerClass))
+#define G_DBUS_SERVER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_DBUS_SERVER, GDBusServerClass))
+#define G_IS_DBUS_SERVER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_DBUS_SERVER))
+#define G_IS_DBUS_SERVER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_DBUS_SERVER))
+
+typedef struct _GDBusServerClass GDBusServerClass;
+typedef struct _GDBusServerPrivate GDBusServerPrivate;
+
+/**
+ * GDBusServer:
+ *
+ * The #GDBusServer structure contains only private data and
+ * should only be accessed using the provided API.
+ */
+struct _GDBusServer
+{
+ /*< private >*/
+ GObject parent_instance;
+ GDBusServerPrivate *priv;
+};
+
+/**
+ * GDBusServerClass:
+ * @new_connection: Signal class handler for the #GDBusServer::new-connection signal.
+ *
+ * Class structure for #GDBusServer.
+ */
+struct _GDBusServerClass
+{
+ /*< private >*/
+ GObjectClass parent_class;
+
+ /*< public >*/
+ /* Signals */
+ void (*new_connection) (GDBusServer *server,
+ GDBusConnection *connection);
+
+ /*< private >*/
+ /* Padding for future expansion */
+ void (*_g_reserved1) (void);
+ void (*_g_reserved2) (void);
+ void (*_g_reserved3) (void);
+ void (*_g_reserved4) (void);
+ void (*_g_reserved5) (void);
+ void (*_g_reserved6) (void);
+ void (*_g_reserved7) (void);
+ void (*_g_reserved8) (void);
+};
+
+GType g_dbus_server_get_type (void) G_GNUC_CONST;
+GDBusServer *g_dbus_server_new_sync (const gchar *address,
+ GDBusServerFlags flags,
+ const gchar *guid,
+ GCancellable *cancellable,
+ GError **error);
+const gchar *g_dbus_server_get_client_address (GDBusServer *server);
+
+G_END_DECLS
+
+#endif /* __G_DBUS_SERVER_H__ */
diff --git a/gdbus/gdbustypes.h b/gdbus/gdbustypes.h
index 95b1c14..738954f 100644
--- a/gdbus/gdbustypes.h
+++ b/gdbus/gdbustypes.h
@@ -36,6 +36,7 @@ typedef struct _GDBusConnection GDBusConnection;
typedef struct _GMessageBusConnection GMessageBusConnection;
typedef struct _GDBusProxy GDBusProxy;
typedef struct _GDBusMethodInvocation GDBusMethodInvocation;
+typedef struct _GDBusServer GDBusServer;
typedef struct _GDBusErrorEntry GDBusErrorEntry;
diff --git a/gdbus/tests/addresses.c b/gdbus/tests/addresses.c
index 6797653..37cd049 100644
--- a/gdbus/tests/addresses.c
+++ b/gdbus/tests/addresses.c
@@ -28,62 +28,41 @@
/* ---------------------------------------------------------------------------------------------------- */
-#if 0 //#ifdef G_OS_UNIX
+#ifdef G_OS_UNIX
static void
test_unix_address (void)
{
- GSocketConnectable *a;
- GSocketAddressEnumerator *e;
- GSocketAddress *addr;
- GError *error;
-
- error = NULL;
- a = g_dbus_address_new ("unix:path=/tmp/dbus-test", &error);
- g_assert_no_error (error);
- g_assert (a != NULL);
- g_object_unref (a);
-
- error = NULL;
- a = g_dbus_address_new ("unix:abstract=/tmp/dbus-another-test", &error);
- g_assert_no_error (error);
- g_assert (a != NULL);
- g_object_unref (a);
+ g_assert (!g_dbus_is_supported_address ("some-imaginary-transport:foo=bar", NULL));
+ g_assert (g_dbus_is_supported_address ("unix:path=/tmp/dbus-test", NULL));
+ g_assert (g_dbus_is_supported_address ("unix:abstract=/tmp/dbus-another-test", NULL));
+ g_assert (g_dbus_is_address ("unix:foo=bar"));
+ g_assert (!g_dbus_is_supported_address ("unix:foo=bar", NULL));
+ g_assert (!g_dbus_is_address ("unix:path=/foo;abstract=/bar"));
+ g_assert (!g_dbus_is_supported_address ("unix:path=/foo;abstract=/bar", NULL));
+ g_assert (g_dbus_is_supported_address ("unix:path=/tmp/concrete;unix:abstract=/tmp/abstract", NULL));
+ g_assert (g_dbus_is_address ("some-imaginary-transport:foo=bar"));
- error = NULL;
- a = g_dbus_address_new ("unix:foo=bar", &error);
- g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_BAD_ADDRESS);
- g_assert (a == NULL);
+ g_assert (g_dbus_is_address ("some-imaginary-transport:foo=bar;unix:path=/this/is/valid"));
+ g_assert (!g_dbus_is_supported_address ("some-imaginary-transport:foo=bar;unix:path=/this/is/valid", NULL));
+}
+#endif
- error = NULL;
- a = g_dbus_address_new ("unix:path=/foo;abstract=/bar", &error);
- g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_BAD_ADDRESS);
- g_assert (a == NULL);
+static void
+test_nonce_tcp_address (void)
+{
+ g_assert (g_dbus_is_supported_address ("nonce-tcp:host=localhost,port=42,noncefile=/foo/bar", NULL));
+ g_assert (g_dbus_is_supported_address ("nonce-tcp:host=localhost,port=42,noncefile=/foo/bar,family=ipv6", NULL));
+ g_assert (g_dbus_is_supported_address ("nonce-tcp:host=localhost,port=42,noncefile=/foo/bar,family=ipv4", NULL));
- error = NULL;
- a = g_dbus_address_new ("unix:path=/tmp/concrete;unix:abstract=/tmp/abstract", &error);
- g_assert_no_error (error);
- g_assert (a != NULL);
- e = g_socket_connectable_enumerate (a);
- g_assert (e != NULL);
- addr = g_socket_address_enumerator_next (e, NULL, &error);
- g_assert_no_error (error);
- g_assert (G_IS_UNIX_SOCKET_ADDRESS (addr));
- g_assert (!g_unix_socket_address_get_is_abstract (G_UNIX_SOCKET_ADDRESS (addr)));
- g_assert_cmpstr (g_unix_socket_address_get_path (G_UNIX_SOCKET_ADDRESS (addr)), ==, "/tmp/concrete");
- g_object_unref (addr);
- addr = g_socket_address_enumerator_next (e, NULL, &error);
- g_assert_no_error (error);
- g_assert (G_IS_UNIX_SOCKET_ADDRESS (addr));
- g_assert (g_unix_socket_address_get_is_abstract (G_UNIX_SOCKET_ADDRESS (addr)));
- g_assert_cmpstr (g_unix_socket_address_get_path (G_UNIX_SOCKET_ADDRESS (addr)), ==, "/tmp/abstract");
- g_object_unref (addr);
- addr = g_socket_address_enumerator_next (e, NULL, &error);
- g_assert_no_error (error);
- g_assert (addr == NULL);
- g_object_unref (e);
- g_object_unref (a);
+ g_assert (!g_dbus_is_supported_address ("nonce-tcp:host=localhost,port=42", NULL));
+ g_assert (!g_dbus_is_supported_address ("nonce-tcp:host=localhost,port=42,noncefile=/foo/bar,family=blah", NULL));
+ g_assert (!g_dbus_is_supported_address ("nonce-tcp:host=localhost,port=420000,noncefile=/foo/bar,family=ipv4", NULL));
+ g_assert (!g_dbus_is_supported_address ("nonce-tcp:host=,port=x42,noncefile=/foo/bar,family=ipv4", NULL));
+ g_assert (!g_dbus_is_supported_address ("nonce-tcp:host=,port=42x,noncefile=/foo/bar,family=ipv4", NULL));
+ g_assert (!g_dbus_is_supported_address ("nonce-tcp:host=,port=420000,noncefile=/foo/bar,family=ipv4", NULL));
+ g_assert (!g_dbus_is_supported_address ("nonce-tcp:port=42,noncefile=/foo/bar", NULL));
+ g_assert (!g_dbus_is_supported_address ("nonce-tcp:host=localhost,noncefile=/foo/bar", NULL));
}
-#endif
int
main (int argc,
@@ -92,9 +71,10 @@ main (int argc,
g_type_init ();
g_test_init (&argc, &argv, NULL);
-#if 0 //#ifdef G_OS_UNIX
+#ifdef G_OS_UNIX
g_test_add_func ("/gdbus/unix-address", test_unix_address);
#endif
+ g_test_add_func ("/gdbus/nonce-tcp-address", test_nonce_tcp_address);
return g_test_run();
}