X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gio%2Fgdbusserver.c;h=cf821304cecf93ed9435023fb4b5334de91ccd5e;hb=25990eb2b6da94e1d03631eab8a952ef84cb9986;hp=b6bd931cf3be81e7f77af1440bf824c815335a36;hpb=25a8aa5d88d3d4b8ebcf8be42a2adc233dbb104c;p=platform%2Fupstream%2Fglib.git diff --git a/gio/gdbusserver.c b/gio/gdbusserver.c index b6bd931..cf82130 100644 --- a/gio/gdbusserver.c +++ b/gio/gdbusserver.c @@ -13,9 +13,7 @@ * 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. + * Public License along with this library; if not, see . * * Author: David Zeuthen */ @@ -27,6 +25,7 @@ #include #include "giotypes.h" +#include "gioerror.h" #include "gdbusaddress.h" #include "gdbusutils.h" #include "gdbusconnection.h" @@ -34,17 +33,28 @@ #include "gioenumtypes.h" #include "gdbusprivate.h" #include "gdbusauthobserver.h" -#include "gio-marshal.h" #include "ginitable.h" #include "gsocketservice.h" +#include "gthreadedsocketservice.h" +#include "gresolver.h" +#include "glib/gstdio.h" +#include "ginetaddress.h" +#include "ginetsocketaddress.h" +#include "ginputstream.h" +#include "giostream.h" #ifdef G_OS_UNIX #include +#endif +#ifdef G_OS_WIN32 +#include +#endif + +#ifdef G_OS_UNIX #include "gunixsocketaddress.h" #endif #include "glibintl.h" -#include "gioalias.h" /** * SECTION:gdbusserver @@ -52,13 +62,31 @@ * @include: gio/gio.h * * #GDBusServer is a helper for listening to and accepting D-Bus - * connections. + * connections. This can be used to create a new D-Bus server, allowing two + * peers to use the D-Bus protocol for their own specialized communication. + * A server instance provided in this way will not perform message routing or + * implement the org.freedesktop.DBus interface. + * + * To just export an object on a well-known name on a message bus, such as the + * session or system bus, you should instead use g_bus_own_name(). * - * D-Bus peer-to-peer exampleFIXME: MISSING XINCLUDE CONTENT + * An example of peer-to-peer communication with G-DBus can be found + * in [gdbus-example-peer.c](https://git.gnome.org/browse/glib/tree/gio/tests/gdbus-example-peer.c). */ -struct _GDBusServerPrivate +/** + * GDBusServer: + * + * The #GDBusServer structure contains only private data and + * should only be accessed using the provided API. + * + * Since: 2.26 + */ +struct _GDBusServer { + /*< private >*/ + GObject parent_instance; + GDBusServerFlags flags; gchar *address; gchar *guid; @@ -70,8 +98,9 @@ struct _GDBusServerPrivate GSocketListener *listener; gboolean is_using_listener; + gulong run_signal_handler_id; - /* The result of g_main_context_get_thread_default() when the object + /* The result of g_main_context_ref_thread_default() when the object * was created (the GObject _init() function) - this is used for delivery * of the :new-connection GObject signal. */ @@ -82,6 +111,27 @@ struct _GDBusServerPrivate GDBusAuthObserver *authentication_observer; }; +typedef struct _GDBusServerClass GDBusServerClass; + +/** + * GDBusServerClass: + * @new_connection: Signal class handler for the #GDBusServer::new-connection signal. + * + * Class structure for #GDBusServer. + * + * Since: 2.26 + */ +struct _GDBusServerClass +{ + /*< private >*/ + GObjectClass parent_class; + + /*< public >*/ + /* Signals */ + gboolean (*new_connection) (GDBusServer *server, + GDBusConnection *connection); +}; + enum { PROP_0, @@ -99,7 +149,7 @@ enum LAST_SIGNAL, }; -guint _signals[LAST_SIGNAL] = {0}; +static guint _signals[LAST_SIGNAL] = {0}; static void initable_iface_init (GInitableIface *initable_iface); @@ -112,27 +162,29 @@ g_dbus_server_finalize (GObject *object) { GDBusServer *server = G_DBUS_SERVER (object); - if (server->priv->authentication_observer != NULL) - g_object_unref (server->priv->authentication_observer); + if (server->authentication_observer != NULL) + g_object_unref (server->authentication_observer); - if (server->priv->listener != NULL) - g_object_unref (server->priv->listener); + if (server->run_signal_handler_id > 0) + g_signal_handler_disconnect (server->listener, server->run_signal_handler_id); - g_free (server->priv->address); - g_free (server->priv->guid); - g_free (server->priv->client_address); - if (server->priv->nonce != NULL) + if (server->listener != NULL) + g_object_unref (server->listener); + + g_free (server->address); + g_free (server->guid); + g_free (server->client_address); + if (server->nonce != NULL) { - memset (server->priv->nonce, '\0', 16); - g_free (server->priv->nonce); + memset (server->nonce, '\0', 16); + g_free (server->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); + g_free (server->nonce_file); - if (server->priv->main_context_at_construction != NULL) - g_main_context_unref (server->priv->main_context_at_construction); + g_main_context_unref (server->main_context_at_construction); G_OBJECT_CLASS (g_dbus_server_parent_class)->finalize (object); } @@ -148,27 +200,27 @@ g_dbus_server_get_property (GObject *object, switch (prop_id) { case PROP_FLAGS: - g_value_set_flags (value, server->priv->flags); + g_value_set_flags (value, server->flags); break; case PROP_GUID: - g_value_set_string (value, server->priv->guid); + g_value_set_string (value, server->guid); break; case PROP_ADDRESS: - g_value_set_string (value, server->priv->address); + g_value_set_string (value, server->address); break; case PROP_CLIENT_ADDRESS: - g_value_set_string (value, server->priv->client_address); + g_value_set_string (value, server->client_address); break; case PROP_ACTIVE: - g_value_set_boolean (value, server->priv->active); + g_value_set_boolean (value, server->active); break; case PROP_AUTHENTICATION_OBSERVER: - g_value_set_object (value, server->priv->authentication_observer); + g_value_set_object (value, server->authentication_observer); break; default: @@ -188,19 +240,19 @@ g_dbus_server_set_property (GObject *object, switch (prop_id) { case PROP_FLAGS: - server->priv->flags = g_value_get_flags (value); + server->flags = g_value_get_flags (value); break; case PROP_GUID: - server->priv->guid = g_value_dup_string (value); + server->guid = g_value_dup_string (value); break; case PROP_ADDRESS: - server->priv->address = g_value_dup_string (value); + server->address = g_value_dup_string (value); break; case PROP_AUTHENTICATION_OBSERVER: - server->priv->authentication_observer = g_value_dup_object (value); + server->authentication_observer = g_value_dup_object (value); break; default: @@ -306,14 +358,14 @@ g_dbus_server_class_init (GDBusServerClass *klass) */ g_object_class_install_property (gobject_class, PROP_ACTIVE, - g_param_spec_string ("active", - P_("Active"), - P_("Whether the server is currently active"), - NULL, - G_PARAM_READABLE | - G_PARAM_STATIC_NAME | - G_PARAM_STATIC_BLURB | - G_PARAM_STATIC_NICK)); + g_param_spec_boolean ("active", + P_("Active"), + P_("Whether the server is currently active"), + FALSE, + G_PARAM_READABLE | + G_PARAM_STATIC_NAME | + G_PARAM_STATIC_BLURB | + G_PARAM_STATIC_NICK)); /** * GDBusServer:authentication-observer: @@ -344,16 +396,26 @@ g_dbus_server_class_init (GDBusServerClass *klass) * g_dbus_connection_get_peer_credentials() to figure out what * identity (if any), was authenticated. * - * If you want to accept the connection, simply ref the @connection - * object. Then call g_dbus_connection_close() and unref it when you - * are done with it. A typical thing to do when accepting a - * connection is to listen to the #GDBusConnection::closed signal. + * If you want to accept the connection, take a reference to the + * @connection object and return %TRUE. When you are done with the + * connection call g_dbus_connection_close() and give up your + * reference. Note that the other peer may disconnect at any time - + * a typical thing to do when accepting a connection is to listen to + * the #GDBusConnection::closed signal. * * 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 thread-default main - * loop of the thread that @server was constructed in. + * connection. Otherwise the signal is emitted in the + * [thread-default main context][g-main-context-push-thread-default] + * of the thread that @server was constructed in. + * + * You are guaranteed that signal handlers for this signal runs + * before incoming messages on @connection are processed. This means + * that it's suitable to call g_dbus_connection_register_object() or + * similar from the signal handler. + * + * Returns: %TRUE to claim @connection, %FALSE to let other handlers + * run. * * Since: 2.26 */ @@ -361,25 +423,18 @@ g_dbus_server_class_init (GDBusServerClass *klass) G_TYPE_DBUS_SERVER, G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GDBusServerClass, new_connection), + g_signal_accumulator_true_handled, + NULL, /* accu_data */ NULL, - NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, + G_TYPE_BOOLEAN, 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); + server->main_context_at_construction = g_main_context_ref_thread_default (); } static gboolean @@ -393,8 +448,8 @@ on_run (GSocketService *service, * @address: A D-Bus address. * @flags: Flags from the #GDBusServerFlags enumeration. * @guid: A D-Bus GUID. - * @observer: A #GDBusAuthObserver or %NULL. - * @cancellable: A #GCancellable or %NULL. + * @observer: (allow-none): A #GDBusAuthObserver or %NULL. + * @cancellable: (allow-none): A #GCancellable or %NULL. * @error: Return location for server or %NULL. * * Creates a new D-Bus server that listens on the first address in @@ -409,8 +464,7 @@ on_run (GSocketService *service, * The returned #GDBusServer isn't active - you have to start it with * g_dbus_server_start(). * - * See for how #GDBusServer can - * be used. + * #GDBusServer is used in this [example][gdbus-peer-to-peer]. * * This is a synchronous failable constructor. See * g_dbus_server_new() for the asynchronous version. @@ -442,15 +496,6 @@ g_dbus_server_new_sync (const gchar *address, "guid", guid, "authentication-observer", observer, NULL); - if (server != NULL) - { - /* Right now we don't have any transport not using the listener... */ - g_assert (server->priv->is_using_listener); - g_signal_connect (G_SOCKET_SERVICE (server->priv->listener), - "run", - G_CALLBACK (on_run), - server); - } return server; } @@ -471,7 +516,7 @@ 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; + return server->client_address; } /** @@ -488,7 +533,7 @@ const gchar * g_dbus_server_get_guid (GDBusServer *server) { g_return_val_if_fail (G_IS_DBUS_SERVER (server), NULL); - return server->priv->guid; + return server->guid; } /** @@ -505,7 +550,7 @@ GDBusServerFlags g_dbus_server_get_flags (GDBusServer *server) { g_return_val_if_fail (G_IS_DBUS_SERVER (server), G_DBUS_SERVER_FLAGS_NONE); - return server->priv->flags; + return server->flags; } /** @@ -522,7 +567,7 @@ gboolean g_dbus_server_is_active (GDBusServer *server) { g_return_val_if_fail (G_IS_DBUS_SERVER (server), G_DBUS_SERVER_FLAGS_NONE); - return server->priv->active; + return server->active; } /** @@ -537,12 +582,12 @@ void g_dbus_server_start (GDBusServer *server) { g_return_if_fail (G_IS_DBUS_SERVER (server)); - if (server->priv->active) + if (server->active) return; /* 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)); - server->priv->active = TRUE; + g_assert (server->is_using_listener); + g_socket_service_start (G_SOCKET_SERVICE (server->listener)); + server->active = TRUE; g_object_notify (G_OBJECT (server), "active"); } @@ -558,12 +603,15 @@ void g_dbus_server_stop (GDBusServer *server) { g_return_if_fail (G_IS_DBUS_SERVER (server)); - if (!server->priv->active) + if (!server->active) return; /* Right now we don't have any transport not using the listener... */ - g_assert (server->priv->is_using_listener); - g_socket_service_stop (G_SOCKET_SERVICE (server->priv->listener)); - server->priv->active = FALSE; + g_assert (server->is_using_listener); + g_assert (server->run_signal_handler_id > 0); + g_signal_handler_disconnect (server->listener, server->run_signal_handler_id); + server->run_signal_handler_id = 0; + g_socket_service_stop (G_SOCKET_SERVICE (server->listener)); + server->active = FALSE; g_object_notify (G_OBJECT (server), "active"); } @@ -631,7 +679,7 @@ try_unix (GDBusServer *server, g_string_free (s, TRUE); local_error = NULL; - if (!g_socket_listener_add_address (server->priv->listener, + if (!g_socket_listener_add_address (server->listener, address, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_DEFAULT, @@ -669,7 +717,7 @@ try_unix (GDBusServer *server, g_assert_not_reached (); } - if (!g_socket_listener_add_address (server->priv->listener, + if (!g_socket_listener_add_address (server->listener, address, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_DEFAULT, @@ -687,18 +735,18 @@ try_unix (GDBusServer *server, /* Fill out client_address if the connection attempt worked */ if (ret) { - server->priv->is_using_listener = TRUE; + server->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))); + server->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))); + server->client_address = g_strdup_printf ("unix:path=%s", + g_unix_socket_address_get_path (G_UNIX_SOCKET_ADDRESS (address))); break; default: @@ -715,7 +763,7 @@ try_unix (GDBusServer *server, /* ---------------------------------------------------------------------------------------------------- */ /* 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) + * both host and port (guaranteed to be a number in [0, 65535]) are set (family is optional) */ static gboolean try_tcp (GDBusServer *server, @@ -727,21 +775,18 @@ try_tcp (GDBusServer *server, 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"); + /* family = g_hash_table_lookup (key_value_pairs, "family"); */ if (g_hash_table_lookup (key_value_pairs, "noncefile") != NULL) { g_set_error_literal (error, @@ -773,7 +818,7 @@ try_tcp (GDBusServer *server, GSocketAddress *effective_address; socket_address = g_inet_socket_address_new (address, port_num); - if (!g_socket_listener_add_address (server->priv->listener, + if (!g_socket_listener_add_address (server->listener, socket_address, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_TCP, @@ -798,16 +843,17 @@ try_tcp (GDBusServer *server, guint n; gsize bytes_written; gsize bytes_remaining; + char *file_escaped; - server->priv->nonce = g_new0 (guchar, 16); + server->nonce = g_new0 (guchar, 16); for (n = 0; n < 16; n++) - server->priv->nonce[n] = g_random_int_range (0, 256); + server->nonce[n] = g_random_int_range (0, 256); fd = g_file_open_tmp ("gdbus-nonce-file-XXXXXX", - &server->priv->nonce_file, + &server->nonce_file, error); if (fd == -1) { - g_socket_listener_close (server->priv->listener); + g_socket_listener_close (server->listener); goto out; } again: @@ -816,7 +862,7 @@ try_tcp (GDBusServer *server, while (bytes_remaining > 0) { gssize ret; - ret = write (fd, server->priv->nonce + bytes_written, bytes_remaining); + ret = write (fd, server->nonce + bytes_written, bytes_remaining); if (ret == -1) { if (errno == EINTR) @@ -824,31 +870,34 @@ try_tcp (GDBusServer *server, g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno), - _("Error writing nonce file at `%s': %s"), - server->priv->nonce_file, + _("Error writing nonce file at '%s': %s"), + server->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); + if (!g_close (fd, error)) + goto out; + file_escaped = g_uri_escape_string (server->nonce_file, "/\\", FALSE); + server->client_address = g_strdup_printf ("nonce-tcp:host=%s,port=%d,noncefile=%s", + host, + port_num, + file_escaped); + g_free (file_escaped); } else { - server->priv->client_address = g_strdup_printf ("tcp:host=%s,port=%d", host, port_num); + server->client_address = g_strdup_printf ("tcp:host=%s,port=%d", host, port_num); } - server->priv->is_using_listener = TRUE; + server->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); + g_list_free_full (resolved_addresses, g_object_unref); + if (resolver) + g_object_unref (resolver); return ret; } @@ -872,11 +921,17 @@ static gboolean emit_new_connection_in_idle (gpointer user_data) { EmitIdleData *data = user_data; + gboolean claimed; + claimed = FALSE; g_signal_emit (data->server, _signals[NEW_CONNECTION_SIGNAL], 0, - data->connection); + data->connection, + &claimed); + + if (claimed) + g_dbus_connection_start_message_processing (data->connection); g_object_unref (data->connection); return FALSE; @@ -893,7 +948,7 @@ on_run (GSocketService *service, GDBusConnection *connection; GDBusConnectionFlags connection_flags; - if (server->priv->nonce != NULL) + if (server->nonce != NULL) { gchar buf[16]; gsize bytes_read; @@ -909,29 +964,37 @@ on_run (GSocketService *service, if (bytes_read != 16) goto out; - if (memcmp (buf, server->priv->nonce, 16) != 0) + if (memcmp (buf, server->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_SERVER | + G_DBUS_CONNECTION_FLAGS_DELAY_MESSAGE_PROCESSING; + if (server->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, + server->guid, connection_flags, - server->priv->authentication_observer, + server->authentication_observer, NULL, /* GCancellable */ NULL); /* GError */ if (connection == NULL) goto out; - if (server->priv->flags & G_DBUS_SERVER_FLAGS_RUN_IN_THREAD) + if (server->flags & G_DBUS_SERVER_FLAGS_RUN_IN_THREAD) { + gboolean claimed; + + claimed = FALSE; g_signal_emit (server, _signals[NEW_CONNECTION_SIGNAL], 0, - connection); + connection, + &claimed); + if (claimed) + g_dbus_connection_start_message_processing (connection); g_object_unref (connection); } else @@ -949,7 +1012,8 @@ on_run (GSocketService *service, emit_new_connection_in_idle, data, (GDestroyNotify) emit_idle_data_free); - g_source_attach (idle_source, server->priv->main_context_at_construction); + g_source_set_name (idle_source, "[gio] emit_new_connection_in_idle"); + g_source_attach (idle_source, server->main_context_at_construction); g_source_unref (idle_source); } @@ -969,21 +1033,22 @@ initable_init (GInitable *initable, GError *last_error; ret = FALSE; + addr_array = NULL; last_error = NULL; - if (!g_dbus_is_guid (server->priv->guid)) + if (!g_dbus_is_guid (server->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); + _("The string '%s' is not a valid D-Bus GUID"), + server->guid); goto out; } - server->priv->listener = G_SOCKET_LISTENER (g_threaded_socket_service_new (-1)); + server->listener = G_SOCKET_LISTENER (g_threaded_socket_service_new (-1)); - addr_array = g_strsplit (server->priv->address, ";", 0); + addr_array = g_strsplit (server->address, ";", 0); last_error = NULL; for (n = 0; addr_array != NULL && addr_array[n] != NULL; n++) { @@ -1016,7 +1081,7 @@ initable_init (GInitable *initable, g_set_error (&this_error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, - _("Cannot listen on unsupported transport `%s'"), + _("Cannot listen on unsupported transport '%s'"), transport_name); g_free (transport_name); @@ -1038,14 +1103,21 @@ initable_init (GInitable *initable, } } - if (!ret) - goto out; - out: + + g_strfreev (addr_array); + if (ret) { if (last_error != NULL) g_error_free (last_error); + + /* Right now we don't have any transport not using the listener... */ + g_assert (server->is_using_listener); + server->run_signal_handler_id = g_signal_connect (G_SOCKET_SERVICE (server->listener), + "run", + G_CALLBACK (on_run), + server); } else { @@ -1063,6 +1135,3 @@ initable_iface_init (GInitableIface *initable_iface) } /* ---------------------------------------------------------------------------------------------------- */ - -#define __G_DBUS_SERVER_C__ -#include "gioaliasdef.c"