diff options
author | Ryan Lortie <desrt@desrt.ca> | 2013-11-06 14:53:47 -0500 |
---|---|---|
committer | Ryan Lortie <desrt@desrt.ca> | 2013-11-06 14:53:47 -0500 |
commit | f826363e4bdb9ffc90903a1b5a4d7ce47177aada (patch) | |
tree | 8089d97cc33d37c5787dc3a27537b4cff023ffc8 | |
parent | 1d6cd4b1b3761dbeb887538a2417456c1611585f (diff) | |
download | glib-tizen/kdbus-dev.tar.gz |
kdbus stufftizen/kdbus-dev
-rw-r--r-- | configure.ac | 10 | ||||
-rw-r--r-- | gio/Makefile.am | 4 | ||||
-rw-r--r-- | gio/gdbusaddress.c | 71 | ||||
-rw-r--r-- | gio/gdbusconnection.c | 95 | ||||
-rw-r--r-- | gio/gdbusprivate.c | 425 | ||||
-rw-r--r-- | gio/gdbusprivate.h | 4 | ||||
-rw-r--r-- | gio/gdbusserver.c | 16 | ||||
-rw-r--r-- | gio/gdesktopappinfo.c | 2 | ||||
-rw-r--r-- | gio/giotypes.h | 33 | ||||
-rw-r--r-- | gio/gkdbus.c | 887 | ||||
-rw-r--r-- | gio/gkdbus.h | 113 | ||||
-rw-r--r-- | gio/gkdbusconnection.c | 206 | ||||
-rw-r--r-- | gio/gkdbusconnection.h | 91 | ||||
-rw-r--r-- | gio/kdbus.h | 445 | ||||
-rw-r--r-- | glib/gmain.c | 9 |
15 files changed, 2233 insertions, 178 deletions
diff --git a/configure.ac b/configure.ac index e61fd9eb9..6a268e169 100644 --- a/configure.ac +++ b/configure.ac @@ -235,6 +235,10 @@ AC_ARG_ENABLE(gc_friendly, [AS_HELP_STRING([--enable-gc-friendly], [turn on garbage collector friendliness [default=no]])],, [enable_gc_friendly=no]) +AC_ARG_ENABLE(kdbus_transport, + [AS_HELP_STRING([--enable-kdbus-transport], + [enable kdbus transport [default=no]])],, + [enable_kdbus_transport=no]) AC_ARG_ENABLE(mem_pools, [AS_HELP_STRING([--disable-mem-pools], [disable all glib memory pools])],, @@ -255,6 +259,12 @@ AS_IF([test "x$enable_gc_friendly" = "xyes"], [ AC_MSG_RESULT([yes]) ], [ AC_MSG_RESULT([no]) ]) +AC_MSG_CHECKING([kdbus transport]) +AS_IF([test "x$enable_kdbus_transport" = "xyes"], [ + AC_MSG_RESULT([yes]) + CFLAGS="$CFLAGS -DKDBUS_TRANSPORT" +], [ AC_MSG_RESULT([no]) ]) + AC_MSG_CHECKING([whether to disable memory pools]) AS_IF([test "x$disable_mem_pools" = "xno"], [ AC_MSG_RESULT([no]) diff --git a/gio/Makefile.am b/gio/Makefile.am index 94d7f59ba..bd18e3a05 100644 --- a/gio/Makefile.am +++ b/gio/Makefile.am @@ -384,6 +384,8 @@ libgio_2_0_la_SOURCES = \ giomodule-priv.h \ gioscheduler.c \ giostream.c \ + gkdbus.c \ + gkdbusconnection.c \ gloadableicon.c \ gmount.c \ gmemoryinputstream.c \ @@ -555,6 +557,8 @@ gio_headers = \ giomodule.h \ gioscheduler.h \ giostream.h \ + gkdbus.h \ + gkdbusconnection.h \ gloadableicon.h \ gmount.h \ gmemoryinputstream.h \ diff --git a/gio/gdbusaddress.c b/gio/gdbusaddress.c index cc9703c96..970b36ffc 100644 --- a/gio/gdbusaddress.c +++ b/gio/gdbusaddress.c @@ -44,6 +44,9 @@ #ifdef G_OS_UNIX #include <gio/gunixsocketaddress.h> +#ifdef KDBUS_TRANSPORT +#include <gio/gkdbusconnection.h> +#endif #endif #ifdef G_OS_WIN32 @@ -401,7 +404,11 @@ g_dbus_is_supported_address (const gchar *string, goto out; supported = FALSE; - if (g_strcmp0 (transport_name, "unix") == 0) + if ((g_strcmp0 (transport_name, "unix") == 0) +#if defined (G_OS_UNIX) && (KDBUS_TRANSPORT) + || (g_strcmp0 (transport_name, "kdbus") == 0) +#endif + ) 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); @@ -553,7 +560,11 @@ g_dbus_address_connect (const gchar *address_entry, { } #ifdef G_OS_UNIX - else if (g_strcmp0 (transport_name, "unix") == 0) + else if ((g_strcmp0 (transport_name, "unix") == 0) +#ifdef KDBUS_TRANSPORT + || (g_strcmp0 (transport_name, "kdbus") == 0) +#endif + ) { const gchar *path; const gchar *abstract; @@ -664,21 +675,47 @@ g_dbus_address_connect (const gchar *address_entry, if (connectable != NULL) { - GSocketClient *client; - GSocketConnection *connection; - - g_assert (ret == NULL); - client = g_socket_client_new (); - connection = g_socket_client_connect (client, - connectable, - cancellable, - error); - g_object_unref (connectable); - g_object_unref (client); - if (connection == NULL) - goto out; - - ret = G_IO_STREAM (connection); +#if defined (G_OS_UNIX) && (KDBUS_TRANSPORT) + if (g_strcmp0 (transport_name, "kdbus") == 0) + { + GKdbusConnection *connection; + + const gchar *path; + path = g_hash_table_lookup (key_value_pairs, "path"); + + g_assert (ret == NULL); + connection = g_kdbus_connection_new (); + g_kdbus_connection_connect (connection, + path, + cancellable, + error); + g_object_unref (connectable); + if (connection == NULL) + goto out; + + ret = G_IO_STREAM (connection); + } + else + { +#endif + GSocketClient *client; + GSocketConnection *connection; + + g_assert (ret == NULL); + client = g_socket_client_new (); + connection = g_socket_client_connect (client, + connectable, + cancellable, + error); + g_object_unref (connectable); + g_object_unref (client); + if (connection == NULL) + goto out; + + ret = G_IO_STREAM (connection); +#if defined (G_OS_UNIX) && (KDBUS_TRANSPORT) + } +#endif if (nonce_file != NULL) { diff --git a/gio/gdbusconnection.c b/gio/gdbusconnection.c index f4c63a9c3..13f549379 100644 --- a/gio/gdbusconnection.c +++ b/gio/gdbusconnection.c @@ -128,6 +128,9 @@ #include "gsimpleasyncresult.h" #ifdef G_OS_UNIX +#ifdef KDBUS_TRANSPORT +#include "gkdbusconnection.h" +#endif #include "gunixconnection.h" #include "gunixfdmessage.h" #endif @@ -1647,6 +1650,18 @@ g_dbus_connection_send_message_unlocked (GDBusConnection *connection, error)) goto out; +#if defined (G_OS_UNIX) && (KDBUS_TRANSPORT) + if (G_IS_KDBUS_CONNECTION (connection->stream)){ + if ((connection->bus_unique_name) != NULL) + { + g_dbus_message_set_sender(message, connection->bus_unique_name); + #ifdef KDBUS_TRANSPORT_DEBUG + g_print (" KDBUS_TRANSPORT_DEBUG: (%s()): set_sender ok!\n",__FUNCTION__); + #endif + } + } +#endif + blob = g_dbus_message_to_blob (message, &blob_size, connection->capabilities, @@ -2578,45 +2593,51 @@ initable_init (GInitable *initable, { g_assert_not_reached (); } - - /* Authenticate the connection */ - if (connection->flags & G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER) - { - g_assert (!(connection->flags & G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT)); - g_assert (connection->guid != NULL); - connection->auth = _g_dbus_auth_new (connection->stream); - if (!_g_dbus_auth_run_server (connection->auth, - connection->authentication_observer, - connection->guid, - (connection->flags & G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS), - get_offered_capabilities_max (connection), - &connection->capabilities, - &connection->credentials, - cancellable, - &connection->initialization_error)) - goto out; - } - else if (connection->flags & G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT) - { - g_assert (!(connection->flags & G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER)); - g_assert (connection->guid == NULL); - connection->auth = _g_dbus_auth_new (connection->stream); - connection->guid = _g_dbus_auth_run_client (connection->auth, - connection->authentication_observer, - get_offered_capabilities_max (connection), - &connection->capabilities, - cancellable, - &connection->initialization_error); - if (connection->guid == NULL) - goto out; - } - - if (connection->authentication_observer != NULL) +#if defined (G_OS_UNIX) && (KDBUS_TRANSPORT) + /* TODO: [KDBUS] Our kdbus daemon doesn't support connection authentication */ + if (!G_IS_KDBUS_CONNECTION (connection->stream)) { - g_object_unref (connection->authentication_observer); - connection->authentication_observer = NULL; - } +#endif + /* Authenticate the connection */ + if (connection->flags & G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER) + { + g_assert (!(connection->flags & G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT)); + g_assert (connection->guid != NULL); + connection->auth = _g_dbus_auth_new (connection->stream); + if (!_g_dbus_auth_run_server (connection->auth, + connection->authentication_observer, + connection->guid, + (connection->flags & G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS), + get_offered_capabilities_max (connection), + &connection->capabilities, + &connection->credentials, + cancellable, + &connection->initialization_error)) + goto out; + } + else if (connection->flags & G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT) + { + g_assert (!(connection->flags & G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER)); + g_assert (connection->guid == NULL); + connection->auth = _g_dbus_auth_new (connection->stream); + connection->guid = _g_dbus_auth_run_client (connection->auth, + connection->authentication_observer, + get_offered_capabilities_max (connection), + &connection->capabilities, + cancellable, + &connection->initialization_error); + if (connection->guid == NULL) + goto out; + } + if (connection->authentication_observer != NULL) + { + g_object_unref (connection->authentication_observer); + connection->authentication_observer = NULL; + } +#if defined (G_OS_UNIX) && (KDBUS_TRANSPORT) + } +#endif //g_output_stream_flush (G_SOCKET_CONNECTION (connection->stream) //g_debug ("haz unix fd passing powers: %d", connection->capabilities & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING); diff --git a/gio/gdbusprivate.c b/gio/gdbusprivate.c index 0e5bef2c8..c01de77e7 100644 --- a/gio/gdbusprivate.c +++ b/gio/gdbusprivate.c @@ -45,6 +45,9 @@ #include "gsocketoutputstream.h" #ifdef G_OS_UNIX +#ifdef KDBUS_TRANSPORT +#include "gkdbusconnection.h" +#endif #include "gunixfdmessage.h" #include "gunixconnection.h" #include "gunixcredentialsmessage.h" @@ -117,6 +120,63 @@ typedef struct gboolean from_mainloop; } ReadWithControlData; +#if defined (G_OS_UNIX) && (KDBUS_TRANSPORT) +typedef struct +{ + GKdbus *kdbus; + GCancellable *cancellable; + + void *buffer; + gsize count; + + GSimpleAsyncResult *simple; + + gboolean from_mainloop; +} ReadKdbusData; + +static void +read_kdbus_data_free (ReadKdbusData *data) +{ + g_object_unref (data->kdbus); + if (data->cancellable != NULL) + g_object_unref (data->cancellable); + g_object_unref (data->simple); + g_free (data); +} + +static gboolean +_g_kdbus_read_ready (GKdbus *kdbus, + GIOCondition condition, + gpointer user_data) +{ + ReadKdbusData *data = user_data; + GError *error; + gssize result; + + error = NULL; + + result = g_kdbus_receive (data->kdbus, + data->buffer, + &error); + if (result >= 0) + { + g_simple_async_result_set_op_res_gssize (data->simple, result); + } + else + { + g_assert (error != NULL); + g_simple_async_result_take_error (data->simple, error); + } + + if (data->from_mainloop) + g_simple_async_result_complete (data->simple); + else + g_simple_async_result_complete_in_idle (data->simple); + + return FALSE; +} +#endif + static void read_with_control_data_free (ReadWithControlData *data) { @@ -167,6 +227,43 @@ _g_socket_read_with_control_messages_ready (GSocket *socket, return FALSE; } +#if defined (G_OS_UNIX) && (KDBUS_TRANSPORT) +static void +_g_kdbus_read (GKdbus *kdbus, + void *buffer, + gsize count, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + ReadKdbusData *data; + GSource *source; + + data = g_new0 (ReadKdbusData, 1); + data->kdbus = g_object_ref (kdbus); + data->cancellable = cancellable != NULL ? g_object_ref (cancellable) : NULL; + data->buffer = buffer; + data->count = count; + + data->simple = g_simple_async_result_new (G_OBJECT (kdbus), + callback, + user_data, + _g_kdbus_read); + g_simple_async_result_set_check_cancellable (data->simple, cancellable); + + data->from_mainloop = TRUE; + source = g_kdbus_create_source (data->kdbus, + G_IO_IN | G_IO_HUP | G_IO_ERR, + cancellable); + g_source_set_callback (source, + (GSourceFunc) _g_kdbus_read_ready, + data, + (GDestroyNotify) read_kdbus_data_free); + g_source_attach (source, g_main_context_get_thread_default ()); + g_source_unref (source); +} +#endif + static void _g_socket_read_with_control_messages (GSocket *socket, void *buffer, @@ -215,6 +312,24 @@ _g_socket_read_with_control_messages (GSocket *socket, } } +#if defined (G_OS_UNIX) && (KDBUS_TRANSPORT) +static gssize +_g_kdbus_read_finish (GKdbus *kdbus, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result); + + g_return_val_if_fail (G_IS_KDBUS (kdbus), -1); + g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == _g_kdbus_read); + + if (g_simple_async_result_propagate_error (simple, error)) + return -1; + else + return g_simple_async_result_get_op_res_gssize (simple); +} +#endif + static gssize _g_socket_read_with_control_messages_finish (GSocket *socket, GAsyncResult *result, @@ -364,8 +479,11 @@ struct GDBusWorker GDBusWorkerDisconnectedCallback disconnected_callback; gpointer user_data; - /* if not NULL, stream is GSocketConnection */ + /* if GSocket and GKdbus are NULL, stream is GSocketConnection */ GSocket *socket; +#if defined (G_OS_UNIX) && (KDBUS_TRANSPORT) + GKdbus *kdbus; +#endif /* used for reading */ GMutex read_lock; @@ -506,7 +624,7 @@ _g_dbus_worker_emit_message_about_to_be_sent (GDBusWorker *worker, } /* can only be called from private thread with read-lock held - takes ownership of @message */ -static void +void _g_dbus_worker_queue_or_deliver_received_message (GDBusWorker *worker, GDBusMessage *message) { @@ -584,7 +702,16 @@ _g_dbus_worker_do_read_cb (GInputStream *input_stream, goto out; error = NULL; +#if defined (G_OS_UNIX) && (KDBUS_TRANSPORT) + if (G_IS_KDBUS_CONNECTION (worker->stream)) + { + bytes_read = _g_kdbus_read_finish (worker->kdbus, + res, + &error); + } else if (worker->socket == NULL) +#else if (worker->socket == NULL) +#endif bytes_read = g_input_stream_read_finish (g_io_stream_get_input_stream (worker->stream), res, &error); @@ -722,6 +849,13 @@ _g_dbus_worker_do_read_cb (GInputStream *input_stream, read_message_print_transport_debug (bytes_read, worker); worker->read_buffer_cur_size += bytes_read; + +#if defined (G_OS_UNIX) && (KDBUS_TRANSPORT) + /* For KDBUS transport we don't have to read message header */ + if (G_IS_KDBUS_CONNECTION (worker->stream)) + worker->read_buffer_bytes_wanted = worker->read_buffer_cur_size; +#endif + if (worker->read_buffer_bytes_wanted == worker->read_buffer_cur_size) { /* OK, got what we asked for! */ @@ -841,12 +975,38 @@ _g_dbus_worker_do_read_unlocked (GDBusWorker *worker) /* ensure we have a (big enough) buffer */ if (worker->read_buffer == NULL || worker->read_buffer_bytes_wanted > worker->read_buffer_allocated_size) { - /* TODO: 4096 is randomly chosen; might want a better chosen default minimum */ - worker->read_buffer_allocated_size = MAX (worker->read_buffer_bytes_wanted, 4096); - worker->read_buffer = g_realloc (worker->read_buffer, worker->read_buffer_allocated_size); +#if defined (G_OS_UNIX) && (KDBUS_TRANSPORT) + if (G_IS_KDBUS_CONNECTION (worker->stream)) + { + /* For KDBUS transport we have to alloc buffer only once - DBUS_MAXIMUM_MESSAGE_LENGTH=2^27 */ + worker->read_buffer_allocated_size = MAX (worker->read_buffer_bytes_wanted, 134217728); + worker->read_buffer = g_realloc (worker->read_buffer, worker->read_buffer_allocated_size); + } + else + { +#endif + /* TODO: 4096 is randomly chosen; might want a better chosen default minimum */ + worker->read_buffer_allocated_size = MAX (worker->read_buffer_bytes_wanted, 4096); + worker->read_buffer = g_realloc (worker->read_buffer, worker->read_buffer_allocated_size); +#if defined (G_OS_UNIX) && (KDBUS_TRANSPORT) + } +#endif } +#if defined (G_OS_UNIX) && (KDBUS_TRANSPORT) + if (G_IS_KDBUS_CONNECTION (worker->stream)) + { + _g_kdbus_read(worker->kdbus, + worker->read_buffer, + worker->read_buffer_bytes_wanted, + worker->cancellable, + (GAsyncReadyCallback) _g_dbus_worker_do_read_cb, + _g_dbus_worker_ref (worker)); + + } else if (worker->socket == NULL) +#else if (worker->socket == NULL) +#endif g_input_stream_read_async (g_io_stream_get_input_stream (worker->stream), worker->read_buffer + worker->read_buffer_cur_size, worker->read_buffer_bytes_wanted - worker->read_buffer_cur_size, @@ -986,131 +1146,144 @@ write_message_continue_writing (MessageToWriteData *data) { GOutputStream *ostream; #ifdef G_OS_UNIX - GSimpleAsyncResult *simple; GUnixFDList *fd_list; -#endif - -#ifdef G_OS_UNIX - /* Note: we can't access data->simple after calling g_async_result_complete () because the - * callback can free @data and we're not completing in idle. So use a copy of the pointer. - */ + GSimpleAsyncResult *simple; simple = data->simple; #endif - ostream = g_io_stream_get_output_stream (data->worker->stream); -#ifdef G_OS_UNIX - fd_list = g_dbus_message_get_unix_fd_list (data->message); -#endif - - g_assert (!g_output_stream_has_pending (ostream)); - g_assert_cmpint (data->total_written, <, data->blob_size); - - if (FALSE) +#if defined (G_OS_UNIX) && (KDBUS_TRANSPORT) + if (G_IS_KDBUS_CONNECTION (data->worker->stream)) { + GError *error; + error = NULL; + data->total_written = g_kdbus_send_message(data->worker, data->worker->kdbus, data->message, data->blob, data->blob_size, &error); + + write_message_print_transport_debug (data->total_written, data); + g_simple_async_result_complete (simple); + g_object_unref (simple); + goto out; } -#ifdef G_OS_UNIX - else if (G_IS_SOCKET_OUTPUT_STREAM (ostream) && data->total_written == 0) + else { - GOutputVector vector; - GSocketControlMessage *control_message; - gssize bytes_written; - GError *error; - - vector.buffer = data->blob; - vector.size = data->blob_size; +#endif + ostream = g_io_stream_get_output_stream (data->worker->stream); +#ifdef G_OS_UNIX + fd_list = g_dbus_message_get_unix_fd_list (data->message); +#endif - control_message = NULL; - if (fd_list != NULL && g_unix_fd_list_get_length (fd_list) > 0) - { - if (!(data->worker->capabilities & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING)) - { - g_simple_async_result_set_error (simple, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "Tried sending a file descriptor but remote peer does not support this capability"); - g_simple_async_result_complete (simple); - g_object_unref (simple); - goto out; - } - control_message = g_unix_fd_message_new_with_fd_list (fd_list); - } + g_assert (!g_output_stream_has_pending (ostream)); + g_assert_cmpint (data->total_written, <, data->blob_size); - error = NULL; - bytes_written = g_socket_send_message (data->worker->socket, - NULL, /* address */ - &vector, - 1, - control_message != NULL ? &control_message : NULL, - control_message != NULL ? 1 : 0, - G_SOCKET_MSG_NONE, - data->worker->cancellable, - &error); - if (control_message != NULL) - g_object_unref (control_message); - - if (bytes_written == -1) + if (FALSE) { - /* Handle WOULD_BLOCK by waiting until there's room in the buffer */ - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) - { - GSource *source; - source = g_socket_create_source (data->worker->socket, - G_IO_OUT | G_IO_HUP | G_IO_ERR, - data->worker->cancellable); - g_source_set_callback (source, - (GSourceFunc) on_socket_ready, - data, - NULL); /* GDestroyNotify */ - g_source_attach (source, g_main_context_get_thread_default ()); - g_source_unref (source); - g_error_free (error); - goto out; - } - g_simple_async_result_take_error (simple, error); - g_simple_async_result_complete (simple); - g_object_unref (simple); - goto out; } - g_assert (bytes_written > 0); /* zero is never returned */ - - write_message_print_transport_debug (bytes_written, data); - - data->total_written += bytes_written; - g_assert (data->total_written <= data->blob_size); - if (data->total_written == data->blob_size) +#ifdef G_OS_UNIX + else if (G_IS_SOCKET_OUTPUT_STREAM (ostream) && data->total_written == 0) { - g_simple_async_result_complete (simple); - g_object_unref (simple); - goto out; - } - - write_message_continue_writing (data); - } + GOutputVector vector; + GSocketControlMessage *control_message; + gssize bytes_written; + GError *error; + + vector.buffer = data->blob; + vector.size = data->blob_size; + + control_message = NULL; + if (fd_list != NULL && g_unix_fd_list_get_length (fd_list) > 0) + { + if (!(data->worker->capabilities & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING)) + { + g_simple_async_result_set_error (simple, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "Tried sending a file descriptor but remote peer does not support this capability"); + g_simple_async_result_complete (simple); + g_object_unref (simple); + goto out; + } + control_message = g_unix_fd_message_new_with_fd_list (fd_list); + } + + error = NULL; + bytes_written = g_socket_send_message (data->worker->socket, + NULL, /* address */ + &vector, + 1, + control_message != NULL ? &control_message : NULL, + control_message != NULL ? 1 : 0, + G_SOCKET_MSG_NONE, + data->worker->cancellable, + &error); + if (control_message != NULL) + g_object_unref (control_message); + + if (bytes_written == -1) + { + /* Handle WOULD_BLOCK by waiting until there's room in the buffer */ + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) + { + GSource *source; + source = g_socket_create_source (data->worker->socket, + G_IO_OUT | G_IO_HUP | G_IO_ERR, + data->worker->cancellable); + g_source_set_callback (source, + (GSourceFunc) on_socket_ready, + data, + NULL); /* GDestroyNotify */ + g_source_attach (source, g_main_context_get_thread_default ()); + g_source_unref (source); + g_error_free (error); + goto out; + } + g_simple_async_result_take_error (simple, error); + g_simple_async_result_complete (simple); + g_object_unref (simple); + goto out; + } + g_assert (bytes_written > 0); /* zero is never returned */ + + write_message_print_transport_debug (bytes_written, data); + + data->total_written += bytes_written; + g_assert (data->total_written <= data->blob_size); + if (data->total_written == data->blob_size) + { + g_simple_async_result_complete (simple); + g_object_unref (simple); + goto out; + } + + write_message_continue_writing (data); + } #endif - else - { + else + { #ifdef G_OS_UNIX - if (fd_list != NULL) - { - g_simple_async_result_set_error (simple, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "Tried sending a file descriptor on unsupported stream of type %s", - g_type_name (G_TYPE_FROM_INSTANCE (ostream))); - g_simple_async_result_complete (simple); - g_object_unref (simple); - goto out; - } + if (fd_list != NULL) + { + g_simple_async_result_set_error (simple, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "Tried sending a file descriptor on unsupported stream of type %s", + g_type_name (G_TYPE_FROM_INSTANCE (ostream))); + g_simple_async_result_complete (simple); + g_object_unref (simple); + goto out; + } #endif - g_output_stream_write_async (ostream, - (const gchar *) data->blob + data->total_written, - data->blob_size - data->total_written, - G_PRIORITY_DEFAULT, - data->worker->cancellable, - write_message_async_cb, - data); + g_output_stream_write_async (ostream, + (const gchar *) data->blob + data->total_written, + data->blob_size - data->total_written, + G_PRIORITY_DEFAULT, + data->worker->cancellable, + write_message_async_cb, + data); + } +#if defined (G_OS_UNIX) && (KDBUS_TRANSPORT) } +#endif + #ifdef G_OS_UNIX out: #endif @@ -1452,9 +1625,14 @@ continue_writing (GDBusWorker *worker) worker->close_expected = TRUE; worker->output_pending = PENDING_CLOSE; - g_io_stream_close_async (worker->stream, G_PRIORITY_DEFAULT, - NULL, iostream_close_cb, - _g_dbus_worker_ref (worker)); +#if defined (G_OS_UNIX) && (KDBUS_TRANSPORT) + if (G_IS_KDBUS_CONNECTION (worker->stream)) + g_kdbus_connection_close (worker->stream, NULL, NULL); + else +#endif + g_io_stream_close_async (worker->stream, G_PRIORITY_DEFAULT, + NULL, iostream_close_cb, + _g_dbus_worker_ref (worker)); } else { @@ -1677,6 +1855,11 @@ _g_dbus_worker_new (GIOStream *stream, if (G_IS_SOCKET_CONNECTION (worker->stream)) worker->socket = g_socket_connection_get_socket (G_SOCKET_CONNECTION (worker->stream)); +#if defined (G_OS_UNIX) && (KDBUS_TRANSPORT) + if (G_IS_KDBUS_CONNECTION (worker->stream)) + worker->kdbus = g_kdbus_connection_get_kdbus (G_KDBUS_CONNECTION (worker->stream)); +#endif + worker->shared_thread_data = _g_dbus_shared_thread_ref (); /* begin reading */ @@ -2156,12 +2339,11 @@ write_message_print_transport_debug (gssize bytes_written, g_print ("========================================================================\n" "GDBus-debug:Transport:\n" " >>>> WROTE %" G_GSIZE_FORMAT " bytes of message with serial %d and\n" - " size %" G_GSIZE_FORMAT " from offset %" G_GSIZE_FORMAT " on a %s\n", + " size %" G_GSIZE_FORMAT " from offset %" G_GSIZE_FORMAT "\n", bytes_written, g_dbus_message_get_serial (data->message), data->blob_size, - data->total_written, - g_type_name (G_TYPE_FROM_INSTANCE (g_io_stream_get_output_stream (data->worker->stream)))); + data->total_written); _g_dbus_debug_print_unlock (); out: ; @@ -2207,12 +2389,11 @@ read_message_print_transport_debug (gssize bytes_read, g_print ("========================================================================\n" "GDBus-debug:Transport:\n" " <<<< READ %" G_GSIZE_FORMAT " bytes of message with serial %d and\n" - " size %d to offset %" G_GSIZE_FORMAT " from a %s\n", + " size %d to offset %" G_GSIZE_FORMAT "\n", bytes_read, serial, message_length, - worker->read_buffer_cur_size, - g_type_name (G_TYPE_FROM_INSTANCE (g_io_stream_get_input_stream (worker->stream)))); + worker->read_buffer_cur_size); _g_dbus_debug_print_unlock (); out: ; diff --git a/gio/gdbusprivate.h b/gio/gdbusprivate.h index 3a6286772..e1e723144 100644 --- a/gio/gdbusprivate.h +++ b/gio/gdbusprivate.h @@ -80,7 +80,9 @@ gboolean _g_dbus_worker_flush_sync (GDBusWorker *worker, void _g_dbus_worker_close (GDBusWorker *worker, GCancellable *cancellable, GSimpleAsyncResult *result); - +/* Samsung change */ +void _g_dbus_worker_queue_or_deliver_received_message (GDBusWorker *worker, + GDBusMessage *message); /* ---------------------------------------------------------------------------------------------------- */ void _g_dbus_initialize (void); diff --git a/gio/gdbusserver.c b/gio/gdbusserver.c index 02508e6bc..48ceb7342 100644 --- a/gio/gdbusserver.c +++ b/gio/gdbusserver.c @@ -634,6 +634,18 @@ random_ascii (void) return ret; } +#ifdef KDBUS_TRANSPORT +static gboolean +try_kdbus (GDBusServer *server, + const gchar *address_entry, + GHashTable *key_value_pairs, + GError **error) +{ + g_print ("GDBusServer - KDBUS\n"); + return TRUE; +} +#endif + /* note that address_entry has already been validated => exactly one of path, tmpdir or abstract keys are set */ static gboolean try_unix (GDBusServer *server, @@ -1071,6 +1083,10 @@ initable_init (GInitable *initable, #ifdef G_OS_UNIX else if (g_strcmp0 (transport_name, "unix") == 0) ret = try_unix (server, address_entry, key_value_pairs, &this_error); +#ifdef KDBUS_TRANSPORT + else if (g_strcmp0 (transport_name, "kdbus") == 0) + ret = try_kdbus (server, address_entry, key_value_pairs, &this_error); +#endif #endif else if (g_strcmp0 (transport_name, "tcp") == 0) ret = try_tcp (server, address_entry, key_value_pairs, FALSE, &this_error); diff --git a/gio/gdesktopappinfo.c b/gio/gdesktopappinfo.c index a76ecf3fa..faf9ac876 100644 --- a/gio/gdesktopappinfo.c +++ b/gio/gdesktopappinfo.c @@ -424,6 +424,8 @@ g_desktop_app_info_load_file (GDesktopAppInfo *self) g_return_val_if_fail (self->filename != NULL, FALSE); + self->desktop_id = g_path_get_basename (self->filename); + key_file = g_key_file_new (); if (g_key_file_load_from_file (key_file, diff --git a/gio/giotypes.h b/gio/giotypes.h index 269609123..671e2e360 100644 --- a/gio/giotypes.h +++ b/gio/giotypes.h @@ -250,6 +250,23 @@ typedef struct _GVolume GVolume; /* Dummy typedef */ typedef struct _GVolumeMonitor GVolumeMonitor; /** + * GKdbus: + * + * A lowlevel kdbus object. + * + **/ + +typedef struct _GKdbus GKdbus; + +/** + * GKdbusConnection: + * + * A kdbus connection GIOStream object. + * + **/ +typedef struct _GKdbusConnection GKdbusConnection; + +/** * GAsyncReadyCallback: * @source_object: the object the asynchronous operation was started with. * @res: a #GAsyncResult. @@ -343,6 +360,22 @@ typedef gboolean (*GSocketSourceFunc) (GSocket *socket, gpointer user_data); /** + * GKdbusSourceFunc: + * @socket: the #GKdbus + * @condition: the current condition at the source fired. + * @user_data: data passed in by the user. + * + * This is the function type of the callback used for the #GSource + * returned by g_kdbus_create_source(). + * + * Returns: it should return %FALSE if the source should be removed. + * + */ +typedef gboolean (*GKdbusSourceFunc) (GKdbus *kdbus, + GIOCondition condition, + gpointer user_data); + +/** * GInputVector: * @buffer: Pointer to a buffer where data will be written. * @size: the available size in @buffer. diff --git a/gio/gkdbus.c b/gio/gkdbus.c new file mode 100644 index 000000000..aa7ce7ddf --- /dev/null +++ b/gio/gkdbus.c @@ -0,0 +1,887 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright © 2013 Samsung + * + * 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. + * + * Authors: Michal Eljasiewicz <m.eljasiewic@samsung.com> + * Authors: Lukasz Skalski <l.skalski@partner.samsung.com> + */ + +#include "config.h" + +#include "gkdbus.h" +#include "glib-unix.h" + +#include <errno.h> +#include <signal.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/mman.h> +#include <stdio.h> + +#ifdef HAVE_SYS_FILIO_H +# include <sys/filio.h> +#endif + +#ifdef HAVE_SYS_UIO_H +#include <sys/uio.h> +#endif + +#include "gcancellable.h" +#include "gioenumtypes.h" +#include "ginitable.h" +#include "gioerror.h" +#include "gioenums.h" +#include "gioerror.h" +#include "glibintl.h" +#include "kdbus.h" +#include "gdbusmessage.h" +#include "gdbusconnection.h" + +#define KDBUS_PART_FOREACH(part, head, first) \ + for (part = (head)->first; \ + (guint8 *)(part) < (guint8 *)(head) + (head)->size; \ + part = KDBUS_PART_NEXT(part)) +#define RECEIVE_POOL_SIZE (10 * 1024LU * 1024LU) + +#define MSG_ITEM_BUILD_VEC(data, datasize) \ + item->type = KDBUS_MSG_PAYLOAD_VEC; \ + item->size = KDBUS_PART_HEADER_SIZE + sizeof(struct kdbus_vec); \ + item->vec.address = (unsigned long) data; \ + item->vec.size = datasize; + +#define KDBUS_ALIGN8(l) (((l) + 7) & ~7) +#define KDBUS_PART_NEXT(part) \ + (typeof(part))(((guint8 *)part) + KDBUS_ALIGN8((part)->size)) +#define KDBUS_ITEM_SIZE(s) KDBUS_ALIGN8((s) + KDBUS_PART_HEADER_SIZE) + +/* + * SECTION:gkdbus + * @short_description: Low-level kdbus object + * @include: gio/gio.h + */ + +static void g_kdbus_initable_iface_init (GInitableIface *iface); +static gboolean g_kdbus_initable_init (GInitable *initable, + GCancellable *cancellable, + GError **error); + +G_DEFINE_TYPE_WITH_CODE (GKdbus, g_kdbus, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, + g_kdbus_initable_iface_init)); + +enum +{ + PROP_0, + PROP_FD, + PROP_TIMEOUT, + PROP_PEER_ID +}; + +struct _GKdbusPrivate +{ + gint fd; + gchar *path; + gchar *buffer_ptr; + gchar *sender; + gint peer_id; + guint64 bloom_size; + guint registered : 1; + guint closed : 1; + guint inited : 1; + guint timeout; + guint timed_out : 1; +}; + +/* + * g_kdbus_get_property: + * + */ +static void +g_kdbus_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GKdbus *kdbus = G_KDBUS (object); + + switch (prop_id) + { + case PROP_FD: + g_value_set_int (value, kdbus->priv->fd); + break; + + case PROP_TIMEOUT: + g_value_set_int (value, kdbus->priv->timeout); + break; + + case PROP_PEER_ID: + g_value_set_int (value, kdbus->priv->peer_id); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +/* + * g_kdbus_set_property: + * + */ +static void +g_kdbus_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GKdbus *kdbus = G_KDBUS (object); + + switch (prop_id) + { + case PROP_TIMEOUT: + kdbus->priv->timeout = g_value_get_int (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +/* + * g_kdbus_finalize: + * TODO: Compare with gsocket + */ +static void +g_kdbus_finalize (GObject *object) +{ + GKdbus *kdbus = G_KDBUS (object); + + if (kdbus->priv->fd != -1 && !kdbus->priv->closed) + g_kdbus_close (kdbus, NULL); + + if (G_OBJECT_CLASS (g_kdbus_parent_class)->finalize) + (*G_OBJECT_CLASS (g_kdbus_parent_class)->finalize) (object); + +} + +/* + * g_kdbus_class_init: + * + */ +static void +g_kdbus_class_init (GKdbusClass *klass) +{ + GObjectClass *gobject_class G_GNUC_UNUSED = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (GKdbusPrivate)); + + gobject_class->finalize = g_kdbus_finalize; + gobject_class->set_property = g_kdbus_set_property; + gobject_class->get_property = g_kdbus_get_property; +/* + g_object_class_install_property (gobject_class, PROP_FD, + g_param_spec_int ("fd", + P_("File descriptor"), + P_("The kdbus file descriptor"), + G_MININT, + G_MAXINT, + -1, + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_TIMEOUT, + g_param_spec_uint ("timeout", + P_("Timeout"), + P_("The timeout in seconds on kdbus I/O"), + 0, + G_MAXUINT, + 0, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_PEER_ID, + g_param_spec_uint ("Peer ID", + P_("kdbus peer ID"), + P_("The kdbus peer ID"), + 0, + G_MAXUINT, + 0, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); +*/ +} + + +/* + * g_kdbus_initable_iface_init: + * + */ +static void +g_kdbus_initable_iface_init (GInitableIface *iface) +{ + iface->init = g_kdbus_initable_init; +} + +/* + * g_kdbus_init: + * + */ +static void +g_kdbus_init (GKdbus *kdbus) +{ + kdbus->priv = G_TYPE_INSTANCE_GET_PRIVATE (kdbus, G_TYPE_KDBUS, GKdbusPrivate); + + kdbus->priv->fd = -1; + kdbus->priv->peer_id = -1; + kdbus->priv->bloom_size = 0; + kdbus->priv->path = NULL; + kdbus->priv->buffer_ptr = NULL; + kdbus->priv->sender = NULL; +} + +/* + * g_kdbus_initable_init: + * + */ +static gboolean +g_kdbus_initable_init (GInitable *initable, + GCancellable *cancellable, + GError **error) +{ + GKdbus *kdbus; + + g_return_val_if_fail (G_IS_KDBUS (initable), FALSE); + + kdbus = G_KDBUS (initable); + + if (cancellable != NULL) + { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + _("Cancellable initialization not supported")); + return FALSE; + } + + kdbus->priv->inited = TRUE; + + return TRUE; +} + +/* + * g_kdbus_get_fd: returns the file descriptor of the kdbus + * + */ + +gint +g_kdbus_get_fd (GKdbus *kdbus) +{ + g_return_val_if_fail (G_IS_KDBUS (kdbus), FALSE); + + return kdbus->priv->fd; +} + +/* + * g_kdbus_open: + * + */ +gboolean +g_kdbus_open (GKdbus *kdbus, + const gchar *address, + GCancellable *cancellable, + GError **error) +{ + g_return_val_if_fail (G_IS_KDBUS (kdbus), FALSE); + kdbus->priv->fd = open(address, O_RDWR|O_CLOEXEC|O_NONBLOCK); + + if (kdbus->priv->fd<0) + { + g_error(" KDBUS_DEBUG: (%s()): error when mmap: %m, %d",__FUNCTION__,errno); + return FALSE; + } + + #ifdef KDBUS_DEBUG + g_print (" KDBUS_DEBUG: (%s()): kdbus endpoint opened\n",__FUNCTION__); + #endif + + kdbus->priv->closed = FALSE; + return TRUE; +} + +/* + * g_kdbus_close: + * + */ +gboolean +g_kdbus_close (GKdbus *kdbus, + GError **error) +{ + g_return_val_if_fail (G_IS_KDBUS (kdbus), FALSE); + close(kdbus->priv->fd); + + kdbus->priv->closed = TRUE; + kdbus->priv->fd = -1; + kdbus->priv->registered = FALSE; + + #ifdef KDBUS_DEBUG + g_print (" KDBUS_DEBUG: (%s()): kdbus endpoint closed\n",__FUNCTION__); + #endif + + return TRUE; +} + +/* + * g_kdbus_is_closed: checks whether a kdbus is closed. + * + */ +gboolean +g_kdbus_is_closed (GKdbus *kdbus) +{ + g_return_val_if_fail (G_IS_KDBUS (kdbus), FALSE); + + return kdbus->priv->closed; +} + +/* + * g_kdbus_register: hello message + unique name + mapping memory for incoming messages + * TODO: + */ +gboolean g_kdbus_register(GKdbus *kdbus) +{ + struct kdbus_cmd_hello __attribute__ ((__aligned__(8))) hello; + + hello.conn_flags = KDBUS_HELLO_ACCEPT_FD/* | + KDBUS_HELLO_ATTACH_COMM | + KDBUS_HELLO_ATTACH_EXE | + KDBUS_HELLO_ATTACH_CMDLINE | + KDBUS_HELLO_ATTACH_CAPS | + KDBUS_HELLO_ATTACH_CGROUP | + KDBUS_HELLO_ATTACH_SECLABEL| + KDBUS_HELLO_ATTACH_AUDIT*/; + hello.size = sizeof(struct kdbus_cmd_hello); + hello.pool_size = RECEIVE_POOL_SIZE; + + if (ioctl(kdbus->priv->fd, KDBUS_CMD_HELLO, &hello)) + { + g_error(" KDBUS_DEBUG: (%s()): fd=%d failed to send hello: %m, %d",__FUNCTION__,kdbus->priv->fd,errno); + return FALSE; + } + + kdbus->priv->registered = TRUE; + kdbus->priv->peer_id = hello.id; + + #ifdef KDBUS_DEBUG + g_print(" KDBUS_DEBUG: (%s()): Our peer ID=%llu\n",__FUNCTION__,hello.id); + #endif + + kdbus->priv->bloom_size = hello.bloom_size; + kdbus->priv->buffer_ptr = mmap(NULL, RECEIVE_POOL_SIZE, PROT_READ, MAP_SHARED, kdbus->priv->fd, 0); + + if (kdbus->priv->buffer_ptr == MAP_FAILED) + { + g_error(" KDBUS_DEBUG: (%s()): error when mmap: %m, %d",__FUNCTION__,errno); + return FALSE; + } + + return TRUE; +} + +/* + * g_kdbus_decode_msg: kdbus message received into buffer + * TODO: + */ +static int +g_kdbus_decode_msg(GKdbus *kdbus, + struct kdbus_msg *msg, + char *data) +{ + const struct kdbus_item *item; + int ret_size = 0; + + KDBUS_PART_FOREACH(item, msg, items) + { + if (item->size <= KDBUS_PART_HEADER_SIZE) + { + g_error(" KDBUS_DEBUG: (%s()): %llu bytes - invalid data record\n",__FUNCTION__,item->size); + break; //TODO: continue (because dbus will find error) or break + } + + switch (item->type) + { + case KDBUS_MSG_PAYLOAD_OFF: + memcpy(data, (char *)kdbus->priv->buffer_ptr + item->vec.offset, item->vec.size); + data += item->vec.size; + ret_size += item->vec.size; + + #ifdef KDBUS_DEBUG + g_print(" KDBUS_DEBUG: (%s()): KDBUS_MSG_PAYLOAD: %llu bytes, off=%llu, size=%llu\n",__FUNCTION__,item->size, + (unsigned long long)item->vec.offset, + (unsigned long long)item->vec.size); + #endif + break; + + case KDBUS_MSG_REPLY_TIMEOUT: + + #ifdef KDBUS_DEBUG + g_print(" KDBUS_DEBUG: (%s()): KDBUS_MSG_REPLY_TIMEOUT: %llu bytes, cookie=%llu\n",__FUNCTION__,item->size, msg->cookie_reply); + #endif + + /* TODO + message = generate_local_error_message(msg->cookie_reply, DBUS_ERROR_NO_REPLY, NULL); + if(message == NULL) + { + ret_size = -1; + goto out; + } + + ret_size = put_message_into_data(message, data); + */ + break; + + case KDBUS_MSG_REPLY_DEAD: + g_print(" KDBUS_DEBUG: (%s()): KDBUS_MSG_REPLY_DEAD: %llu bytes, cookie=%llu\n",__FUNCTION__,item->size, msg->cookie_reply); + + /* TODO + message = generate_local_error_message(msg->cookie_reply, DBUS_ERROR_NAME_HAS_NO_OWNER, NULL); + if(message == NULL) + { + ret_size = -1; + goto out; + } + + ret_size = put_message_into_data(message, data); + */ + break; + } + } + + return ret_size; +} + +typedef struct { + GSource source; + GPollFD pollfd; + GKdbus *kdbus; + GIOCondition condition; + GCancellable *cancellable; + GPollFD cancel_pollfd; + gint64 timeout_time; +} GKdbusSource; + +/* + * kdbus_source_prepare: + * + */ +static gboolean +kdbus_source_prepare (GSource *source, + gint *timeout) +{ + GKdbusSource *kdbus_source = (GKdbusSource *)source; + + if (g_cancellable_is_cancelled (kdbus_source->cancellable)) + return TRUE; + + if (kdbus_source->timeout_time) + { + gint64 now; + + now = g_source_get_time (source); + /* Round up to ensure that we don't try again too early */ + *timeout = (kdbus_source->timeout_time - now + 999) / 1000; + if (*timeout < 0) + { + kdbus_source->kdbus->priv->timed_out = TRUE; + *timeout = 0; + return TRUE; + } + } + else + *timeout = -1; + + if ((kdbus_source->condition & kdbus_source->pollfd.revents) != 0) + return TRUE; + + return FALSE; +} + +/* + * kdbus_source_check: + * + */ +static gboolean +kdbus_source_check (GSource *source) +{ + int timeout; + + return kdbus_source_prepare (source, &timeout); +} + +/* + * kdbus_source_dispatch + * + */ +static gboolean +kdbus_source_dispatch (GSource *source, + GSourceFunc callback, + gpointer user_data) +{ + GKdbusSourceFunc func = (GKdbusSourceFunc)callback; + GKdbusSource *kdbus_source = (GKdbusSource *)source; + GKdbus *kdbus = kdbus_source->kdbus; + gboolean ret; + + if (kdbus_source->kdbus->priv->timed_out) + kdbus_source->pollfd.revents |= kdbus_source->condition & (G_IO_IN | G_IO_OUT); + + ret = (*func) (kdbus, + kdbus_source->pollfd.revents & kdbus_source->condition, + user_data); + + if (kdbus->priv->timeout) + kdbus_source->timeout_time = g_get_monotonic_time () + + kdbus->priv->timeout * 1000000; + + else + kdbus_source->timeout_time = 0; + + return ret; +} + +/* + * kdbus_source_finalize + * + */ +static void +kdbus_source_finalize (GSource *source) +{ + GKdbusSource *kdbus_source = (GKdbusSource *)source; + GKdbus *kdbus; + + kdbus = kdbus_source->kdbus; + + g_object_unref (kdbus); + + if (kdbus_source->cancellable) + { + g_cancellable_release_fd (kdbus_source->cancellable); + g_object_unref (kdbus_source->cancellable); + } +} + +/* + * kdbus_source_closure_callback: + * + */ +static gboolean +kdbus_source_closure_callback (GKdbus *kdbus, + GIOCondition condition, + gpointer data) +{ + GClosure *closure = data; + GValue params[2] = { G_VALUE_INIT, G_VALUE_INIT }; + GValue result_value = G_VALUE_INIT; + gboolean result; + + g_value_init (&result_value, G_TYPE_BOOLEAN); + + g_value_init (¶ms[0], G_TYPE_KDBUS); + g_value_set_object (¶ms[0], kdbus); + g_value_init (¶ms[1], G_TYPE_IO_CONDITION); + g_value_set_flags (¶ms[1], condition); + + g_closure_invoke (closure, &result_value, 2, params, NULL); + + result = g_value_get_boolean (&result_value); + g_value_unset (&result_value); + g_value_unset (¶ms[0]); + g_value_unset (¶ms[1]); + + return result; +} + +static GSourceFuncs kdbus_source_funcs = +{ + kdbus_source_prepare, + kdbus_source_check, + kdbus_source_dispatch, + kdbus_source_finalize, + (GSourceFunc)kdbus_source_closure_callback, +}; + +/* + * kdbus_source_new: + * + */ +static GSource * +kdbus_source_new (GKdbus *kdbus, + GIOCondition condition, + GCancellable *cancellable) +{ + GSource *source; + GKdbusSource *kdbus_source; + + condition |= G_IO_HUP | G_IO_ERR; + + source = g_source_new (&kdbus_source_funcs, sizeof (GKdbusSource)); + g_source_set_name (source, "GKdbus"); + kdbus_source = (GKdbusSource *)source; + + kdbus_source->kdbus = g_object_ref (kdbus); + kdbus_source->condition = condition; + + if (g_cancellable_make_pollfd (cancellable, + &kdbus_source->cancel_pollfd)) + { + kdbus_source->cancellable = g_object_ref (cancellable); + g_source_add_poll (source, &kdbus_source->cancel_pollfd); + } + + kdbus_source->pollfd.fd = kdbus->priv->fd; + kdbus_source->pollfd.events = condition; + kdbus_source->pollfd.revents = 0; + g_source_add_poll (source, &kdbus_source->pollfd); + + if (kdbus->priv->timeout) + kdbus_source->timeout_time = g_get_monotonic_time () + + kdbus->priv->timeout * 1000000; + + else + kdbus_source->timeout_time = 0; + + return source; +} + +/* + * g_kdbus_create_source: + * + */ +GSource * +g_kdbus_create_source (GKdbus *kdbus, + GIOCondition condition, + GCancellable *cancellable) +{ + g_return_val_if_fail (G_IS_KDBUS (kdbus) && (cancellable == NULL || G_IS_CANCELLABLE (cancellable)), NULL); + + return kdbus_source_new (kdbus, condition, cancellable); +} + +/* + * g_kdbus_receive: + * TODO: Handle errors + */ +gssize +g_kdbus_receive (GKdbus *kdbus, + char *data, + GError **error) +{ + int ret_size = 0; + guint64 __attribute__ ((__aligned__(8))) offset; + struct kdbus_msg *msg; + + /* TODO: Temporary hack */ + if (kdbus->priv->closed == TRUE) + return 1; + + //get memory offset of msg + again: + if (ioctl(kdbus->priv->fd, KDBUS_CMD_MSG_RECV, &offset) < 0) + { + if(errno == EINTR) + goto again; + + /* TODO: Temporary hack */ + if (errno == EAGAIN) + return 1; + + g_error (" KDBUS_DEBUG: (%s()): ioctl MSG_RECV failed! %d (%m)\n",__FUNCTION__,errno); + return 1; + } + + msg = (struct kdbus_msg *)((char*)kdbus->priv->buffer_ptr + offset); + ret_size = g_kdbus_decode_msg(kdbus, msg, (char*)data); + + //release memory occupied by msg + again_2: + if (ioctl(kdbus->priv->fd, KDBUS_CMD_MSG_RELEASE, &offset) < 0) + { + if(errno == EINTR) + goto again_2; + g_print (" KDBUS_DEBUG: (%s()): ioctl MSG_RELEASE failed!\n",__FUNCTION__); + return -1; + } + + return ret_size; +} + +/* + * g_kdbus_send_reply: + * TODO: Handle errors,remove unused variables + */ +static gboolean +g_kdbus_send_reply (GDBusWorker *worker, + GKdbus *kdbus, + GDBusMessage *dbus_msg) +{ + GDBusMessage *reply = NULL; + char *unique_name = NULL; + char *sender = NULL; + + reply = g_dbus_message_new_method_reply(dbus_msg); + g_dbus_message_set_sender(reply, "org.freedesktop.DBus"); + + unique_name = malloc(30); //TODO: should allow for Kdbus peer ID max value? + sprintf(unique_name, "%i", kdbus->priv->peer_id); + + sender = malloc (strlen(unique_name) + 4); + if(!sender) + { + //TODO: Handle error + g_error (" KDBUS_DEBUG: (%s()): sender malloc error\n",__FUNCTION__); + return -1; + } + + sprintf(sender, ":1.%s", unique_name); + kdbus->priv->sender = sender; + + #ifdef KDBUS_DEBUG + g_print ("g_kdbus_send_reply: sender set to:%s! \n", kdbus->priv->sender); + #endif + + //g_dbus_message_set_body(reply, g_variant_new ("(s)", unique_name)); + g_dbus_message_set_body (reply, g_variant_new ("(s)",sender)); + _g_dbus_worker_queue_or_deliver_received_message (worker, reply); + + g_free (unique_name); + g_free (sender); + return TRUE; +} + +/* + * g_kdbus_send_message: + * TODO: Handle errors + */ +gssize +g_kdbus_send_message (GDBusWorker *worker, + GKdbus *kdbus, + GDBusMessage *dbus_msg, + gchar *blob, + gsize blob_size, + GError **error) +{ + struct kdbus_msg* kmsg; + struct kdbus_item *item; + guint64 kmsg_size = 0; + const gchar *name; + guint64 dst_id = KDBUS_DST_ID_BROADCAST; + + if (kdbus->priv->registered == FALSE) + { + if (!g_kdbus_register(kdbus)) + { + g_error (" KDBUS_DEBUG: (%s()): registering failed!\n",__FUNCTION__); + return -1; + } + + if (g_strcmp0(g_dbus_message_get_member(dbus_msg), "Hello") == 0) + { + #ifdef KDBUS_DEBUG + g_print (" KDBUS_DEBUG: (%s()): sending \"Hello\" message!\n",__FUNCTION__); + #endif + + g_kdbus_send_reply(worker, kdbus, dbus_msg); + goto out; + } + } + + if ((name = g_dbus_message_get_destination(dbus_msg))) + { + dst_id = KDBUS_DST_ID_WELL_KNOWN_NAME; + if ((name[0] == ':') && (name[1] == '1') && (name[2] == '.')) + { + dst_id = strtoull(&name[3], NULL, 10); + name=NULL; + } + } + + kmsg_size = sizeof(struct kdbus_msg); + kmsg_size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_vec)); //vector for blob + + if (name) + kmsg_size += KDBUS_ITEM_SIZE(strlen(name) + 1); + else if (dst_id == KDBUS_DST_ID_BROADCAST) + kmsg_size += KDBUS_PART_HEADER_SIZE + kdbus->priv->bloom_size; + + kmsg = malloc(kmsg_size); + if (!kmsg) + { + //TODO: Handle error + g_error (" KDBUS_DEBUG: (%s()): kmsg malloc error\n",__FUNCTION__); + return -1; + } + + memset(kmsg, 0, kmsg_size); + kmsg->size = kmsg_size; + kmsg->payload_type = KDBUS_PAYLOAD_DBUS1; + kmsg->dst_id = name ? 0 : dst_id; + kmsg->src_id = kdbus->priv->peer_id; + kmsg->cookie = g_dbus_message_get_serial(dbus_msg); + + #ifdef KDBUS_DEBUG + g_print (" KDBUS_DEBUG: (%s()): destination name: %s\n",__FUNCTION__,name); + g_print (" KDBUS_DEBUG: (%s()): blob size: %d\n",__FUNCTION__,(gint)blob_size); + g_print (" KDBUS_DEBUG: (%s()): serial: %i\n",__FUNCTION__,kmsg->cookie); + g_print (" KDBUS_DEBUG: (%s()): src_id/peer_id: %i\n",__FUNCTION__,kdbus->priv->peer_id); + #endif + + //build message contents + item = kmsg->items; + MSG_ITEM_BUILD_VEC(blob, blob_size); + + if (name) + { + item = KDBUS_PART_NEXT(item); + item->type = KDBUS_MSG_DST_NAME; + item->size = KDBUS_PART_HEADER_SIZE + strlen(name) + 1; + strcpy(item->str, name); + } + else if (dst_id == KDBUS_DST_ID_BROADCAST) + { + item = KDBUS_PART_NEXT(item); + item->type = KDBUS_MSG_BLOOM; + item->size = KDBUS_PART_HEADER_SIZE + kdbus->priv->bloom_size; + strncpy(item->data,g_dbus_message_get_interface(dbus_msg),kdbus->priv->bloom_size); + } + +again: + if (ioctl(kdbus->priv->fd, KDBUS_CMD_MSG_SEND, kmsg)) + { + if(errno == EINTR) + goto again; + else + g_error (" KDBUS_DEBUG: (%s()): ioctl error sending kdbus message:%d (%m)\n",__FUNCTION__,errno); + } + + #ifdef KDBUS_DEBUG + g_print (" KDBUS_DEBUG: (%s()): ioctl(CMD_MSG_SEND) sent successfully\n",__FUNCTION__); + #endif + + free(kmsg); + +out: + return blob_size; +} + diff --git a/gio/gkdbus.h b/gio/gkdbus.h new file mode 100644 index 000000000..1e6a25d09 --- /dev/null +++ b/gio/gkdbus.h @@ -0,0 +1,113 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright © 2013 Samsung + * + * 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. + * + * Authors: Michal Eljasiewicz <m.eljasiewic@samsung.com> + * Authors: Lukasz Skalski <l.skalski@partner.samsung.com> + */ + +#ifndef __G_KDBUS_H__ +#define __G_KDBUS_H__ + +#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION) +#error "Only <gio/gio.h> can be included directly." +#endif + +#include <gio/giotypes.h> +#include "gdbusprivate.h" + +G_BEGIN_DECLS + +#define G_TYPE_KDBUS (g_kdbus_get_type ()) +#define G_KDBUS(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \ + G_TYPE_KDBUS, GKdbus)) +#define G_KDBUS_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class), \ + G_TYPE_KDBUS, GKdbusClass)) +#define G_IS_KDBUS(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \ + G_TYPE_KDBUS)) +#define G_IS_KDBUS_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), \ + G_TYPE_KDBUS)) +#define G_KDBUS_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), \ + G_TYPE_KDBUS, GKdbusClass)) + +typedef struct _GKdbusPrivate GKdbusPrivate; +typedef struct _GKdbusClass GKdbusClass; + +struct _GKdbusClass +{ + GObjectClass parent_class; + + /*< 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); + void (*_g_reserved9) (void); + void (*_g_reserved10) (void); +}; + +struct _GKdbus +{ + GObject parent_instance; + GKdbusPrivate *priv; +}; + +GLIB_AVAILABLE_IN_ALL +GType g_kdbus_get_type (void) G_GNUC_CONST; +GLIB_AVAILABLE_IN_ALL +gint g_kdbus_get_fd (GKdbus *kdbus); +GLIB_AVAILABLE_IN_ALL +gboolean g_kdbus_open (GKdbus *kdbus, + const gchar *address, + GCancellable *cancellable, + GError **error); +GLIB_AVAILABLE_IN_ALL +gboolean g_kdbus_close (GKdbus *kdbus, + GError **error); +GLIB_AVAILABLE_IN_ALL +gboolean g_kdbus_is_closed (GKdbus *kdbus); +GLIB_AVAILABLE_IN_ALL +gssize g_kdbus_receive (GKdbus *kdbus, + char *data, + GError **error); +GLIB_AVAILABLE_IN_ALL +gssize g_kdbus_send_message (GDBusWorker *worker, + GKdbus *kdbus, + GDBusMessage *dbus_msg, + gchar *blob, + gsize blob_size, + GError **error); +GLIB_AVAILABLE_IN_ALL +gboolean g_kdbus_register (GKdbus *kdbus); +GLIB_AVAILABLE_IN_ALL +GSource * g_kdbus_create_source (GKdbus *kdbus, + GIOCondition condition, + GCancellable *cancellable); +GLIB_AVAILABLE_IN_ALL +GIOCondition g_kdbus_condition_check (GKdbus *kdbus, + GIOCondition condition); + +G_END_DECLS + +#endif /* __G_KDBUS_H__ */ diff --git a/gio/gkdbusconnection.c b/gio/gkdbusconnection.c new file mode 100644 index 000000000..c4ec1a0ad --- /dev/null +++ b/gio/gkdbusconnection.c @@ -0,0 +1,206 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright © 2013 Samsung + * + * 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. + * + * Authors: Michal Eljasiewicz <m.eljasiewic@samsung.com> + * Authors: Lukasz Skalski <l.skalski@partner.samsung.com> + */ + +#include <fcntl.h> +#include "config.h" + +#include <gio/gtask.h> + +#include "gkdbusconnection.h" +#include "gunixconnection.h" + + +/** + * SECTION:gkdbusconnection + * @short_description: A kdbus connection + * @include: gio/gio.h + * @see_also: #GIOStream, #GKdbusClient + * + * #GKdbusConnection is a #GIOStream for a connected kdbus bus. + */ + +G_DEFINE_TYPE (GKdbusConnection, g_kdbus_connection, G_TYPE_IO_STREAM); + +struct _GKdbusConnectionPrivate +{ + GKdbus *kdbus; + gboolean in_dispose; +}; + +/* + * g_kdbus_connection_new: + * + */ +GKdbusConnection * +g_kdbus_connection_new (void) +{ + return g_object_new(G_TYPE_KDBUS_CONNECTION,NULL); +} + +/* + * g_kdbus_connection_connect: + * + */ +gboolean +g_kdbus_connection_connect (GKdbusConnection *connection, + const gchar *address, + GCancellable *cancellable, + GError **error) +{ + g_return_val_if_fail (G_IS_KDBUS_CONNECTION (connection), FALSE); + + return g_kdbus_open (connection->priv->kdbus,address,cancellable,error); +} + +/* + * g_kdbus_connection_is_connected: + * + */ +gboolean +g_kdbus_connection_is_connected (GKdbusConnection *connection) +{ + return (!g_kdbus_is_closed (connection->priv->kdbus)); +} + +/* + * g_kdbus_connection_get_property: + * + */ +static void +g_kdbus_connection_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + //GKdbusConnection *connection = G_KDBUS_CONNECTION (object); + switch (prop_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +/* + * g_kdbus_connection_set_property + * + */ +static void +g_kdbus_connection_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + //GKdbusConnection *connection = G_KDBUS_CONNECTION (object); + switch (prop_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +// TODO +static void +g_kdbus_connection_dispose (GObject *object) +{ + GKdbusConnection *connection = G_KDBUS_CONNECTION (object); + + connection->priv->in_dispose = TRUE; + + G_OBJECT_CLASS (g_kdbus_connection_parent_class) + ->dispose (object); + + connection->priv->in_dispose = FALSE; +} + +/* + * g_kdbus_connection_finalize: + * + */ +static void +g_kdbus_connection_finalize (GObject *object) +{ + //GKdbusConnection *connection = G_KDBUS_CONNECTION (object); + G_OBJECT_CLASS (g_kdbus_connection_parent_class) + ->finalize (object); +} + +/* + * g_kdbus_connection_close + * + */ +gboolean +g_kdbus_connection_close (GIOStream *stream, + GCancellable *cancellable, + GError **error) +{ + GKdbusConnection *connection = G_KDBUS_CONNECTION (stream); + + if (connection->priv->in_dispose) + return TRUE; + + return g_kdbus_close (connection->priv->kdbus, error); + return TRUE; +} + +/* + * g_kdbus_connection_class_init: + * + */ +static void +g_kdbus_connection_class_init (GKdbusConnectionClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (GKdbusConnectionPrivate)); + + gobject_class->set_property = g_kdbus_connection_set_property; + gobject_class->get_property = g_kdbus_connection_get_property; + gobject_class->finalize = g_kdbus_connection_finalize; + gobject_class->dispose = g_kdbus_connection_dispose; +} + +/* + * g_kdbus_connection_init: + * + */ +static void +g_kdbus_connection_init (GKdbusConnection *connection) +{ + connection->priv = G_TYPE_INSTANCE_GET_PRIVATE (connection, + G_TYPE_KDBUS_CONNECTION, + GKdbusConnectionPrivate); + connection->priv->kdbus = g_object_new(G_TYPE_KDBUS,NULL); +} + +/* + * g_kdbus_connection_get_kdbus: gets the underlying #GKdbus object of the connection. + * + */ +GKdbus * +g_kdbus_connection_get_kdbus (GKdbusConnection *connection) +{ + g_return_val_if_fail (G_IS_KDBUS_CONNECTION (connection), NULL); + + return connection->priv->kdbus; +} + diff --git a/gio/gkdbusconnection.h b/gio/gkdbusconnection.h new file mode 100644 index 000000000..716c9bca4 --- /dev/null +++ b/gio/gkdbusconnection.h @@ -0,0 +1,91 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright © 2013 Samsung + * + * 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. + * + * Authors: Michal Eljasiewicz <m.eljasiewic@samsung.com> + * Authors: Lukasz Skalski <l.skalski@partner.samsung.com> + */ + +#ifndef __G_KDBUS_CONNECTION_H__ +#define __G_KDBUS_CONNECTION_H__ + +#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION) +#error "Only <gio/gio.h> can be included directly." +#endif + +#include <glib-object.h> +#include <gio/gkdbus.h> +#include <gio/giostream.h> + +G_BEGIN_DECLS + +#define G_TYPE_KDBUS_CONNECTION (g_kdbus_connection_get_type ()) +#define G_KDBUS_CONNECTION(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \ + G_TYPE_KDBUS_CONNECTION, GKdbusConnection)) +#define G_KDBUS_CONNECTION_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class), \ + G_TYPE_KDBUS_CONNECTION, GKdbusConnectionClass)) +#define G_IS_KDBUS_CONNECTION(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \ + G_TYPE_KDBUS_CONNECTION)) +#define G_IS_KDBUS_CONNECTION_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), \ + G_TYPE_KDBUS_CONNECTION)) +#define G_KDBUS_CONNECTION_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), \ + G_TYPE_KDBUS_CONNECTION, GKdbusConnectionClass)) + +typedef struct _GKdbusConnectionPrivate GKdbusConnectionPrivate; +typedef struct _GKdbusConnectionClass GKdbusConnectionClass; + +struct _GKdbusConnectionClass +{ + GIOStreamClass parent_class; + + /* 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); +}; + +struct _GKdbusConnection +{ + GIOStream parent_instance; + GKdbusConnectionPrivate *priv; +}; + +GLIB_AVAILABLE_IN_ALL +GType g_kdbus_connection_get_type (void) G_GNUC_CONST; +GLIB_AVAILABLE_IN_ALL +GKdbusConnection *g_kdbus_connection_new (void); +GLIB_AVAILABLE_IN_ALL +gboolean g_kdbus_connection_is_connected (GKdbusConnection *connection); +GLIB_AVAILABLE_IN_ALL +gboolean g_kdbus_connection_connect (GKdbusConnection *connection, + const gchar *address, + GCancellable *cancellable, + GError **error); +GLIB_AVAILABLE_IN_ALL +gboolean g_kdbus_connection_close (GIOStream *stream, + GCancellable *cancellable, + GError **error); +GLIB_AVAILABLE_IN_ALL +GKdbus *g_kdbus_connection_get_kdbus (GKdbusConnection *connection); + +G_END_DECLS + +#endif /* __G_KDBUS_CONNECTION_H__ */ diff --git a/gio/kdbus.h b/gio/kdbus.h new file mode 100644 index 000000000..fe461013c --- /dev/null +++ b/gio/kdbus.h @@ -0,0 +1,445 @@ +/* + * Copyright (C) 2013 Kay Sievers + * Copyright (C) 2013 Greg Kroah-Hartman <gregkh@linuxfoundation.org> + * Copyright (C) 2013 Linux Foundation + * Copyright (C) 2013 Lennart Poettering + * Copyright (C) 2013 Daniel Mack <daniel@zonque.org> + * + * kdbus 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.1 of the License, or (at + * your option) any later version. + */ + +#ifndef _KDBUS_H_ +#define _KDBUS_H_ + +#include <sys/ioctl.h> +#include <sys/types.h> +#include <linux/types.h> + +/* todo #define KDBUS_MSG_MAX_PAYLOAD_VEC_SIZE SZ_8M - maximum size of message header and items + * taken from internal.h of kdbus + * finally it should be placed higher - e.g. kdbus.h of kdbus kernel module + */ +#define KDBUS_MSG_MAX_PAYLOAD_VEC_SIZE 0x00800000 /* maximum size of message header and items */ + +#define KDBUS_IOC_MAGIC 0x95 +#define KDBUS_SRC_ID_KERNEL (0) +#define KDBUS_DST_ID_WELL_KNOWN_NAME (0) +#define KDBUS_MATCH_SRC_ID_ANY (~0ULL) +#define KDBUS_DST_ID_BROADCAST (~0ULL) + +/* Common first elements in a structure which are used to iterate over + * a list of elements. */ +#define KDBUS_PART_HEADER \ + struct { \ + __u64 size; \ + __u64 type; \ + } + +#define KDBUS_PART_HEADER_SIZE offsetof(struct kdbus_item, data) + +/* Message sent from kernel to userspace, when the owner or starter of + * a well-known name changes */ +struct kdbus_manager_msg_name_change { + __u64 old_id; + __u64 new_id; + __u64 flags; /* 0 or (possibly?) KDBUS_NAME_IN_QUEUE */ + char name[0]; +}; + +struct kdbus_manager_msg_id_change { + __u64 id; + __u64 flags; /* The kernel flags field from KDBUS_HELLO */ +}; + +struct kdbus_creds { + __u64 uid; + __u64 gid; + __u64 pid; + __u64 tid; + + /* The starttime of the process PID. This is useful to detect + PID overruns from the client side. i.e. if you use the PID to + look something up in /proc/$PID/ you can afterwards check the + starttime field of it to ensure you didn't run into a PID + ovretun. */ + __u64 starttime; +}; + +struct kdbus_audit { + __u64 sessionid; + __u64 loginuid; +}; + +struct kdbus_timestamp { + __u64 monotonic_ns; + __u64 realtime_ns; +}; + +struct kdbus_vec { + __u64 size; + union { + __u64 address; + __u64 offset; + }; +}; + +struct kdbus_memfd { + __u64 size; + int fd; + __u32 __pad; +}; + +/* Message Item Types */ +enum { + _KDBUS_MSG_NULL, + + /* Filled in by userspace */ + KDBUS_MSG_PAYLOAD_VEC, /* .data_vec, reference to memory area */ + KDBUS_MSG_PAYLOAD_OFF, /* .data_vec, reference to memory area */ + KDBUS_MSG_PAYLOAD_MEMFD, /* file descriptor of a special data file */ + KDBUS_MSG_FDS, /* .data_fds of file descriptors */ + KDBUS_MSG_BLOOM, /* for broadcasts, carries bloom filter blob in .data */ + KDBUS_MSG_DST_NAME, /* destination's well-known name, in .str */ + KDBUS_MSG_PRIORITY, /* queue priority for message */ + + /* Filled in by kernelspace */ + KDBUS_MSG_SRC_NAMES = 0x400,/* NUL separated string list with well-known names of source */ + KDBUS_MSG_TIMESTAMP, /* .timestamp */ + KDBUS_MSG_SRC_CREDS, /* .creds */ + KDBUS_MSG_SRC_PID_COMM, /* optional, in .str */ + KDBUS_MSG_SRC_TID_COMM, /* optional, in .str */ + KDBUS_MSG_SRC_EXE, /* optional, in .str */ + KDBUS_MSG_SRC_CMDLINE, /* optional, in .str (a chain of NUL str) */ + KDBUS_MSG_SRC_CGROUP, /* optional, in .str */ + KDBUS_MSG_SRC_CAPS, /* caps data blob, in .data */ + KDBUS_MSG_SRC_SECLABEL, /* NUL terminated string, in .str */ + KDBUS_MSG_SRC_AUDIT, /* .audit */ + + /* Special messages from kernel, consisting of one and only one of these data blocks */ + KDBUS_MSG_NAME_ADD = 0x800,/* .name_change */ + KDBUS_MSG_NAME_REMOVE, /* .name_change */ + KDBUS_MSG_NAME_CHANGE, /* .name_change */ + KDBUS_MSG_ID_ADD, /* .id_change */ + KDBUS_MSG_ID_REMOVE, /* .id_change */ + KDBUS_MSG_REPLY_TIMEOUT, /* empty, but .reply_cookie in .kdbus_msg is filled in */ + KDBUS_MSG_REPLY_DEAD, /* dito */ +}; + +/** + * struct kdbus_item - chain of data blocks + * + * size: overall data record size + * type: kdbus_item type of data + */ +struct kdbus_item { + KDBUS_PART_HEADER; + union { + /* inline data */ + __u8 data[0]; + __u32 data32[0]; + __u64 data64[0]; + char str[0]; + + /* connection */ + __u64 id; + + /* data vector */ + struct kdbus_vec vec; + + /* process credentials and properties*/ + struct kdbus_creds creds; + struct kdbus_audit audit; + struct kdbus_timestamp timestamp; + + /* specific fields */ + struct kdbus_memfd memfd; + int fds[0]; + struct kdbus_manager_msg_name_change name_change; + struct kdbus_manager_msg_id_change id_change; + }; +}; + +enum { + KDBUS_MSG_FLAGS_EXPECT_REPLY = 1 << 0, + KDBUS_MSG_FLAGS_NO_AUTO_START = 1 << 1, +}; + +enum { + KDBUS_PAYLOAD_KERNEL, + KDBUS_PAYLOAD_DBUS1 = 0x4442757356657231ULL, /* 'DBusVer1' */ + KDBUS_PAYLOAD_GVARIANT = 0x4756617269616e74ULL, /* 'GVariant' */ +}; + +/** + * struct kdbus_msg + * + * set by userspace: + * dst_id: destination id + * flags: KDBUS_MSG_FLAGS_* + * items: data records + * + * set by kernel: + * src_id: who sent the message + */ +struct kdbus_msg { + __u64 size; + __u64 flags; + __u64 dst_id; /* connection, 0 == name in data, ~0 broadcast */ + __u64 src_id; /* connection, 0 == kernel */ + __u64 payload_type; /* 'DBusVer1', 'GVariant', ... */ + __u64 cookie; /* userspace-supplied cookie */ + union { + __u64 cookie_reply; /* cookie we reply to */ + __u64 timeout_ns; /* timespan to wait for reply */ + }; + struct kdbus_item items[0]; +}; + +enum { + _KDBUS_POLICY_NULL, + KDBUS_POLICY_NAME, + KDBUS_POLICY_ACCESS, +}; + +enum { + _KDBUS_POLICY_ACCESS_NULL, + KDBUS_POLICY_ACCESS_USER, + KDBUS_POLICY_ACCESS_GROUP, + KDBUS_POLICY_ACCESS_WORLD, +}; + +enum { + KDBUS_POLICY_RECV = 1 << 2, + KDBUS_POLICY_SEND = 1 << 1, + KDBUS_POLICY_OWN = 1 << 0, +}; + +struct kdbus_policy_access { + __u64 type; /* USER, GROUP, WORLD */ + __u64 bits; /* RECV, SEND, OWN */ + __u64 id; /* uid, gid, 0 */ +}; + +//FIXME: convert access to access[] +struct kdbus_policy { + KDBUS_PART_HEADER; + union { + char name[0]; + struct kdbus_policy_access access; + }; +}; + +/* A series of KDBUS_POLICY_NAME, plus one or more KDBUS_POLICY_ACCESS */ +struct kdbus_cmd_policy { + __u64 size; + struct kdbus_policy policies[0]; +}; + +/* Flags for struct kdbus_cmd_hello */ +enum { + KDBUS_HELLO_STARTER = 1 << 0, + KDBUS_HELLO_ACCEPT_FD = 1 << 1, + + /* The following have an effect on directed messages only -- + * not for broadcasts */ + KDBUS_HELLO_ATTACH_COMM = 1 << 10, + KDBUS_HELLO_ATTACH_EXE = 1 << 11, + KDBUS_HELLO_ATTACH_CMDLINE = 1 << 12, + KDBUS_HELLO_ATTACH_CGROUP = 1 << 13, + KDBUS_HELLO_ATTACH_CAPS = 1 << 14, + KDBUS_HELLO_ATTACH_SECLABEL = 1 << 15, + KDBUS_HELLO_ATTACH_AUDIT = 1 << 16, +}; + +struct kdbus_cmd_hello { + __u64 size; + + /* userspace → kernel, kernel → userspace */ + __u64 conn_flags; /* userspace specifies its + * capabilities and more, kernel + * returns its capabilites and + * more. Kernel might refuse client's + * capabilities by returning an error + * from KDBUS_HELLO */ + + /* kernel → userspace */ + __u64 bus_flags; /* this is .flags copied verbatim from + * from original KDBUS_CMD_BUS_MAKE + * ioctl. It's intended to be useful + * to do negotiation of features of + * the payload that is transfreted. */ + __u64 id; /* id assigned to this connection */ + __u64 bloom_size; /* The bloom filter size chosen by the + * bus owner */ + __u64 pool_size; /* maximum size of pool buffer */ + struct kdbus_item items[0]; +}; + +/* Flags for kdbus_cmd_{bus,ep,ns}_make */ +enum { + KDBUS_MAKE_ACCESS_GROUP = 1 << 0, + KDBUS_MAKE_ACCESS_WORLD = 1 << 1, + KDBUS_MAKE_POLICY_OPEN = 1 << 2, +}; + +/* Items to append to kdbus_cmd_{bus,ep,ns}_make */ +enum { + _KDBUS_MAKE_NULL, + KDBUS_MAKE_NAME, + KDBUS_MAKE_CGROUP, /* the cgroup hierarchy ID for which to attach + * cgroup membership paths to messages. + * FIXME: remove, use *the* hierarchy */ + KDBUS_MAKE_CRED, /* allow translator services which connect + * to the bus on behalf of somebody else, + * allow specifiying the credentials of the + * client to connect on behalf on. Needs + * privileges */ +}; + +struct kdbus_cmd_bus_make { + __u64 size; + __u64 flags; /* userspace → kernel, kernel → userspace + * When creating a bus feature + * kernel negotiation. */ + __u64 bus_flags; /* userspace → kernel + * When a bus is created this value is + * copied verbatim into the bus + * structure and returned from + * KDBUS_CMD_HELLO, later */ + __u64 bloom_size; /* size of the bloom filter for this bus */ + struct kdbus_item items[0]; +}; + +struct kdbus_cmd_ep_make { + __u64 size; + __u64 flags; /* userspace → kernel, kernel → userspace + * When creating an entry point + * feature kernel negotiation done the + * same way as for + * KDBUS_CMD_BUS_MAKE. Unused for + * now. */ + struct kdbus_item items[0]; +}; + +struct kdbus_cmd_ns_make { + __u64 size; + __u64 flags; /* userspace → kernel, kernel → userspace + * When creating an entry point + * feature kernel negotiation done the + * same way as for + * KDBUS_CMD_BUS_MAKE. Unused for + * now. */ + struct kdbus_item items[0]; +}; + +enum { + /* userspace → kernel */ + KDBUS_NAME_REPLACE_EXISTING = 1 << 0, + KDBUS_NAME_QUEUE = 1 << 1, + KDBUS_NAME_ALLOW_REPLACEMENT = 1 << 2, + + /* kernel → userspace */ + KDBUS_NAME_IN_QUEUE = 1 << 16, +}; + +/* We allow (de)regestration of names of other peers */ +struct kdbus_cmd_name { + __u64 size; + __u64 flags; + __u64 id; + __u64 conn_flags; + char name[0]; +}; + +struct kdbus_cmd_names { + __u64 size; + struct kdbus_cmd_name names[0]; +}; + +enum { + _KDBUS_NAME_INFO_ITEM_NULL, + KDBUS_NAME_INFO_ITEM_NAME, /* userspace → kernel */ + KDBUS_NAME_INFO_ITEM_SECLABEL, /* kernel → userspace */ + KDBUS_NAME_INFO_ITEM_AUDIT, /* kernel → userspace */ +}; + +struct kdbus_cmd_name_info { + __u64 size; /* overall size of info */ + __u64 flags; + __u64 id; /* either ID, or 0 and _ITEM_NAME follows */ + struct kdbus_creds creds; + struct kdbus_item items[0]; /* list of item records */ +}; + +enum { + _KDBUS_MATCH_NULL, + KDBUS_MATCH_BLOOM, /* Matches a mask blob against KDBUS_MSG_BLOOM */ + KDBUS_MATCH_SRC_NAME, /* Matches a name string against KDBUS_MSG_SRC_NAMES */ + KDBUS_MATCH_NAME_ADD, /* Matches a name string against KDBUS_MSG_NAME_ADD */ + KDBUS_MATCH_NAME_REMOVE, /* Matches a name string against KDBUS_MSG_NAME_REMOVE */ + KDBUS_MATCH_NAME_CHANGE, /* Matches a name string against KDBUS_MSG_NAME_CHANGE */ + KDBUS_MATCH_ID_ADD, /* Matches an ID against KDBUS_MSG_ID_ADD */ + KDBUS_MATCH_ID_REMOVE, /* Matches an ID against KDBUS_MSG_ID_REMOVE */ +}; + +struct kdbus_cmd_match { + __u64 size; + __u64 id; /* We allow registration/deregestration of matches for other peers */ + __u64 cookie; /* userspace supplied cookie; when removing; kernel deletes everything with same cookie */ + __u64 src_id; /* ~0: any. other: exact unique match */ + struct kdbus_item items[0]; +}; + +struct kdbus_cmd_monitor { + __u64 id; /* We allow setting the monitor flag of other peers */ + unsigned int enable; /* A boolean to enable/disable monitoring */ + __u32 __pad; +}; + +/* FD states: + * control nodes: unset + * bus owner (via KDBUS_CMD_BUS_MAKE) + * ns owner (via KDBUS_CMD_NS_MAKE) + * + * ep nodes: unset + * connected (via KDBUS_CMD_HELLO) + * starter (via KDBUS_CMD_HELLO with KDBUS_CMD_HELLO_STARTER) + * ep owner (via KDBUS_CMD_EP_MAKE) + */ +enum { + /* kdbus control node commands: require unset state */ + KDBUS_CMD_BUS_MAKE = _IOW(KDBUS_IOC_MAGIC, 0x00, struct kdbus_cmd_bus_make), + KDBUS_CMD_NS_MAKE = _IOR(KDBUS_IOC_MAGIC, 0x10, struct kdbus_cmd_ns_make), + + /* kdbus ep node commands: require unset state */ + KDBUS_CMD_EP_MAKE = _IOW(KDBUS_IOC_MAGIC, 0x20, struct kdbus_cmd_ep_make), + KDBUS_CMD_HELLO = _IOWR(KDBUS_IOC_MAGIC, 0x30, struct kdbus_cmd_hello), + + /* kdbus ep node commands: require connected state */ + KDBUS_CMD_MSG_SEND = _IOW(KDBUS_IOC_MAGIC, 0x40, struct kdbus_msg), + KDBUS_CMD_MSG_RECV = _IOR(KDBUS_IOC_MAGIC, 0x41, __u64 *), + KDBUS_CMD_MSG_RELEASE = _IOW(KDBUS_IOC_MAGIC, 0x42, __u64 *), + + KDBUS_CMD_NAME_ACQUIRE = _IOWR(KDBUS_IOC_MAGIC, 0x50, struct kdbus_cmd_name), + KDBUS_CMD_NAME_RELEASE = _IOW(KDBUS_IOC_MAGIC, 0x51, struct kdbus_cmd_name), + KDBUS_CMD_NAME_LIST = _IOWR(KDBUS_IOC_MAGIC, 0x52, struct kdbus_cmd_names), + KDBUS_CMD_NAME_QUERY = _IOWR(KDBUS_IOC_MAGIC, 0x53, struct kdbus_cmd_name_info), + + KDBUS_CMD_MATCH_ADD = _IOW(KDBUS_IOC_MAGIC, 0x60, struct kdbus_cmd_match), + KDBUS_CMD_MATCH_REMOVE = _IOW(KDBUS_IOC_MAGIC, 0x61, struct kdbus_cmd_match), + KDBUS_CMD_MONITOR = _IOW(KDBUS_IOC_MAGIC, 0x62, struct kdbus_cmd_monitor), + + /* kdbus ep node commands: require ep owner state */ + KDBUS_CMD_EP_POLICY_SET = _IOW(KDBUS_IOC_MAGIC, 0x70, struct kdbus_cmd_policy), + + /* kdbus memfd commands: */ + KDBUS_CMD_MEMFD_NEW = _IOR(KDBUS_IOC_MAGIC, 0x80, int *), + KDBUS_CMD_MEMFD_SIZE_GET = _IOR(KDBUS_IOC_MAGIC, 0x81, __u64 *), + KDBUS_CMD_MEMFD_SIZE_SET = _IOW(KDBUS_IOC_MAGIC, 0x82, __u64 *), + KDBUS_CMD_MEMFD_SEAL_GET = _IOR(KDBUS_IOC_MAGIC, 0x83, int *), + KDBUS_CMD_MEMFD_SEAL_SET = _IO(KDBUS_IOC_MAGIC, 0x84), +}; +#endif diff --git a/glib/gmain.c b/glib/gmain.c index 68a7f8e81..1746762c7 100644 --- a/glib/gmain.c +++ b/glib/gmain.c @@ -3692,7 +3692,14 @@ g_main_context_iterate (GMainContext *context, if (!block) timeout = 0; - + + #ifdef KDBUS_DEBUG + g_print (" KDBUS_DEBUG: nfds=%d\n",nfds); + g_print (" KDBUS_DEBUG: fd[0]=%d\n",fds[0].fd); + g_print (" KDBUS_DEBUG: fd[1]=%d\n",fds[1].fd); + g_print (" KDBUS_DEBUG: fd[2]=%d\n",fds[2].fd); + #endif + g_main_context_poll (context, timeout, max_priority, fds, nfds); some_ready = g_main_context_check (context, max_priority, fds, nfds); |