/* GDBus - GLib D-Bus Library
*
- * Copyright (C) 2008-2009 Red Hat, Inc.
+ * Copyright (C) 2008-2010 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
#include <stdlib.h>
#include <string.h>
-
-#ifdef G_OS_UNIX
-#include <gio/gunixconnection.h>
-#include <gio/gunixfdmessage.h>
-#include "gunixcredentialsmessage.h"
+#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "ginputstream.h"
#include "giostream.h"
#include "gsocketcontrolmessage.h"
+#include "gsocketconnection.h"
#ifdef G_OS_UNIX
-#include <unistd.h>
#include "gunixfdmessage.h"
#include "gunixconnection.h"
+#include "gunixcredentialsmessage.h"
+#endif
+
+#ifdef G_OS_WIN32
+#include <windows.h>
#endif
#include "glibintl.h"
+#include "gioalias.h"
/* ---------------------------------------------------------------------------------------------------- */
-static gchar *
-hexdump (const gchar *data, gsize len, guint indent)
+gchar *
+_g_dbus_hexdump (const gchar *data, gsize len, guint indent)
{
guint n, m;
GString *ret;
GDBusCapabilityFlags capabilities;
GCancellable *cancellable;
GDBusWorkerMessageReceivedCallback message_received_callback;
+ GDBusWorkerMessageAboutToBeSentCallback message_about_to_be_sent_callback;
GDBusWorkerDisconnectedCallback disconnected_callback;
gpointer user_data;
}
static void
-_g_dbus_worker_emit_message (GDBusWorker *worker,
- GDBusMessage *message)
+_g_dbus_worker_emit_message_received (GDBusWorker *worker,
+ GDBusMessage *message)
{
if (!worker->stopped)
worker->message_received_callback (worker, message, worker->user_data);
}
+static gboolean
+_g_dbus_worker_emit_message_about_to_be_sent (GDBusWorker *worker,
+ GDBusMessage *message)
+{
+ gboolean ret;
+ ret = FALSE;
+ if (!worker->stopped)
+ ret = worker->message_about_to_be_sent_callback (worker, message, worker->user_data);
+ return ret;
+}
+
static void _g_dbus_worker_do_read_unlocked (GDBusWorker *worker);
/* called in private thread shared by all GDBusConnection instances (without read-lock held) */
message = g_dbus_message_new_from_blob ((guchar *) worker->read_buffer,
worker->read_buffer_cur_size,
+ worker->capabilities,
&error);
if (message == NULL)
{
+ gchar *s;
+ s = _g_dbus_hexdump (worker->read_buffer, worker->read_buffer_cur_size, 2);
+ g_warning ("Error decoding D-Bus message of %" G_GSIZE_FORMAT " bytes\n"
+ "The error is: %s\n"
+ "The payload is as follows:\n"
+ "%s\n",
+ worker->read_buffer_cur_size,
+ error->message,
+ s);
+ g_free (s);
_g_dbus_worker_emit_disconnected (worker, FALSE, error);
g_error_free (error);
goto out;
}
+#ifdef G_OS_UNIX
if (worker->read_fd_list != NULL)
{
g_dbus_message_set_unix_fd_list (message, worker->read_fd_list);
worker->read_fd_list = NULL;
}
+#endif
if (G_UNLIKELY (_g_dbus_debug_message ()))
{
s = g_dbus_message_print (message, 2);
g_print ("%s", s);
g_free (s);
- s = hexdump (worker->read_buffer, worker->read_buffer_cur_size, 2);
+ s = _g_dbus_hexdump (worker->read_buffer, worker->read_buffer_cur_size, 2);
g_print ("%s\n", s);
g_free (s);
}
/* yay, got a message, go deliver it */
- _g_dbus_worker_emit_message (worker, message);
+ _g_dbus_worker_emit_message_received (worker, message);
g_object_unref (message);
/* start reading another message! */
/* ---------------------------------------------------------------------------------------------------- */
-/* called in private thread shared by all GDBusConnection instances (with write-lock held) */
+/* called in private thread shared by all GDBusConnection instances (without write-lock held) */
static gboolean
write_message (GDBusWorker *worker,
MessageToWriteData *data,
s = g_dbus_message_print (data->message, 2);
g_print ("%s", s);
g_free (s);
- s = hexdump (data->blob, data->blob_size, 2);
+ s = _g_dbus_hexdump (data->blob, data->blob_size, 2);
g_print ("%s\n", s);
g_free (s);
}
GDBusWorker *worker = user_data;
gboolean more_writes_are_pending;
MessageToWriteData *data;
+ gboolean message_was_dropped;
GError *error;
g_mutex_lock (worker->write_lock);
-
data = g_queue_pop_head (worker->write_queue);
g_assert (data != NULL);
+ more_writes_are_pending = (g_queue_get_length (worker->write_queue) > 0);
+ worker->write_is_pending = more_writes_are_pending;
+ g_mutex_unlock (worker->write_lock);
- error = NULL;
- if (!write_message (worker,
- data,
- &error))
+ /* Note that write_lock is only used for protecting the @write_queue
+ * and @write_is_pending fields of the GDBusWorker struct ... which we
+ * need to modify from arbitrary threads in _g_dbus_worker_send_message().
+ *
+ * Therefore, it's fine to drop it here when calling back into user
+ * code and then writing the message out onto the GIOStream since this
+ * function only runs on the worker thread.
+ */
+ message_was_dropped = _g_dbus_worker_emit_message_about_to_be_sent (worker, data->message);
+ if (G_LIKELY (!message_was_dropped))
{
- /* TODO: handle */
- _g_dbus_worker_emit_disconnected (worker, TRUE, error);
- g_error_free (error);
+ error = NULL;
+ if (!write_message (worker,
+ data,
+ &error))
+ {
+ /* TODO: handle */
+ _g_dbus_worker_emit_disconnected (worker, TRUE, error);
+ g_error_free (error);
+ }
}
message_to_write_data_free (data);
- more_writes_are_pending = (g_queue_get_length (worker->write_queue) > 0);
-
- worker->write_is_pending = more_writes_are_pending;
- g_mutex_unlock (worker->write_lock);
-
return more_writes_are_pending;
}
}
GDBusWorker *
-_g_dbus_worker_new (GIOStream *stream,
- GDBusCapabilityFlags capabilities,
- GDBusWorkerMessageReceivedCallback message_received_callback,
- GDBusWorkerDisconnectedCallback disconnected_callback,
- gpointer user_data)
+_g_dbus_worker_new (GIOStream *stream,
+ GDBusCapabilityFlags capabilities,
+ GDBusWorkerMessageReceivedCallback message_received_callback,
+ GDBusWorkerMessageAboutToBeSentCallback message_about_to_be_sent_callback,
+ GDBusWorkerDisconnectedCallback disconnected_callback,
+ gpointer user_data)
{
GDBusWorker *worker;
g_return_val_if_fail (G_IS_IO_STREAM (stream), NULL);
g_return_val_if_fail (message_received_callback != NULL, NULL);
+ g_return_val_if_fail (message_about_to_be_sent_callback != NULL, NULL);
g_return_val_if_fail (disconnected_callback != NULL, NULL);
worker = g_new0 (GDBusWorker, 1);
worker->read_lock = g_mutex_new ();
worker->message_received_callback = message_received_callback;
+ worker->message_about_to_be_sent_callback = message_about_to_be_sent_callback;
worker->disconnected_callback = disconnected_callback;
worker->user_data = user_data;
worker->stream = g_object_ref (stream);
/* ---------------------------------------------------------------------------------------------------- */
-gchar *
-_g_dbus_compute_complete_signature (GDBusArgInfo **args,
- gboolean include_parentheses)
+GVariantType *
+_g_dbus_compute_complete_signature (GDBusArgInfo **args)
{
- GString *s;
+ const GVariantType *arg_types[256];
guint n;
- if (include_parentheses)
- s = g_string_new ("(");
- else
- s = g_string_new ("");
- if (args != NULL)
+ if (args)
for (n = 0; args[n] != NULL; n++)
- g_string_append (s, args[n]->signature);
+ {
+ /* DBus places a hard limit of 255 on signature length.
+ * therefore number of args must be less than 256.
+ */
+ g_assert (n < 256);
+
+ arg_types[n] = G_VARIANT_TYPE (args[n]->signature);
+
+ if G_UNLIKELY (arg_types[n] == NULL)
+ return NULL;
+ }
+ else
+ n = 0;
+
+ return g_variant_type_new_tuple (arg_types, n);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+#ifdef G_OS_WIN32
+
+extern BOOL WINAPI ConvertSidToStringSidA (PSID Sid, LPSTR *StringSid);
+
+gchar *
+_g_dbus_win32_get_user_sid (void)
+{
+ HANDLE h;
+ TOKEN_USER *user;
+ DWORD token_information_len;
+ PSID psid;
+ gchar *sid;
+ gchar *ret;
+
+ ret = NULL;
+ user = NULL;
+ h = INVALID_HANDLE_VALUE;
+
+ if (!OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &h))
+ {
+ g_warning ("OpenProcessToken failed with error code %d", (gint) GetLastError ());
+ goto out;
+ }
+
+ /* Get length of buffer */
+ token_information_len = 0;
+ if (!GetTokenInformation (h, TokenUser, NULL, 0, &token_information_len))
+ {
+ if (GetLastError () != ERROR_INSUFFICIENT_BUFFER)
+ {
+ g_warning ("GetTokenInformation() failed with error code %d", (gint) GetLastError ());
+ goto out;
+ }
+ }
+ user = g_malloc (token_information_len);
+ if (!GetTokenInformation (h, TokenUser, user, token_information_len, &token_information_len))
+ {
+ g_warning ("GetTokenInformation() failed with error code %d", (gint) GetLastError ());
+ goto out;
+ }
- if (include_parentheses)
- g_string_append_c (s, ')');
+ psid = user->User.Sid;
+ if (!IsValidSid (psid))
+ {
+ g_warning ("Invalid SID");
+ goto out;
+ }
- return g_string_free (s, FALSE);
+ if (!ConvertSidToStringSidA (psid, &sid))
+ {
+ g_warning ("Invalid SID");
+ goto out;
+ }
+
+ ret = g_strdup (sid);
+ LocalFree (sid);
+
+out:
+ g_free (user);
+ if (h != INVALID_HANDLE_VALUE)
+ CloseHandle (h);
+ return ret;
}
+#endif
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+#define __G_DBUS_PRIVATE_C__
+#include "gioaliasdef.c"