819aa340067d1350d13d6687e68a781dc33ed200
[platform/upstream/glib.git] / gio / gdbusprivate.c
1 /* GDBus - GLib D-Bus Library
2  *
3  * Copyright (C) 2008-2010 Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General
16  * Public License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18  * Boston, MA 02111-1307, USA.
19  *
20  * Author: David Zeuthen <davidz@redhat.com>
21  */
22
23 #include "config.h"
24
25 #include <stdlib.h>
26 #include <string.h>
27 #ifdef HAVE_UNISTD_H
28 #include <unistd.h>
29 #endif
30
31 #include "giotypes.h"
32 #include "gsocket.h"
33 #include "gdbusprivate.h"
34 #include "gdbusmessage.h"
35 #include "gdbuserror.h"
36 #include "gdbusintrospection.h"
37 #include "gasyncresult.h"
38 #include "gsimpleasyncresult.h"
39 #include "ginputstream.h"
40 #include "giostream.h"
41 #include "gsocketcontrolmessage.h"
42 #include "gsocketconnection.h"
43
44 #ifdef G_OS_UNIX
45 #include "gunixfdmessage.h"
46 #include "gunixconnection.h"
47 #include "gunixcredentialsmessage.h"
48 #endif
49
50 #ifdef G_OS_WIN32
51 #include <windows.h>
52 #endif
53
54 #include "glibintl.h"
55 #include "gioalias.h"
56
57 /* ---------------------------------------------------------------------------------------------------- */
58
59 gchar *
60 _g_dbus_hexdump (const gchar *data, gsize len, guint indent)
61 {
62  guint n, m;
63  GString *ret;
64
65  ret = g_string_new (NULL);
66
67  for (n = 0; n < len; n += 16)
68    {
69      g_string_append_printf (ret, "%*s%04x: ", indent, "", n);
70
71      for (m = n; m < n + 16; m++)
72        {
73          if (m > n && (m%4) == 0)
74            g_string_append_c (ret, ' ');
75          if (m < len)
76            g_string_append_printf (ret, "%02x ", (guchar) data[m]);
77          else
78            g_string_append (ret, "   ");
79        }
80
81      g_string_append (ret, "   ");
82
83      for (m = n; m < len && m < n + 16; m++)
84        g_string_append_c (ret, g_ascii_isprint (data[m]) ? data[m] : '.');
85
86      g_string_append_c (ret, '\n');
87    }
88
89  return g_string_free (ret, FALSE);
90 }
91
92 /* ---------------------------------------------------------------------------------------------------- */
93
94 /* Unfortunately ancillary messages are discarded when reading from a
95  * socket using the GSocketInputStream abstraction. So we provide a
96  * very GInputStream-ish API that uses GSocket in this case (very
97  * similar to GSocketInputStream).
98  */
99
100 typedef struct
101 {
102   GSocket *socket;
103   GCancellable *cancellable;
104
105   void *buffer;
106   gsize count;
107
108   GSocketControlMessage ***messages;
109   gint *num_messages;
110
111   GSimpleAsyncResult *simple;
112
113   gboolean from_mainloop;
114 } ReadWithControlData;
115
116 static void
117 read_with_control_data_free (ReadWithControlData *data)
118 {
119   g_object_unref (data->socket);
120   if (data->cancellable != NULL)
121     g_object_unref (data->cancellable);
122   g_object_unref (data->simple);
123   g_free (data);
124 }
125
126 static gboolean
127 _g_socket_read_with_control_messages_ready (GSocket      *socket,
128                                             GIOCondition  condition,
129                                             gpointer      user_data)
130 {
131   ReadWithControlData *data = user_data;
132   GError *error;
133   gssize result;
134   GInputVector vector;
135
136   error = NULL;
137   vector.buffer = data->buffer;
138   vector.size = data->count;
139   result = g_socket_receive_message (data->socket,
140                                      NULL, /* address */
141                                      &vector,
142                                      1,
143                                      data->messages,
144                                      data->num_messages,
145                                      NULL,
146                                      data->cancellable,
147                                      &error);
148   if (result >= 0)
149     {
150       g_simple_async_result_set_op_res_gssize (data->simple, result);
151     }
152   else
153     {
154       g_assert (error != NULL);
155       g_simple_async_result_set_from_error (data->simple, error);
156       g_error_free (error);
157     }
158
159   if (data->from_mainloop)
160     g_simple_async_result_complete (data->simple);
161   else
162     g_simple_async_result_complete_in_idle (data->simple);
163
164   return FALSE;
165 }
166
167 static void
168 _g_socket_read_with_control_messages (GSocket                 *socket,
169                                       void                    *buffer,
170                                       gsize                    count,
171                                       GSocketControlMessage ***messages,
172                                       gint                    *num_messages,
173                                       gint                     io_priority,
174                                       GCancellable            *cancellable,
175                                       GAsyncReadyCallback      callback,
176                                       gpointer                 user_data)
177 {
178   ReadWithControlData *data;
179
180   data = g_new0 (ReadWithControlData, 1);
181   data->socket = g_object_ref (socket);
182   data->cancellable = cancellable != NULL ? g_object_ref (cancellable) : NULL;
183   data->buffer = buffer;
184   data->count = count;
185   data->messages = messages;
186   data->num_messages = num_messages;
187
188   data->simple = g_simple_async_result_new (G_OBJECT (socket),
189                                             callback,
190                                             user_data,
191                                             _g_socket_read_with_control_messages);
192
193   if (!g_socket_condition_check (socket, G_IO_IN))
194     {
195       GSource *source;
196       data->from_mainloop = TRUE;
197       source = g_socket_create_source (data->socket,
198                                        G_IO_IN | G_IO_HUP | G_IO_ERR,
199                                        cancellable);
200       g_source_set_callback (source,
201                              (GSourceFunc) _g_socket_read_with_control_messages_ready,
202                              data,
203                              (GDestroyNotify) read_with_control_data_free);
204       g_source_attach (source, g_main_context_get_thread_default ());
205       g_source_unref (source);
206     }
207   else
208     {
209       _g_socket_read_with_control_messages_ready (data->socket, G_IO_IN, data);
210       read_with_control_data_free (data);
211     }
212 }
213
214 static gssize
215 _g_socket_read_with_control_messages_finish (GSocket       *socket,
216                                              GAsyncResult  *result,
217                                              GError       **error)
218 {
219   GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
220
221   g_return_val_if_fail (G_IS_SOCKET (socket), -1);
222   g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == _g_socket_read_with_control_messages);
223
224   if (g_simple_async_result_propagate_error (simple, error))
225       return -1;
226   else
227     return g_simple_async_result_get_op_res_gssize (simple);
228 }
229
230 /* ---------------------------------------------------------------------------------------------------- */
231
232 G_LOCK_DEFINE_STATIC (shared_thread_lock);
233
234 typedef struct
235 {
236   gint num_users;
237   GThread *thread;
238   GMainContext *context;
239   GMainLoop *loop;
240 } SharedThreadData;
241
242 static SharedThreadData *shared_thread_data = NULL;
243
244 static gpointer
245 shared_thread_func (gpointer data)
246 {
247   g_main_context_push_thread_default (shared_thread_data->context);
248   g_main_loop_run (shared_thread_data->loop);
249   g_main_context_pop_thread_default (shared_thread_data->context);
250   return NULL;
251 }
252
253 typedef void (*GDBusSharedThreadFunc) (gpointer user_data);
254
255 typedef struct
256 {
257   GDBusSharedThreadFunc func;
258   gpointer              user_data;
259   gboolean              done;
260 } CallerData;
261
262 static gboolean
263 invoke_caller (gpointer user_data)
264 {
265   CallerData *data = user_data;
266   data->func (data->user_data);
267   data->done = TRUE;
268   return FALSE;
269 }
270
271 static void
272 _g_dbus_shared_thread_ref (GDBusSharedThreadFunc func,
273                            gpointer              user_data)
274 {
275   GError *error;
276   GSource *idle_source;
277   CallerData *data;
278
279   G_LOCK (shared_thread_lock);
280
281   if (shared_thread_data != NULL)
282     {
283       shared_thread_data->num_users += 1;
284       goto have_thread;
285     }
286
287   shared_thread_data = g_new0 (SharedThreadData, 1);
288   shared_thread_data->num_users = 1;
289
290   error = NULL;
291   shared_thread_data->context = g_main_context_new ();
292   shared_thread_data->loop = g_main_loop_new (shared_thread_data->context, FALSE);
293   shared_thread_data->thread = g_thread_create (shared_thread_func,
294                                                 NULL,
295                                                 TRUE,
296                                                 &error);
297   g_assert_no_error (error);
298
299  have_thread:
300
301   data = g_new0 (CallerData, 1);
302   data->func = func;
303   data->user_data = user_data;
304   data->done = FALSE;
305
306   idle_source = g_idle_source_new ();
307   g_source_set_priority (idle_source, G_PRIORITY_DEFAULT);
308   g_source_set_callback (idle_source,
309                          invoke_caller,
310                          data,
311                          NULL);
312   g_source_attach (idle_source, shared_thread_data->context);
313   g_source_unref (idle_source);
314
315   /* wait for the user code to run.. hmm.. probably use a condition variable instead */
316   while (!data->done)
317     g_thread_yield ();
318
319   g_free (data);
320
321   G_UNLOCK (shared_thread_lock);
322 }
323
324 static void
325 _g_dbus_shared_thread_unref (void)
326 {
327   /* TODO: actually destroy the shared thread here */
328 #if 0
329   G_LOCK (shared_thread_lock);
330   g_assert (shared_thread_data != NULL);
331   shared_thread_data->num_users -= 1;
332   if (shared_thread_data->num_users == 0)
333     {
334       g_main_loop_quit (shared_thread_data->loop);
335       //g_thread_join (shared_thread_data->thread);
336       g_main_loop_unref (shared_thread_data->loop);
337       g_main_context_unref (shared_thread_data->context);
338       g_free (shared_thread_data);
339       shared_thread_data = NULL;
340       G_UNLOCK (shared_thread_lock);
341     }
342   else
343     {
344       G_UNLOCK (shared_thread_lock);
345     }
346 #endif
347 }
348
349 /* ---------------------------------------------------------------------------------------------------- */
350
351 struct GDBusWorker
352 {
353   volatile gint                       ref_count;
354
355   gboolean                            stopped;
356
357   /* TODO: frozen (e.g. G_DBUS_CONNECTION_FLAGS_DELAY_MESSAGE_PROCESSING) currently
358    * only affects messages received from the other peer (since GDBusServer is the
359    * only user) - we might want it to affect messages sent to the other peer too?
360    */
361   gboolean                            frozen;
362   GQueue                             *received_messages_while_frozen;
363
364   GIOStream                          *stream;
365   GDBusCapabilityFlags                capabilities;
366   GCancellable                       *cancellable;
367   GDBusWorkerMessageReceivedCallback  message_received_callback;
368   GDBusWorkerMessageAboutToBeSentCallback message_about_to_be_sent_callback;
369   GDBusWorkerDisconnectedCallback     disconnected_callback;
370   gpointer                            user_data;
371
372   GThread                            *thread;
373
374   /* if not NULL, stream is GSocketConnection */
375   GSocket *socket;
376
377   /* used for reading */
378   GMutex                             *read_lock;
379   gchar                              *read_buffer;
380   gsize                               read_buffer_allocated_size;
381   gsize                               read_buffer_cur_size;
382   gsize                               read_buffer_bytes_wanted;
383   GUnixFDList                        *read_fd_list;
384   GSocketControlMessage             **read_ancillary_messages;
385   gint                                read_num_ancillary_messages;
386
387   /* used for writing */
388   GMutex                             *write_lock;
389   GQueue                             *write_queue;
390   gboolean                            write_is_pending;
391   guint64                             write_num_messages_written;
392   GList                              *write_pending_flushes;
393 };
394
395 typedef struct
396 {
397   GMutex *mutex;
398   GCond *cond;
399   guint64 number_to_wait_for;
400 } FlushData;
401
402 struct _MessageToWriteData ;
403 typedef struct _MessageToWriteData MessageToWriteData;
404
405 static void message_to_write_data_free (MessageToWriteData *data);
406
407 static GDBusWorker *
408 _g_dbus_worker_ref (GDBusWorker *worker)
409 {
410   g_atomic_int_inc (&worker->ref_count);
411   return worker;
412 }
413
414 static void
415 _g_dbus_worker_unref (GDBusWorker *worker)
416 {
417   if (g_atomic_int_dec_and_test (&worker->ref_count))
418     {
419       g_assert (worker->write_pending_flushes == NULL);
420
421       _g_dbus_shared_thread_unref ();
422
423       g_object_unref (worker->stream);
424
425       g_mutex_free (worker->read_lock);
426       g_object_unref (worker->cancellable);
427       if (worker->read_fd_list != NULL)
428         g_object_unref (worker->read_fd_list);
429
430       g_queue_foreach (worker->received_messages_while_frozen, (GFunc) g_object_unref, NULL);
431       g_queue_free (worker->received_messages_while_frozen);
432
433       g_mutex_free (worker->write_lock);
434       g_queue_foreach (worker->write_queue, (GFunc) message_to_write_data_free, NULL);
435       g_queue_free (worker->write_queue);
436
437       g_free (worker);
438     }
439 }
440
441 static void
442 _g_dbus_worker_emit_disconnected (GDBusWorker  *worker,
443                                   gboolean      remote_peer_vanished,
444                                   GError       *error)
445 {
446   if (!worker->stopped)
447     worker->disconnected_callback (worker, remote_peer_vanished, error, worker->user_data);
448 }
449
450 static void
451 _g_dbus_worker_emit_message_received (GDBusWorker  *worker,
452                                       GDBusMessage *message)
453 {
454   if (!worker->stopped)
455     worker->message_received_callback (worker, message, worker->user_data);
456 }
457
458 static gboolean
459 _g_dbus_worker_emit_message_about_to_be_sent (GDBusWorker  *worker,
460                                               GDBusMessage *message)
461 {
462   gboolean ret;
463   ret = FALSE;
464   if (!worker->stopped)
465     ret = worker->message_about_to_be_sent_callback (worker, message, worker->user_data);
466   return ret;
467 }
468
469 /* can only be called from private thread with read-lock held - takes ownership of @message */
470 static void
471 _g_dbus_worker_queue_or_deliver_received_message (GDBusWorker  *worker,
472                                                   GDBusMessage *message)
473 {
474   if (worker->frozen || g_queue_get_length (worker->received_messages_while_frozen) > 0)
475     {
476       /* queue up */
477       g_queue_push_tail (worker->received_messages_while_frozen, message);
478     }
479   else
480     {
481       /* not frozen, nor anything in queue */
482       _g_dbus_worker_emit_message_received (worker, message);
483       g_object_unref (message);
484     }
485 }
486
487 /* called in private thread shared by all GDBusConnection instances (without read-lock held) */
488 static gboolean
489 unfreeze_in_idle_cb (gpointer user_data)
490 {
491   GDBusWorker *worker = user_data;
492   GDBusMessage *message;
493
494   g_mutex_lock (worker->read_lock);
495   if (worker->frozen)
496     {
497       while ((message = g_queue_pop_head (worker->received_messages_while_frozen)) != NULL)
498         {
499           _g_dbus_worker_emit_message_received (worker, message);
500           g_object_unref (message);
501         }
502       worker->frozen = FALSE;
503     }
504   else
505     {
506       g_assert (g_queue_get_length (worker->received_messages_while_frozen) == 0);
507     }
508   g_mutex_unlock (worker->read_lock);
509   return FALSE;
510 }
511
512 /* can be called from any thread */
513 void
514 _g_dbus_worker_unfreeze (GDBusWorker *worker)
515 {
516   GSource *idle_source;
517   idle_source = g_idle_source_new ();
518   g_source_set_priority (idle_source, G_PRIORITY_DEFAULT);
519   g_source_set_callback (idle_source,
520                          unfreeze_in_idle_cb,
521                          _g_dbus_worker_ref (worker),
522                          (GDestroyNotify) _g_dbus_worker_unref);
523   g_source_attach (idle_source, shared_thread_data->context);
524   g_source_unref (idle_source);
525 }
526
527 /* ---------------------------------------------------------------------------------------------------- */
528
529 static void _g_dbus_worker_do_read_unlocked (GDBusWorker *worker);
530
531 /* called in private thread shared by all GDBusConnection instances (without read-lock held) */
532 static void
533 _g_dbus_worker_do_read_cb (GInputStream  *input_stream,
534                            GAsyncResult  *res,
535                            gpointer       user_data)
536 {
537   GDBusWorker *worker = user_data;
538   GError *error;
539   gssize bytes_read;
540
541   g_mutex_lock (worker->read_lock);
542
543   /* If already stopped, don't even process the reply */
544   if (worker->stopped)
545     goto out;
546
547   error = NULL;
548   if (worker->socket == NULL)
549     bytes_read = g_input_stream_read_finish (g_io_stream_get_input_stream (worker->stream),
550                                              res,
551                                              &error);
552   else
553     bytes_read = _g_socket_read_with_control_messages_finish (worker->socket,
554                                                               res,
555                                                               &error);
556   if (worker->read_num_ancillary_messages > 0)
557     {
558       gint n;
559       for (n = 0; n < worker->read_num_ancillary_messages; n++)
560         {
561           GSocketControlMessage *control_message = G_SOCKET_CONTROL_MESSAGE (worker->read_ancillary_messages[n]);
562
563           if (FALSE)
564             {
565             }
566 #ifdef G_OS_UNIX
567           else if (G_IS_UNIX_FD_MESSAGE (control_message))
568             {
569               GUnixFDMessage *fd_message;
570               gint *fds;
571               gint num_fds;
572
573               fd_message = G_UNIX_FD_MESSAGE (control_message);
574               fds = g_unix_fd_message_steal_fds (fd_message, &num_fds);
575               if (worker->read_fd_list == NULL)
576                 {
577                   worker->read_fd_list = g_unix_fd_list_new_from_array (fds, num_fds);
578                 }
579               else
580                 {
581                   gint n;
582                   for (n = 0; n < num_fds; n++)
583                     {
584                       /* TODO: really want a append_steal() */
585                       g_unix_fd_list_append (worker->read_fd_list, fds[n], NULL);
586                       close (fds[n]);
587                     }
588                 }
589               g_free (fds);
590             }
591           else if (G_IS_UNIX_CREDENTIALS_MESSAGE (control_message))
592             {
593               /* do nothing */
594             }
595 #endif
596           else
597             {
598               if (error == NULL)
599                 {
600                   g_set_error (&error,
601                                G_IO_ERROR,
602                                G_IO_ERROR_FAILED,
603                                "Unexpected ancillary message of type %s received from peer",
604                                g_type_name (G_TYPE_FROM_INSTANCE (control_message)));
605                   _g_dbus_worker_emit_disconnected (worker, TRUE, error);
606                   g_error_free (error);
607                   g_object_unref (control_message);
608                   n++;
609                   while (n < worker->read_num_ancillary_messages)
610                     g_object_unref (worker->read_ancillary_messages[n++]);
611                   g_free (worker->read_ancillary_messages);
612                   goto out;
613                 }
614             }
615           g_object_unref (control_message);
616         }
617       g_free (worker->read_ancillary_messages);
618     }
619
620   if (bytes_read == -1)
621     {
622       _g_dbus_worker_emit_disconnected (worker, TRUE, error);
623       g_error_free (error);
624       goto out;
625     }
626
627 #if 0
628   g_debug ("read %d bytes (is_closed=%d blocking=%d condition=0x%02x) stream %p, %p",
629            (gint) bytes_read,
630            g_socket_is_closed (g_socket_connection_get_socket (G_SOCKET_CONNECTION (worker->stream))),
631            g_socket_get_blocking (g_socket_connection_get_socket (G_SOCKET_CONNECTION (worker->stream))),
632            g_socket_condition_check (g_socket_connection_get_socket (G_SOCKET_CONNECTION (worker->stream)),
633                                      G_IO_IN | G_IO_OUT | G_IO_HUP),
634            worker->stream,
635            worker);
636 #endif
637
638   /* TODO: hmm, hmm... */
639   if (bytes_read == 0)
640     {
641       g_set_error (&error,
642                    G_IO_ERROR,
643                    G_IO_ERROR_FAILED,
644                    "Underlying GIOStream returned 0 bytes on an async read");
645       _g_dbus_worker_emit_disconnected (worker, TRUE, error);
646       g_error_free (error);
647       goto out;
648     }
649
650   worker->read_buffer_cur_size += bytes_read;
651   if (worker->read_buffer_bytes_wanted == worker->read_buffer_cur_size)
652     {
653       /* OK, got what we asked for! */
654       if (worker->read_buffer_bytes_wanted == 16)
655         {
656           gssize message_len;
657           /* OK, got the header - determine how many more bytes are needed */
658           error = NULL;
659           message_len = g_dbus_message_bytes_needed ((guchar *) worker->read_buffer,
660                                                      16,
661                                                      &error);
662           if (message_len == -1)
663             {
664               g_warning ("_g_dbus_worker_do_read_cb: error determing bytes needed: %s", error->message);
665               _g_dbus_worker_emit_disconnected (worker, FALSE, error);
666               g_error_free (error);
667               goto out;
668             }
669
670           worker->read_buffer_bytes_wanted = message_len;
671           _g_dbus_worker_do_read_unlocked (worker);
672         }
673       else
674         {
675           GDBusMessage *message;
676           error = NULL;
677
678           /* TODO: use connection->priv->auth to decode the message */
679
680           message = g_dbus_message_new_from_blob ((guchar *) worker->read_buffer,
681                                                   worker->read_buffer_cur_size,
682                                                   worker->capabilities,
683                                                   &error);
684           if (message == NULL)
685             {
686               gchar *s;
687               s = _g_dbus_hexdump (worker->read_buffer, worker->read_buffer_cur_size, 2);
688               g_warning ("Error decoding D-Bus message of %" G_GSIZE_FORMAT " bytes\n"
689                          "The error is: %s\n"
690                          "The payload is as follows:\n"
691                          "%s\n",
692                          worker->read_buffer_cur_size,
693                          error->message,
694                          s);
695               g_free (s);
696               _g_dbus_worker_emit_disconnected (worker, FALSE, error);
697               g_error_free (error);
698               goto out;
699             }
700
701 #ifdef G_OS_UNIX
702           if (worker->read_fd_list != NULL)
703             {
704               g_dbus_message_set_unix_fd_list (message, worker->read_fd_list);
705               worker->read_fd_list = NULL;
706             }
707 #endif
708
709           if (G_UNLIKELY (_g_dbus_debug_message ()))
710             {
711               gchar *s;
712               _g_dbus_debug_print_lock ();
713               g_print ("========================================================================\n"
714                        "GDBus-debug:Message:\n"
715                        "  <<<< RECEIVED D-Bus message (%" G_GSIZE_FORMAT " bytes)\n",
716                        worker->read_buffer_cur_size);
717               s = g_dbus_message_print (message, 2);
718               g_print ("%s", s);
719               g_free (s);
720               if (G_UNLIKELY (_g_dbus_debug_payload ()))
721                 {
722                   s = _g_dbus_hexdump (worker->read_buffer, worker->read_buffer_cur_size, 2);
723                   g_print ("%s\n", s);
724                   g_free (s);
725                 }
726               _g_dbus_debug_print_unlock ();
727             }
728
729           /* yay, got a message, go deliver it */
730           _g_dbus_worker_queue_or_deliver_received_message (worker, message);
731
732           /* start reading another message! */
733           worker->read_buffer_bytes_wanted = 0;
734           worker->read_buffer_cur_size = 0;
735           _g_dbus_worker_do_read_unlocked (worker);
736         }
737     }
738   else
739     {
740       /* didn't get all the bytes we requested - so repeat the request... */
741       _g_dbus_worker_do_read_unlocked (worker);
742     }
743
744  out:
745   g_mutex_unlock (worker->read_lock);
746
747   /* gives up the reference acquired when calling g_input_stream_read_async() */
748   _g_dbus_worker_unref (worker);
749 }
750
751 /* called in private thread shared by all GDBusConnection instances (with read-lock held) */
752 static void
753 _g_dbus_worker_do_read_unlocked (GDBusWorker *worker)
754 {
755   /* if bytes_wanted is zero, it means start reading a message */
756   if (worker->read_buffer_bytes_wanted == 0)
757     {
758       worker->read_buffer_cur_size = 0;
759       worker->read_buffer_bytes_wanted = 16;
760     }
761
762   /* ensure we have a (big enough) buffer */
763   if (worker->read_buffer == NULL || worker->read_buffer_bytes_wanted > worker->read_buffer_allocated_size)
764     {
765       /* TODO: 4096 is randomly chosen; might want a better chosen default minimum */
766       worker->read_buffer_allocated_size = MAX (worker->read_buffer_bytes_wanted, 4096);
767       worker->read_buffer = g_realloc (worker->read_buffer, worker->read_buffer_allocated_size);
768     }
769
770   if (worker->socket == NULL)
771     g_input_stream_read_async (g_io_stream_get_input_stream (worker->stream),
772                                worker->read_buffer + worker->read_buffer_cur_size,
773                                worker->read_buffer_bytes_wanted - worker->read_buffer_cur_size,
774                                G_PRIORITY_DEFAULT,
775                                worker->cancellable,
776                                (GAsyncReadyCallback) _g_dbus_worker_do_read_cb,
777                                _g_dbus_worker_ref (worker));
778   else
779     {
780       worker->read_ancillary_messages = NULL;
781       worker->read_num_ancillary_messages = 0;
782       _g_socket_read_with_control_messages (worker->socket,
783                                             worker->read_buffer + worker->read_buffer_cur_size,
784                                             worker->read_buffer_bytes_wanted - worker->read_buffer_cur_size,
785                                             &worker->read_ancillary_messages,
786                                             &worker->read_num_ancillary_messages,
787                                             G_PRIORITY_DEFAULT,
788                                             worker->cancellable,
789                                             (GAsyncReadyCallback) _g_dbus_worker_do_read_cb,
790                                             _g_dbus_worker_ref (worker));
791     }
792 }
793
794 /* called in private thread shared by all GDBusConnection instances (without read-lock held) */
795 static void
796 _g_dbus_worker_do_read (GDBusWorker *worker)
797 {
798   g_mutex_lock (worker->read_lock);
799   _g_dbus_worker_do_read_unlocked (worker);
800   g_mutex_unlock (worker->read_lock);
801 }
802
803 /* ---------------------------------------------------------------------------------------------------- */
804
805 struct _MessageToWriteData
806 {
807   GDBusMessage *message;
808   gchar        *blob;
809   gsize         blob_size;
810 };
811
812 static void
813 message_to_write_data_free (MessageToWriteData *data)
814 {
815   g_object_unref (data->message);
816   g_free (data->blob);
817   g_free (data);
818 }
819
820 /* ---------------------------------------------------------------------------------------------------- */
821
822 /* called in private thread shared by all GDBusConnection instances (without write-lock held) */
823 static gboolean
824 write_message (GDBusWorker         *worker,
825                MessageToWriteData  *data,
826                GError             **error)
827 {
828   gboolean ret;
829   GList *l;
830   GList *ll;
831
832   g_return_val_if_fail (data->blob_size > 16, FALSE);
833
834   ret = FALSE;
835
836   /* First, the initial 16 bytes - special case UNIX sockets here
837    * since it may involve writing an ancillary message with file
838    * descriptors
839    */
840 #ifdef G_OS_UNIX
841   {
842     GOutputVector vector;
843     GSocketControlMessage *message;
844     GUnixFDList *fd_list;
845     gssize bytes_written;
846
847     fd_list = g_dbus_message_get_unix_fd_list (data->message);
848
849     message = NULL;
850     if (fd_list != NULL)
851       {
852         if (!G_IS_UNIX_CONNECTION (worker->stream))
853           {
854             g_set_error (error,
855                          G_IO_ERROR,
856                          G_IO_ERROR_INVALID_ARGUMENT,
857                          "Tried sending a file descriptor on unsupported stream of type %s",
858                          g_type_name (G_TYPE_FROM_INSTANCE (worker->stream)));
859             goto out;
860           }
861         else if (!(worker->capabilities & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING))
862           {
863             g_set_error_literal (error,
864                                  G_IO_ERROR,
865                                  G_IO_ERROR_INVALID_ARGUMENT,
866                                  "Tried sending a file descriptor but remote peer does not support this capability");
867             goto out;
868           }
869         message = g_unix_fd_message_new_with_fd_list (fd_list);
870       }
871
872     vector.buffer = data->blob;
873     vector.size = 16;
874
875     bytes_written = g_socket_send_message (worker->socket,
876                                            NULL, /* address */
877                                            &vector,
878                                            1,
879                                            message != NULL ? &message : NULL,
880                                            message != NULL ? 1 : 0,
881                                            G_SOCKET_MSG_NONE,
882                                            worker->cancellable,
883                                            error);
884     if (bytes_written == -1)
885       {
886         g_prefix_error (error, _("Error writing first 16 bytes of message to socket: "));
887         if (message != NULL)
888           g_object_unref (message);
889         goto out;
890       }
891     if (message != NULL)
892       g_object_unref (message);
893
894     if (bytes_written < 16)
895       {
896         /* TODO: I think this needs to be handled ... are we guaranteed that the ancillary
897          * messages are sent?
898          */
899         g_assert_not_reached ();
900       }
901   }
902 #else
903   /* write the first 16 bytes (guaranteed to return an error if everything can't be written) */
904   if (!g_output_stream_write_all (g_io_stream_get_output_stream (worker->stream),
905                                   (const gchar *) data->blob,
906                                   16,
907                                   NULL, /* bytes_written */
908                                   worker->cancellable, /* cancellable */
909                                   error))
910     goto out;
911 #endif
912
913   /* Then write the rest of the message (guaranteed to return an error if everything can't be written) */
914   if (!g_output_stream_write_all (g_io_stream_get_output_stream (worker->stream),
915                                   (const gchar *) data->blob + 16,
916                                   data->blob_size - 16,
917                                   NULL, /* bytes_written */
918                                   worker->cancellable, /* cancellable */
919                                   error))
920     goto out;
921
922   ret = TRUE;
923
924   /* wake up pending flushes */
925   g_mutex_lock (worker->write_lock);
926   worker->write_num_messages_written += 1;
927   for (l = worker->write_pending_flushes; l != NULL; l = ll)
928     {
929       FlushData *f = l->data;
930       ll = l->next;
931
932       if (f->number_to_wait_for == worker->write_num_messages_written)
933         {
934           g_mutex_lock (f->mutex);
935           g_cond_signal (f->cond);
936           g_mutex_unlock (f->mutex);
937           worker->write_pending_flushes = g_list_delete_link (worker->write_pending_flushes, l);
938         }
939     }
940   g_mutex_unlock (worker->write_lock);
941
942   if (G_UNLIKELY (_g_dbus_debug_message ()))
943     {
944       gchar *s;
945       _g_dbus_debug_print_lock ();
946       g_print ("========================================================================\n"
947                "GDBus-debug:Message:\n"
948                "  >>>> SENT D-Bus message (%" G_GSIZE_FORMAT " bytes)\n",
949                data->blob_size);
950       s = g_dbus_message_print (data->message, 2);
951       g_print ("%s", s);
952       g_free (s);
953       if (G_UNLIKELY (_g_dbus_debug_payload ()))
954         {
955           s = _g_dbus_hexdump (data->blob, data->blob_size, 2);
956           g_print ("%s\n", s);
957           g_free (s);
958         }
959       _g_dbus_debug_print_unlock ();
960     }
961
962  out:
963   return ret;
964 }
965
966 /* ---------------------------------------------------------------------------------------------------- */
967
968 /* called in private thread shared by all GDBusConnection instances (without write-lock held) */
969 static gboolean
970 write_message_in_idle_cb (gpointer user_data)
971 {
972   GDBusWorker *worker = user_data;
973   gboolean more_writes_are_pending;
974   MessageToWriteData *data;
975   gboolean message_was_dropped;
976   GError *error;
977
978   g_mutex_lock (worker->write_lock);
979   data = g_queue_pop_head (worker->write_queue);
980   g_assert (data != NULL);
981   more_writes_are_pending = (g_queue_get_length (worker->write_queue) > 0);
982   worker->write_is_pending = more_writes_are_pending;
983   g_mutex_unlock (worker->write_lock);
984
985   /* Note that write_lock is only used for protecting the @write_queue
986    * and @write_is_pending fields of the GDBusWorker struct ... which we
987    * need to modify from arbitrary threads in _g_dbus_worker_send_message().
988    *
989    * Therefore, it's fine to drop it here when calling back into user
990    * code and then writing the message out onto the GIOStream since this
991    * function only runs on the worker thread.
992    */
993   message_was_dropped = _g_dbus_worker_emit_message_about_to_be_sent (worker, data->message);
994   if (G_LIKELY (!message_was_dropped))
995     {
996       error = NULL;
997       if (!write_message (worker,
998                           data,
999                           &error))
1000         {
1001           /* TODO: handle */
1002           _g_dbus_worker_emit_disconnected (worker, TRUE, error);
1003           g_error_free (error);
1004         }
1005     }
1006   message_to_write_data_free (data);
1007
1008   return more_writes_are_pending;
1009 }
1010
1011 /* ---------------------------------------------------------------------------------------------------- */
1012
1013 /* can be called from any thread - steals blob */
1014 void
1015 _g_dbus_worker_send_message (GDBusWorker    *worker,
1016                              GDBusMessage   *message,
1017                              gchar          *blob,
1018                              gsize           blob_len)
1019 {
1020   MessageToWriteData *data;
1021
1022   g_return_if_fail (G_IS_DBUS_MESSAGE (message));
1023   g_return_if_fail (blob != NULL);
1024   g_return_if_fail (blob_len > 16);
1025
1026   data = g_new0 (MessageToWriteData, 1);
1027   data->message = g_object_ref (message);
1028   data->blob = blob; /* steal! */
1029   data->blob_size = blob_len;
1030
1031   g_mutex_lock (worker->write_lock);
1032   g_queue_push_tail (worker->write_queue, data);
1033   if (!worker->write_is_pending)
1034     {
1035       GSource *idle_source;
1036
1037       worker->write_is_pending = TRUE;
1038
1039       idle_source = g_idle_source_new ();
1040       g_source_set_priority (idle_source, G_PRIORITY_DEFAULT);
1041       g_source_set_callback (idle_source,
1042                              write_message_in_idle_cb,
1043                              _g_dbus_worker_ref (worker),
1044                              (GDestroyNotify) _g_dbus_worker_unref);
1045       g_source_attach (idle_source, shared_thread_data->context);
1046       g_source_unref (idle_source);
1047     }
1048   g_mutex_unlock (worker->write_lock);
1049 }
1050
1051 /* ---------------------------------------------------------------------------------------------------- */
1052
1053 static void
1054 _g_dbus_worker_thread_begin_func (gpointer user_data)
1055 {
1056   GDBusWorker *worker = user_data;
1057
1058   worker->thread = g_thread_self ();
1059
1060   /* begin reading */
1061   _g_dbus_worker_do_read (worker);
1062 }
1063
1064 GDBusWorker *
1065 _g_dbus_worker_new (GIOStream                              *stream,
1066                     GDBusCapabilityFlags                    capabilities,
1067                     gboolean                                initially_frozen,
1068                     GDBusWorkerMessageReceivedCallback      message_received_callback,
1069                     GDBusWorkerMessageAboutToBeSentCallback message_about_to_be_sent_callback,
1070                     GDBusWorkerDisconnectedCallback         disconnected_callback,
1071                     gpointer                                user_data)
1072 {
1073   GDBusWorker *worker;
1074
1075   g_return_val_if_fail (G_IS_IO_STREAM (stream), NULL);
1076   g_return_val_if_fail (message_received_callback != NULL, NULL);
1077   g_return_val_if_fail (message_about_to_be_sent_callback != NULL, NULL);
1078   g_return_val_if_fail (disconnected_callback != NULL, NULL);
1079
1080   worker = g_new0 (GDBusWorker, 1);
1081   worker->ref_count = 1;
1082
1083   worker->read_lock = g_mutex_new ();
1084   worker->message_received_callback = message_received_callback;
1085   worker->message_about_to_be_sent_callback = message_about_to_be_sent_callback;
1086   worker->disconnected_callback = disconnected_callback;
1087   worker->user_data = user_data;
1088   worker->stream = g_object_ref (stream);
1089   worker->capabilities = capabilities;
1090   worker->cancellable = g_cancellable_new ();
1091
1092   worker->frozen = initially_frozen;
1093   worker->received_messages_while_frozen = g_queue_new ();
1094
1095   worker->write_lock = g_mutex_new ();
1096   worker->write_queue = g_queue_new ();
1097
1098   if (G_IS_SOCKET_CONNECTION (worker->stream))
1099     worker->socket = g_socket_connection_get_socket (G_SOCKET_CONNECTION (worker->stream));
1100
1101   _g_dbus_shared_thread_ref (_g_dbus_worker_thread_begin_func, worker);
1102
1103   return worker;
1104 }
1105
1106 /* ---------------------------------------------------------------------------------------------------- */
1107
1108 /* This can be called from any thread - frees worker - guarantees no callbacks
1109  * will ever be issued again
1110  */
1111 void
1112 _g_dbus_worker_stop (GDBusWorker *worker)
1113 {
1114   /* If we're called in the worker thread it means we are called from
1115    * a worker callback. This is fine, we just can't lock in that case since
1116    * we're already holding the lock...
1117    */
1118   if (g_thread_self () != worker->thread)
1119     g_mutex_lock (worker->read_lock);
1120   worker->stopped = TRUE;
1121   if (g_thread_self () != worker->thread)
1122     g_mutex_unlock (worker->read_lock);
1123
1124   g_cancellable_cancel (worker->cancellable);
1125   _g_dbus_worker_unref (worker);
1126 }
1127
1128 /* ---------------------------------------------------------------------------------------------------- */
1129
1130 /* can be called from any thread (except the worker thread) - blocks
1131  * calling thread until all queued outgoing messages are written and
1132  * the transport has been flushed
1133  */
1134 gboolean
1135 _g_dbus_worker_flush_sync (GDBusWorker    *worker,
1136                            GCancellable   *cancellable,
1137                            GError        **error)
1138 {
1139   gboolean ret;
1140   FlushData *data;
1141
1142   data = NULL;
1143
1144   /* if the queue is empty, there's nothing to wait for */
1145   g_mutex_lock (worker->write_lock);
1146   if (g_queue_get_length (worker->write_queue) > 0)
1147     {
1148       data = g_new0 (FlushData, 1);
1149       data->mutex = g_mutex_new ();
1150       data->cond = g_cond_new ();
1151       data->number_to_wait_for = worker->write_num_messages_written + g_queue_get_length (worker->write_queue);
1152       g_mutex_lock (data->mutex);
1153       worker->write_pending_flushes = g_list_prepend (worker->write_pending_flushes, data);
1154     }
1155   g_mutex_unlock (worker->write_lock);
1156
1157   if (data != NULL)
1158     {
1159       g_cond_wait (data->cond, data->mutex);
1160       g_mutex_unlock (data->mutex);
1161
1162       /* note:the element is removed from worker->write_pending_flushes in write_message() */
1163       g_cond_free (data->cond);
1164       g_mutex_free (data->mutex);
1165       g_free (data);
1166     }
1167
1168   ret = g_output_stream_flush (g_io_stream_get_output_stream (worker->stream),
1169                                cancellable,
1170                                error);
1171   return ret;
1172 }
1173
1174 /* ---------------------------------------------------------------------------------------------------- */
1175
1176 #define G_DBUS_DEBUG_AUTHENTICATION (1<<0)
1177 #define G_DBUS_DEBUG_MESSAGE        (1<<1)
1178 #define G_DBUS_DEBUG_PAYLOAD        (1<<2)
1179 #define G_DBUS_DEBUG_CALL           (1<<3)
1180 #define G_DBUS_DEBUG_SIGNAL         (1<<4)
1181 #define G_DBUS_DEBUG_INCOMING       (1<<5)
1182 #define G_DBUS_DEBUG_EMISSION       (1<<6)
1183 #define G_DBUS_DEBUG_ADDRESS        (1<<7)
1184 #define G_DBUS_DEBUG_ALL            0xffffffff
1185 static gint _gdbus_debug_flags = 0;
1186
1187 gboolean
1188 _g_dbus_debug_authentication (void)
1189 {
1190   _g_dbus_initialize ();
1191   return (_gdbus_debug_flags & G_DBUS_DEBUG_AUTHENTICATION) != 0;
1192 }
1193
1194 gboolean
1195 _g_dbus_debug_message (void)
1196 {
1197   _g_dbus_initialize ();
1198   return (_gdbus_debug_flags & G_DBUS_DEBUG_MESSAGE) != 0;
1199 }
1200
1201 gboolean
1202 _g_dbus_debug_payload (void)
1203 {
1204   _g_dbus_initialize ();
1205   return (_gdbus_debug_flags & G_DBUS_DEBUG_PAYLOAD) != 0;
1206 }
1207
1208 gboolean
1209 _g_dbus_debug_call (void)
1210 {
1211   _g_dbus_initialize ();
1212   return (_gdbus_debug_flags & G_DBUS_DEBUG_CALL) != 0;
1213 }
1214
1215 gboolean
1216 _g_dbus_debug_signal (void)
1217 {
1218   _g_dbus_initialize ();
1219   return (_gdbus_debug_flags & G_DBUS_DEBUG_SIGNAL) != 0;
1220 }
1221
1222 gboolean
1223 _g_dbus_debug_incoming (void)
1224 {
1225   _g_dbus_initialize ();
1226   return (_gdbus_debug_flags & G_DBUS_DEBUG_INCOMING) != 0;
1227 }
1228
1229 gboolean
1230 _g_dbus_debug_emission (void)
1231 {
1232   _g_dbus_initialize ();
1233   return (_gdbus_debug_flags & G_DBUS_DEBUG_EMISSION) != 0;
1234 }
1235
1236 gboolean
1237 _g_dbus_debug_address (void)
1238 {
1239   _g_dbus_initialize ();
1240   return (_gdbus_debug_flags & G_DBUS_DEBUG_ADDRESS) != 0;
1241 }
1242
1243 G_LOCK_DEFINE_STATIC (print_lock);
1244
1245 void
1246 _g_dbus_debug_print_lock (void)
1247 {
1248   G_LOCK (print_lock);
1249 }
1250
1251 void
1252 _g_dbus_debug_print_unlock (void)
1253 {
1254   G_UNLOCK (print_lock);
1255 }
1256
1257 /*
1258  * _g_dbus_initialize:
1259  *
1260  * Does various one-time init things such as
1261  *
1262  *  - registering the G_DBUS_ERROR error domain
1263  *  - parses the G_DBUS_DEBUG environment variable
1264  */
1265 void
1266 _g_dbus_initialize (void)
1267 {
1268   static volatile gsize initialized = 0;
1269
1270   if (g_once_init_enter (&initialized))
1271     {
1272       volatile GQuark g_dbus_error_domain;
1273       const gchar *debug;
1274
1275       g_dbus_error_domain = G_DBUS_ERROR;
1276
1277       debug = g_getenv ("G_DBUS_DEBUG");
1278       if (debug != NULL)
1279         {
1280           gchar **tokens;
1281           guint n;
1282           tokens = g_strsplit (debug, ",", 0);
1283           for (n = 0; tokens[n] != NULL; n++)
1284             {
1285               if (g_strcmp0 (tokens[n], "authentication") == 0)
1286                 _gdbus_debug_flags |= G_DBUS_DEBUG_AUTHENTICATION;
1287               else if (g_strcmp0 (tokens[n], "message") == 0)
1288                 _gdbus_debug_flags |= G_DBUS_DEBUG_MESSAGE;
1289               else if (g_strcmp0 (tokens[n], "payload") == 0) /* implies `message' */
1290                 _gdbus_debug_flags |= (G_DBUS_DEBUG_MESSAGE | G_DBUS_DEBUG_PAYLOAD);
1291               else if (g_strcmp0 (tokens[n], "call") == 0)
1292                 _gdbus_debug_flags |= G_DBUS_DEBUG_CALL;
1293               else if (g_strcmp0 (tokens[n], "signal") == 0)
1294                 _gdbus_debug_flags |= G_DBUS_DEBUG_SIGNAL;
1295               else if (g_strcmp0 (tokens[n], "incoming") == 0)
1296                 _gdbus_debug_flags |= G_DBUS_DEBUG_INCOMING;
1297               else if (g_strcmp0 (tokens[n], "emission") == 0)
1298                 _gdbus_debug_flags |= G_DBUS_DEBUG_EMISSION;
1299               else if (g_strcmp0 (tokens[n], "address") == 0)
1300                 _gdbus_debug_flags |= G_DBUS_DEBUG_ADDRESS;
1301               else if (g_strcmp0 (tokens[n], "all") == 0)
1302                 _gdbus_debug_flags |= G_DBUS_DEBUG_ALL;
1303             }
1304           g_strfreev (tokens);
1305         }
1306
1307       g_once_init_leave (&initialized, 1);
1308     }
1309 }
1310
1311 /* ---------------------------------------------------------------------------------------------------- */
1312
1313 GVariantType *
1314 _g_dbus_compute_complete_signature (GDBusArgInfo **args)
1315 {
1316   const GVariantType *arg_types[256];
1317   guint n;
1318
1319   if (args)
1320     for (n = 0; args[n] != NULL; n++)
1321       {
1322         /* DBus places a hard limit of 255 on signature length.
1323          * therefore number of args must be less than 256.
1324          */
1325         g_assert (n < 256);
1326
1327         arg_types[n] = G_VARIANT_TYPE (args[n]->signature);
1328
1329         if G_UNLIKELY (arg_types[n] == NULL)
1330           return NULL;
1331       }
1332   else
1333     n = 0;
1334
1335   return g_variant_type_new_tuple (arg_types, n);
1336 }
1337
1338 /* ---------------------------------------------------------------------------------------------------- */
1339
1340 #ifdef G_OS_WIN32
1341
1342 extern BOOL WINAPI ConvertSidToStringSidA (PSID Sid, LPSTR *StringSid);
1343
1344 gchar *
1345 _g_dbus_win32_get_user_sid (void)
1346 {
1347   HANDLE h;
1348   TOKEN_USER *user;
1349   DWORD token_information_len;
1350   PSID psid;
1351   gchar *sid;
1352   gchar *ret;
1353
1354   ret = NULL;
1355   user = NULL;
1356   h = INVALID_HANDLE_VALUE;
1357
1358   if (!OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &h))
1359     {
1360       g_warning ("OpenProcessToken failed with error code %d", (gint) GetLastError ());
1361       goto out;
1362     }
1363
1364   /* Get length of buffer */
1365   token_information_len = 0;
1366   if (!GetTokenInformation (h, TokenUser, NULL, 0, &token_information_len))
1367     {
1368       if (GetLastError () != ERROR_INSUFFICIENT_BUFFER)
1369         {
1370           g_warning ("GetTokenInformation() failed with error code %d", (gint) GetLastError ());
1371           goto out;
1372         }
1373     }
1374   user = g_malloc (token_information_len);
1375   if (!GetTokenInformation (h, TokenUser, user, token_information_len, &token_information_len))
1376     {
1377       g_warning ("GetTokenInformation() failed with error code %d", (gint) GetLastError ());
1378       goto out;
1379     }
1380
1381   psid = user->User.Sid;
1382   if (!IsValidSid (psid))
1383     {
1384       g_warning ("Invalid SID");
1385       goto out;
1386     }
1387
1388   if (!ConvertSidToStringSidA (psid, &sid))
1389     {
1390       g_warning ("Invalid SID");
1391       goto out;
1392     }
1393
1394   ret = g_strdup (sid);
1395   LocalFree (sid);
1396
1397 out:
1398   g_free (user);
1399   if (h != INVALID_HANDLE_VALUE)
1400     CloseHandle (h);
1401   return ret;
1402 }
1403 #endif
1404
1405 /* ---------------------------------------------------------------------------------------------------- */
1406
1407 gchar *
1408 _g_dbus_get_machine_id (GError **error)
1409 {
1410   gchar *ret;
1411   /* TODO: use PACKAGE_LOCALSTATEDIR ? */
1412   ret = NULL;
1413   if (!g_file_get_contents ("/var/lib/dbus/machine-id",
1414                             &ret,
1415                             NULL,
1416                             error))
1417     {
1418       g_prefix_error (error, _("Unable to load /var/lib/dbus/machine-id: "));
1419     }
1420   else
1421     {
1422       /* TODO: validate value */
1423       g_strstrip (ret);
1424     }
1425   return ret;
1426 }
1427
1428 /* ---------------------------------------------------------------------------------------------------- */
1429
1430 gchar *
1431 _g_dbus_enum_to_string (GType enum_type, gint value)
1432 {
1433   gchar *ret;
1434   GEnumClass *klass;
1435   GEnumValue *enum_value;
1436
1437   klass = g_type_class_ref (enum_type);
1438   enum_value = g_enum_get_value (klass, value);
1439   if (enum_value != NULL)
1440     ret = g_strdup (enum_value->value_nick);
1441   else
1442     ret = g_strdup_printf ("unknown (value %d)", value);
1443   g_type_class_unref (klass);
1444   return ret;
1445 }
1446
1447 /* ---------------------------------------------------------------------------------------------------- */
1448
1449 #define __G_DBUS_PRIVATE_C__
1450 #include "gioaliasdef.c"