LCOV - code coverage report
Current view: top level - gio - gdbusprivate.c (source / functions) Coverage Total Hit
Test: unnamed Lines: 79.1 % 795 629
Test Date: 2024-11-26 05:23:01 Functions: 89.6 % 67 60
Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : /* GDBus - GLib D-Bus Library
       2                 :             :  *
       3                 :             :  * Copyright (C) 2008-2010 Red Hat, Inc.
       4                 :             :  *
       5                 :             :  * SPDX-License-Identifier: LGPL-2.1-or-later
       6                 :             :  *
       7                 :             :  * This library is free software; you can redistribute it and/or
       8                 :             :  * modify it under the terms of the GNU Lesser General Public
       9                 :             :  * License as published by the Free Software Foundation; either
      10                 :             :  * version 2.1 of the License, or (at your option) any later version.
      11                 :             :  *
      12                 :             :  * This library is distributed in the hope that it will be useful,
      13                 :             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14                 :             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15                 :             :  * Lesser General Public License for more details.
      16                 :             :  *
      17                 :             :  * You should have received a copy of the GNU Lesser General
      18                 :             :  * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
      19                 :             :  *
      20                 :             :  * Author: David Zeuthen <davidz@redhat.com>
      21                 :             :  */
      22                 :             : 
      23                 :             : #include "config.h"
      24                 :             : 
      25                 :             : #include <stdlib.h>
      26                 :             : #include <string.h>
      27                 :             : 
      28                 :             : #include "gdbusauthobserver.h"
      29                 :             : #include "gdbusconnection.h"
      30                 :             : #include "gdbusdaemon.h"
      31                 :             : #include "gdbuserror.h"
      32                 :             : #include "gdbusintrospection.h"
      33                 :             : #include "gdbusmessage.h"
      34                 :             : #include "gdbusprivate.h"
      35                 :             : #include "gdbusproxy.h"
      36                 :             : #include "ginputstream.h"
      37                 :             : #include "gioenumtypes.h"
      38                 :             : #include "giomodule-priv.h"
      39                 :             : #include "giostream.h"
      40                 :             : #include "giotypes.h"
      41                 :             : #include "glib-private.h"
      42                 :             : #include "glib/gstdio.h"
      43                 :             : #include "gmemoryinputstream.h"
      44                 :             : #include "gsocket.h"
      45                 :             : #include "gsocketaddress.h"
      46                 :             : #include "gsocketconnection.h"
      47                 :             : #include "gsocketcontrolmessage.h"
      48                 :             : #include "gsocketoutputstream.h"
      49                 :             : #include "gtask.h"
      50                 :             : 
      51                 :             : #ifdef G_OS_UNIX
      52                 :             : #include "gunixfdmessage.h"
      53                 :             : #include "gunixconnection.h"
      54                 :             : #include "gunixcredentialsmessage.h"
      55                 :             : #endif
      56                 :             : 
      57                 :             : #ifdef G_OS_WIN32
      58                 :             : #include <windows.h>
      59                 :             : #include <io.h>
      60                 :             : #include <conio.h>
      61                 :             : #include "gwin32sid.h"
      62                 :             : #endif
      63                 :             : 
      64                 :             : #include "glibintl.h"
      65                 :             : 
      66                 :             : static gboolean _g_dbus_worker_do_initial_read (gpointer data);
      67                 :             : static void schedule_pending_close (GDBusWorker *worker);
      68                 :             : 
      69                 :             : /* ---------------------------------------------------------------------------------------------------- */
      70                 :             : 
      71                 :             : gchar *
      72                 :           0 : _g_dbus_hexdump (const gchar *data, gsize len, guint indent)
      73                 :             : {
      74                 :             :  guint n, m;
      75                 :             :  GString *ret;
      76                 :             : 
      77                 :           0 :  ret = g_string_new (NULL);
      78                 :             : 
      79                 :           0 :  for (n = 0; n < len; n += 16)
      80                 :             :    {
      81                 :           0 :      g_string_append_printf (ret, "%*s%04x: ", indent, "", n);
      82                 :             : 
      83                 :           0 :      for (m = n; m < n + 16; m++)
      84                 :             :        {
      85                 :           0 :          if (m > n && (m%4) == 0)
      86                 :             :            g_string_append_c (ret, ' ');
      87                 :           0 :          if (m < len)
      88                 :           0 :            g_string_append_printf (ret, "%02x ", (guchar) data[m]);
      89                 :             :          else
      90                 :           0 :            g_string_append (ret, "   ");
      91                 :             :        }
      92                 :             : 
      93                 :           0 :      g_string_append (ret, "   ");
      94                 :             : 
      95                 :           0 :      for (m = n; m < len && m < n + 16; m++)
      96                 :           0 :        g_string_append_c (ret, g_ascii_isprint (data[m]) ? data[m] : '.');
      97                 :             : 
      98                 :             :      g_string_append_c (ret, '\n');
      99                 :             :    }
     100                 :             : 
     101                 :           0 :  return g_string_free (ret, FALSE);
     102                 :             : }
     103                 :             : 
     104                 :             : /* ---------------------------------------------------------------------------------------------------- */
     105                 :             : 
     106                 :             : /* Unfortunately ancillary messages are discarded when reading from a
     107                 :             :  * socket using the GSocketInputStream abstraction. So we provide a
     108                 :             :  * very GInputStream-ish API that uses GSocket in this case (very
     109                 :             :  * similar to GSocketInputStream).
     110                 :             :  */
     111                 :             : 
     112                 :             : typedef struct
     113                 :             : {
     114                 :             :   void *buffer;
     115                 :             :   gsize count;
     116                 :             : 
     117                 :             :   GSocketControlMessage ***messages;
     118                 :             :   gint *num_messages;
     119                 :             : } ReadWithControlData;
     120                 :             : 
     121                 :             : static void
     122                 :       56717 : read_with_control_data_free (ReadWithControlData *data)
     123                 :             : {
     124                 :       56717 :   g_slice_free (ReadWithControlData, data);
     125                 :       56717 : }
     126                 :             : 
     127                 :             : static gboolean
     128                 :       56717 : _g_socket_read_with_control_messages_ready (GSocket      *socket,
     129                 :             :                                             GIOCondition  condition,
     130                 :             :                                             gpointer      user_data)
     131                 :             : {
     132                 :       56717 :   GTask *task = user_data;
     133                 :       56717 :   ReadWithControlData *data = g_task_get_task_data (task);
     134                 :             :   GError *error;
     135                 :             :   gssize result;
     136                 :             :   GInputVector vector;
     137                 :             : 
     138                 :       56717 :   error = NULL;
     139                 :       56717 :   vector.buffer = data->buffer;
     140                 :       56717 :   vector.size = data->count;
     141                 :       56717 :   result = g_socket_receive_message (socket,
     142                 :             :                                      NULL, /* address */
     143                 :             :                                      &vector,
     144                 :             :                                      1,
     145                 :             :                                      data->messages,
     146                 :             :                                      data->num_messages,
     147                 :             :                                      NULL,
     148                 :             :                                      g_task_get_cancellable (task),
     149                 :             :                                      &error);
     150                 :             : 
     151                 :       56717 :   if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
     152                 :             :     {
     153                 :           0 :       g_error_free (error);
     154                 :           0 :       return TRUE;
     155                 :             :     }
     156                 :             : 
     157                 :       56717 :   g_assert (result >= 0 || error != NULL);
     158                 :       56717 :   if (result >= 0)
     159                 :       55204 :     g_task_return_int (task, result);
     160                 :             :   else
     161                 :        1513 :     g_task_return_error (task, error);
     162                 :       56717 :   g_object_unref (task);
     163                 :             : 
     164                 :       56717 :   return FALSE;
     165                 :             : }
     166                 :             : 
     167                 :             : static void
     168                 :       56770 : _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                 :             :   GTask *task;
     179                 :             :   ReadWithControlData *data;
     180                 :             :   GSource *source;
     181                 :             : 
     182                 :       56770 :   data = g_slice_new0 (ReadWithControlData);
     183                 :       56770 :   data->buffer = buffer;
     184                 :       56770 :   data->count = count;
     185                 :       56770 :   data->messages = messages;
     186                 :       56770 :   data->num_messages = num_messages;
     187                 :             : 
     188                 :       56770 :   task = g_task_new (socket, cancellable, callback, user_data);
     189                 :       56770 :   g_task_set_source_tag (task, _g_socket_read_with_control_messages);
     190                 :       56770 :   g_task_set_name (task, "[gio] D-Bus read");
     191                 :       56770 :   g_task_set_task_data (task, data, (GDestroyNotify) read_with_control_data_free);
     192                 :             : 
     193                 :       56770 :   if (g_socket_condition_check (socket, G_IO_IN))
     194                 :             :     {
     195                 :       47733 :       if (!_g_socket_read_with_control_messages_ready (socket, G_IO_IN, task))
     196                 :       47733 :         return;
     197                 :             :     }
     198                 :             : 
     199                 :        9037 :   source = g_socket_create_source (socket,
     200                 :             :                                    G_IO_IN | G_IO_HUP | G_IO_ERR,
     201                 :             :                                    cancellable);
     202                 :        9037 :   g_task_attach_source (task, source, (GSourceFunc) _g_socket_read_with_control_messages_ready);
     203                 :        9037 :   g_source_unref (source);
     204                 :             : }
     205                 :             : 
     206                 :             : static gssize
     207                 :       55202 : _g_socket_read_with_control_messages_finish (GSocket       *socket,
     208                 :             :                                              GAsyncResult  *result,
     209                 :             :                                              GError       **error)
     210                 :             : {
     211                 :       55202 :   g_return_val_if_fail (G_IS_SOCKET (socket), -1);
     212                 :       55202 :   g_return_val_if_fail (g_task_is_valid (result, socket), -1);
     213                 :             : 
     214                 :       55202 :   return g_task_propagate_int (G_TASK (result), error);
     215                 :             : }
     216                 :             : 
     217                 :             : /* ---------------------------------------------------------------------------------------------------- */
     218                 :             : 
     219                 :             : /* Work-around for https://bugzilla.gnome.org/show_bug.cgi?id=674885
     220                 :             :    and see also the original https://bugzilla.gnome.org/show_bug.cgi?id=627724  */
     221                 :             : 
     222                 :             : static GPtrArray *ensured_classes = NULL;
     223                 :             : 
     224                 :             : static void
     225                 :        1476 : ensure_type (GType gtype)
     226                 :             : {
     227                 :        1476 :   g_ptr_array_add (ensured_classes, g_type_class_ref (gtype));
     228                 :        1476 : }
     229                 :             : 
     230                 :             : static void
     231                 :           0 : release_required_types (void)
     232                 :             : {
     233                 :           0 :   g_ptr_array_foreach (ensured_classes, (GFunc) g_type_class_unref, NULL);
     234                 :           0 :   g_ptr_array_unref (ensured_classes);
     235                 :           0 :   ensured_classes = NULL;
     236                 :           0 : }
     237                 :             : 
     238                 :             : static void
     239                 :         123 : ensure_required_types (void)
     240                 :             : {
     241                 :         123 :   g_assert (ensured_classes == NULL);
     242                 :         123 :   ensured_classes = g_ptr_array_new ();
     243                 :             :   /* Generally in this list, you should initialize types which are used as
     244                 :             :    * properties first, then the class which has them. For example, GDBusProxy
     245                 :             :    * has a type of GDBusConnection, so we initialize GDBusConnection first.
     246                 :             :    * And because GDBusConnection has a property of type GDBusConnectionFlags,
     247                 :             :    * we initialize that first.
     248                 :             :    *
     249                 :             :    * Similarly, GSocket has a type of GSocketAddress.
     250                 :             :    *
     251                 :             :    * We don't fill out the whole dependency tree right now because in practice
     252                 :             :    * it tends to be just types that GDBus use that cause pain, and there
     253                 :             :    * is work on a more general approach in https://bugzilla.gnome.org/show_bug.cgi?id=674885
     254                 :             :    */
     255                 :         123 :   ensure_type (G_TYPE_TASK);
     256                 :         123 :   ensure_type (G_TYPE_MEMORY_INPUT_STREAM);
     257                 :         123 :   ensure_type (G_TYPE_DBUS_CONNECTION_FLAGS);
     258                 :         123 :   ensure_type (G_TYPE_DBUS_CAPABILITY_FLAGS);
     259                 :         123 :   ensure_type (G_TYPE_DBUS_AUTH_OBSERVER);
     260                 :         123 :   ensure_type (G_TYPE_DBUS_CONNECTION);
     261                 :         123 :   ensure_type (G_TYPE_DBUS_PROXY);
     262                 :         123 :   ensure_type (G_TYPE_SOCKET_FAMILY);
     263                 :         123 :   ensure_type (G_TYPE_SOCKET_TYPE);
     264                 :         123 :   ensure_type (G_TYPE_SOCKET_PROTOCOL);
     265                 :         123 :   ensure_type (G_TYPE_SOCKET_ADDRESS);
     266                 :         123 :   ensure_type (G_TYPE_SOCKET);
     267                 :         123 : }
     268                 :             : /* ---------------------------------------------------------------------------------------------------- */
     269                 :             : 
     270                 :             : typedef struct
     271                 :             : {
     272                 :             :   gint refcount;  /* (atomic) */
     273                 :             :   GThread *thread;
     274                 :             :   GMainContext *context;
     275                 :             :   GMainLoop *loop;
     276                 :             : } SharedThreadData;
     277                 :             : 
     278                 :             : static gpointer
     279                 :          96 : gdbus_shared_thread_func (gpointer user_data)
     280                 :             : {
     281                 :          96 :   SharedThreadData *data = user_data;
     282                 :             : 
     283                 :          96 :   g_main_context_push_thread_default (data->context);
     284                 :          96 :   g_main_loop_run (data->loop);
     285                 :           0 :   g_main_context_pop_thread_default (data->context);
     286                 :             : 
     287                 :           0 :   release_required_types ();
     288                 :             : 
     289                 :           0 :   return NULL;
     290                 :             : }
     291                 :             : 
     292                 :             : /* ---------------------------------------------------------------------------------------------------- */
     293                 :             : 
     294                 :             : static SharedThreadData *
     295                 :        2210 : _g_dbus_shared_thread_ref (void)
     296                 :             : {
     297                 :             :   static SharedThreadData *shared_thread_data = 0;
     298                 :             : 
     299                 :        2210 :   if (g_once_init_enter_pointer (&shared_thread_data))
     300                 :             :     {
     301                 :             :       SharedThreadData *data;
     302                 :             : 
     303                 :          96 :       data = g_new0 (SharedThreadData, 1);
     304                 :          96 :       data->refcount = 0;
     305                 :             :       
     306                 :          96 :       data->context = g_main_context_new ();
     307                 :          96 :       data->loop = g_main_loop_new (data->context, FALSE);
     308                 :          96 :       data->thread = g_thread_new ("gdbus",
     309                 :             :                                    gdbus_shared_thread_func,
     310                 :             :                                    data);
     311                 :             :       /* We can cast between gsize and gpointer safely */
     312                 :          96 :       g_once_init_leave_pointer (&shared_thread_data, data);
     313                 :             :     }
     314                 :             : 
     315                 :        2210 :   g_atomic_int_inc (&shared_thread_data->refcount);
     316                 :        2210 :   return shared_thread_data;
     317                 :             : }
     318                 :             : 
     319                 :             : static void
     320                 :        1953 : _g_dbus_shared_thread_unref (SharedThreadData *data)
     321                 :             : {
     322                 :             :   /* TODO: actually destroy the shared thread here */
     323                 :             : #if 0
     324                 :             :   g_assert (data != NULL);
     325                 :             :   if (g_atomic_int_dec_and_test (&data->refcount))
     326                 :             :     {
     327                 :             :       g_main_loop_quit (data->loop);
     328                 :             :       //g_thread_join (data->thread);
     329                 :             :       g_main_loop_unref (data->loop);
     330                 :             :       g_main_context_unref (data->context);
     331                 :             :     }
     332                 :             : #endif
     333                 :        1953 : }
     334                 :             : 
     335                 :             : /* ---------------------------------------------------------------------------------------------------- */
     336                 :             : 
     337                 :             : typedef enum {
     338                 :             :     PENDING_NONE = 0,
     339                 :             :     PENDING_WRITE,
     340                 :             :     PENDING_FLUSH,
     341                 :             :     PENDING_CLOSE
     342                 :             : } OutputPending;
     343                 :             : 
     344                 :             : struct GDBusWorker
     345                 :             : {
     346                 :             :   gint                                ref_count;  /* (atomic) */
     347                 :             : 
     348                 :             :   SharedThreadData                   *shared_thread_data;
     349                 :             : 
     350                 :             :   /* really a boolean, but GLib 2.28 lacks atomic boolean ops */
     351                 :             :   gint                                stopped;  /* (atomic) */
     352                 :             : 
     353                 :             :   /* TODO: frozen (e.g. G_DBUS_CONNECTION_FLAGS_DELAY_MESSAGE_PROCESSING) currently
     354                 :             :    * only affects messages received from the other peer (since GDBusServer is the
     355                 :             :    * only user) - we might want it to affect messages sent to the other peer too?
     356                 :             :    */
     357                 :             :   gboolean                            frozen;
     358                 :             :   GDBusCapabilityFlags                capabilities;
     359                 :             :   GQueue                             *received_messages_while_frozen;
     360                 :             : 
     361                 :             :   GIOStream                          *stream;
     362                 :             :   GCancellable                       *cancellable;
     363                 :             :   GDBusWorkerMessageReceivedCallback  message_received_callback;
     364                 :             :   GDBusWorkerMessageAboutToBeSentCallback message_about_to_be_sent_callback;
     365                 :             :   GDBusWorkerDisconnectedCallback     disconnected_callback;
     366                 :             :   gpointer                            user_data;
     367                 :             : 
     368                 :             :   /* if not NULL, stream is GSocketConnection */
     369                 :             :   GSocket *socket;
     370                 :             : 
     371                 :             :   /* used for reading */
     372                 :             :   GMutex                              read_lock;
     373                 :             :   gchar                              *read_buffer;
     374                 :             :   gsize                               read_buffer_allocated_size;
     375                 :             :   gsize                               read_buffer_cur_size;
     376                 :             :   gsize                               read_buffer_bytes_wanted;
     377                 :             :   GUnixFDList                        *read_fd_list;
     378                 :             :   GSocketControlMessage             **read_ancillary_messages;
     379                 :             :   gint                                read_num_ancillary_messages;
     380                 :             : 
     381                 :             :   /* Whether an async write, flush or close, or none of those, is pending.
     382                 :             :    * Only the worker thread may change its value, and only with the write_lock.
     383                 :             :    * Other threads may read its value when holding the write_lock.
     384                 :             :    * The worker thread may read its value at any time.
     385                 :             :    */
     386                 :             :   OutputPending                       output_pending;
     387                 :             :   /* used for writing */
     388                 :             :   GMutex                              write_lock;
     389                 :             :   /* queue of MessageToWriteData, protected by write_lock */
     390                 :             :   GQueue                             *write_queue;
     391                 :             :   /* protected by write_lock */
     392                 :             :   guint64                             write_num_messages_written;
     393                 :             :   /* number of messages we'd written out last time we flushed;
     394                 :             :    * protected by write_lock
     395                 :             :    */
     396                 :             :   guint64                             write_num_messages_flushed;
     397                 :             :   /* list of FlushData, protected by write_lock */
     398                 :             :   GList                              *write_pending_flushes;
     399                 :             :   /* list of CloseData, protected by write_lock */
     400                 :             :   GList                              *pending_close_attempts;
     401                 :             :   /* no lock - only used from the worker thread */
     402                 :             :   gboolean                            close_expected;
     403                 :             : };
     404                 :             : 
     405                 :             : static void _g_dbus_worker_unref (GDBusWorker *worker);
     406                 :             : 
     407                 :             : /* ---------------------------------------------------------------------------------------------------- */
     408                 :             : 
     409                 :             : typedef struct
     410                 :             : {
     411                 :             :   GMutex  mutex;
     412                 :             :   GCond   cond;
     413                 :             :   guint64 number_to_wait_for;
     414                 :             :   gboolean finished;
     415                 :             :   GError *error;
     416                 :             : } FlushData;
     417                 :             : 
     418                 :             : struct _MessageToWriteData ;
     419                 :             : typedef struct _MessageToWriteData MessageToWriteData;
     420                 :             : 
     421                 :             : static void message_to_write_data_free (MessageToWriteData *data);
     422                 :             : 
     423                 :             : static void read_message_print_transport_debug (gssize bytes_read,
     424                 :             :                                                 GDBusWorker *worker);
     425                 :             : 
     426                 :             : static void write_message_print_transport_debug (gssize bytes_written,
     427                 :             :                                                  MessageToWriteData *data);
     428                 :             : 
     429                 :             : typedef struct {
     430                 :             :     GDBusWorker *worker;
     431                 :             :     GTask *task;
     432                 :             : } CloseData;
     433                 :             : 
     434                 :        2059 : static void close_data_free (CloseData *close_data)
     435                 :             : {
     436                 :        2059 :   g_clear_object (&close_data->task);
     437                 :             : 
     438                 :        2059 :   _g_dbus_worker_unref (close_data->worker);
     439                 :        2059 :   g_slice_free (CloseData, close_data);
     440                 :        2059 : }
     441                 :             : 
     442                 :             : /* ---------------------------------------------------------------------------------------------------- */
     443                 :             : 
     444                 :             : static GDBusWorker *
     445                 :       89038 : _g_dbus_worker_ref (GDBusWorker *worker)
     446                 :             : {
     447                 :       89038 :   g_atomic_int_inc (&worker->ref_count);
     448                 :       89038 :   return worker;
     449                 :             : }
     450                 :             : 
     451                 :             : static void
     452                 :       90936 : _g_dbus_worker_unref (GDBusWorker *worker)
     453                 :             : {
     454                 :       90936 :   if (g_atomic_int_dec_and_test (&worker->ref_count))
     455                 :             :     {
     456                 :        1953 :       g_assert (worker->write_pending_flushes == NULL);
     457                 :             : 
     458                 :        1953 :       _g_dbus_shared_thread_unref (worker->shared_thread_data);
     459                 :             : 
     460                 :        1953 :       g_object_unref (worker->stream);
     461                 :             : 
     462                 :        1953 :       g_mutex_clear (&worker->read_lock);
     463                 :        1953 :       g_object_unref (worker->cancellable);
     464                 :        1953 :       if (worker->read_fd_list != NULL)
     465                 :           0 :         g_object_unref (worker->read_fd_list);
     466                 :             : 
     467                 :        1953 :       g_queue_free_full (worker->received_messages_while_frozen, (GDestroyNotify) g_object_unref);
     468                 :        1953 :       g_mutex_clear (&worker->write_lock);
     469                 :        1953 :       g_queue_free_full (worker->write_queue, (GDestroyNotify) message_to_write_data_free);
     470                 :        1953 :       g_free (worker->read_buffer);
     471                 :             : 
     472                 :        1953 :       g_free (worker);
     473                 :             :     }
     474                 :       90936 : }
     475                 :             : 
     476                 :             : static void
     477                 :         681 : _g_dbus_worker_emit_disconnected (GDBusWorker  *worker,
     478                 :             :                                   gboolean      remote_peer_vanished,
     479                 :             :                                   GError       *error)
     480                 :             : {
     481                 :         681 :   if (!g_atomic_int_get (&worker->stopped))
     482                 :         608 :     worker->disconnected_callback (worker, remote_peer_vanished, error, worker->user_data);
     483                 :         681 : }
     484                 :             : 
     485                 :             : static void
     486                 :       27418 : _g_dbus_worker_emit_message_received (GDBusWorker  *worker,
     487                 :             :                                       GDBusMessage *message)
     488                 :             : {
     489                 :       27418 :   if (!g_atomic_int_get (&worker->stopped))
     490                 :       27414 :     worker->message_received_callback (worker, message, worker->user_data);
     491                 :       27418 : }
     492                 :             : 
     493                 :             : static GDBusMessage *
     494                 :       14513 : _g_dbus_worker_emit_message_about_to_be_sent (GDBusWorker  *worker,
     495                 :             :                                               GDBusMessage *message)
     496                 :             : {
     497                 :             :   GDBusMessage *ret;
     498                 :       14513 :   if (!g_atomic_int_get (&worker->stopped))
     499                 :       14466 :     ret = worker->message_about_to_be_sent_callback (worker, g_steal_pointer (&message), worker->user_data);
     500                 :             :   else
     501                 :          47 :     ret = g_steal_pointer (&message);
     502                 :       14513 :   return ret;
     503                 :             : }
     504                 :             : 
     505                 :             : /* can only be called from private thread with read-lock held - takes ownership of @message */
     506                 :             : static void
     507                 :       27418 : _g_dbus_worker_queue_or_deliver_received_message (GDBusWorker  *worker,
     508                 :             :                                                   GDBusMessage *message)
     509                 :             : {
     510                 :       27418 :   if (worker->frozen || g_queue_get_length (worker->received_messages_while_frozen) > 0)
     511                 :             :     {
     512                 :             :       /* queue up */
     513                 :          15 :       g_queue_push_tail (worker->received_messages_while_frozen, g_steal_pointer (&message));
     514                 :             :     }
     515                 :             :   else
     516                 :             :     {
     517                 :             :       /* not frozen, nor anything in queue */
     518                 :       27403 :       _g_dbus_worker_emit_message_received (worker, message);
     519                 :       27403 :       g_clear_object (&message);
     520                 :             :     }
     521                 :       27418 : }
     522                 :             : 
     523                 :             : /* called in private thread shared by all GDBusConnection instances (without read-lock held) */
     524                 :             : static gboolean
     525                 :         204 : unfreeze_in_idle_cb (gpointer user_data)
     526                 :             : {
     527                 :         204 :   GDBusWorker *worker = user_data;
     528                 :             :   GDBusMessage *message;
     529                 :             : 
     530                 :         204 :   g_mutex_lock (&worker->read_lock);
     531                 :         204 :   if (worker->frozen)
     532                 :             :     {
     533                 :         423 :       while ((message = g_queue_pop_head (worker->received_messages_while_frozen)) != NULL)
     534                 :             :         {
     535                 :          15 :           _g_dbus_worker_emit_message_received (worker, message);
     536                 :          15 :           g_clear_object (&message);
     537                 :             :         }
     538                 :         204 :       worker->frozen = FALSE;
     539                 :             :     }
     540                 :             :   else
     541                 :             :     {
     542                 :           0 :       g_assert (g_queue_get_length (worker->received_messages_while_frozen) == 0);
     543                 :             :     }
     544                 :         204 :   g_mutex_unlock (&worker->read_lock);
     545                 :         204 :   return FALSE;
     546                 :             : }
     547                 :             : 
     548                 :             : /* can be called from any thread */
     549                 :             : void
     550                 :         204 : _g_dbus_worker_unfreeze (GDBusWorker *worker)
     551                 :             : {
     552                 :             :   GSource *idle_source;
     553                 :         204 :   idle_source = g_idle_source_new ();
     554                 :         204 :   g_source_set_priority (idle_source, G_PRIORITY_DEFAULT);
     555                 :         204 :   g_source_set_callback (idle_source,
     556                 :             :                          unfreeze_in_idle_cb,
     557                 :         204 :                          _g_dbus_worker_ref (worker),
     558                 :             :                          (GDestroyNotify) _g_dbus_worker_unref);
     559                 :         204 :   g_source_set_static_name (idle_source, "[gio] unfreeze_in_idle_cb");
     560                 :         204 :   g_source_attach (idle_source, worker->shared_thread_data->context);
     561                 :         204 :   g_source_unref (idle_source);
     562                 :         204 : }
     563                 :             : 
     564                 :             : /* ---------------------------------------------------------------------------------------------------- */
     565                 :             : 
     566                 :             : static void _g_dbus_worker_do_read_unlocked (GDBusWorker *worker);
     567                 :             : 
     568                 :             : /* called in private thread shared by all GDBusConnection instances (without read-lock held) */
     569                 :             : static void
     570                 :       57128 : _g_dbus_worker_do_read_cb (GInputStream  *input_stream,
     571                 :             :                            GAsyncResult  *res,
     572                 :             :                            gpointer       user_data)
     573                 :             : {
     574                 :       57128 :   GDBusWorker *worker = user_data;
     575                 :             :   GError *error;
     576                 :             :   gssize bytes_read;
     577                 :             : 
     578                 :       57128 :   g_mutex_lock (&worker->read_lock);
     579                 :             : 
     580                 :             :   /* If already stopped, don't even process the reply */
     581                 :       57128 :   if (g_atomic_int_get (&worker->stopped))
     582                 :        1620 :     goto out;
     583                 :             : 
     584                 :       55508 :   error = NULL;
     585                 :       55508 :   if (worker->socket == NULL)
     586                 :         306 :     bytes_read = g_input_stream_read_finish (g_io_stream_get_input_stream (worker->stream),
     587                 :             :                                              res,
     588                 :             :                                              &error);
     589                 :             :   else
     590                 :       55202 :     bytes_read = _g_socket_read_with_control_messages_finish (worker->socket,
     591                 :             :                                                               res,
     592                 :             :                                                               &error);
     593                 :       55508 :   if (worker->read_num_ancillary_messages > 0)
     594                 :             :     {
     595                 :             :       gint n;
     596                 :          30 :       for (n = 0; n < worker->read_num_ancillary_messages; n++)
     597                 :             :         {
     598                 :          15 :           GSocketControlMessage *control_message = G_SOCKET_CONTROL_MESSAGE (worker->read_ancillary_messages[n]);
     599                 :             : 
     600                 :             :           if (FALSE)
     601                 :             :             {
     602                 :             :             }
     603                 :             : #ifdef G_OS_UNIX
     604                 :          15 :           else if (G_IS_UNIX_FD_MESSAGE (control_message))
     605                 :             :             {
     606                 :             :               GUnixFDMessage *fd_message;
     607                 :             :               gint *fds;
     608                 :             :               gint num_fds;
     609                 :             : 
     610                 :          15 :               fd_message = G_UNIX_FD_MESSAGE (control_message);
     611                 :          15 :               fds = g_unix_fd_message_steal_fds (fd_message, &num_fds);
     612                 :          15 :               if (worker->read_fd_list == NULL)
     613                 :             :                 {
     614                 :          15 :                   worker->read_fd_list = g_unix_fd_list_new_from_array (fds, num_fds);
     615                 :             :                 }
     616                 :             :               else
     617                 :             :                 {
     618                 :             :                   gint n;
     619                 :           0 :                   for (n = 0; n < num_fds; n++)
     620                 :             :                     {
     621                 :             :                       /* TODO: really want a append_steal() */
     622                 :           0 :                       g_unix_fd_list_append (worker->read_fd_list, fds[n], NULL);
     623                 :           0 :                       (void) g_close (fds[n], NULL);
     624                 :             :                     }
     625                 :             :                 }
     626                 :          15 :               g_free (fds);
     627                 :             :             }
     628                 :           0 :           else if (G_IS_UNIX_CREDENTIALS_MESSAGE (control_message))
     629                 :             :             {
     630                 :             :               /* do nothing */
     631                 :             :             }
     632                 :             : #endif
     633                 :             :           else
     634                 :             :             {
     635                 :           0 :               if (error == NULL)
     636                 :             :                 {
     637                 :           0 :                   g_set_error (&error,
     638                 :             :                                G_IO_ERROR,
     639                 :             :                                G_IO_ERROR_FAILED,
     640                 :             :                                "Unexpected ancillary message of type %s received from peer",
     641                 :           0 :                                g_type_name (G_TYPE_FROM_INSTANCE (control_message)));
     642                 :           0 :                   _g_dbus_worker_emit_disconnected (worker, TRUE, error);
     643                 :           0 :                   g_error_free (error);
     644                 :           0 :                   g_object_unref (control_message);
     645                 :           0 :                   n++;
     646                 :           0 :                   while (n < worker->read_num_ancillary_messages)
     647                 :           0 :                     g_object_unref (worker->read_ancillary_messages[n++]);
     648                 :           0 :                   g_free (worker->read_ancillary_messages);
     649                 :           0 :                   goto out;
     650                 :             :                 }
     651                 :             :             }
     652                 :          15 :           g_object_unref (control_message);
     653                 :             :         }
     654                 :          15 :       g_free (worker->read_ancillary_messages);
     655                 :             :     }
     656                 :             : 
     657                 :       55508 :   if (bytes_read == -1)
     658                 :             :     {
     659                 :         106 :       if (G_UNLIKELY (_g_dbus_debug_transport ()))
     660                 :             :         {
     661                 :           0 :           _g_dbus_debug_print_lock ();
     662                 :           0 :           g_print ("========================================================================\n"
     663                 :             :                    "GDBus-debug:Transport:\n"
     664                 :             :                    "  ---- READ ERROR on stream of type %s:\n"
     665                 :             :                    "  ---- %s %d: %s\n",
     666                 :           0 :                    g_type_name (G_TYPE_FROM_INSTANCE (g_io_stream_get_input_stream (worker->stream))),
     667                 :           0 :                    g_quark_to_string (error->domain), error->code,
     668                 :           0 :                    error->message);
     669                 :           0 :           _g_dbus_debug_print_unlock ();
     670                 :             :         }
     671                 :             : 
     672                 :             :       /* Every async read that uses this callback uses worker->cancellable
     673                 :             :        * as its GCancellable. worker->cancellable gets cancelled if and only
     674                 :             :        * if the GDBusConnection tells us to close (either via
     675                 :             :        * _g_dbus_worker_stop, which is called on last-unref, or directly),
     676                 :             :        * so a cancelled read must mean our connection was closed locally.
     677                 :             :        *
     678                 :             :        * If we're closing, other errors are possible - notably,
     679                 :             :        * G_IO_ERROR_CLOSED can be seen if we close the stream with an async
     680                 :             :        * read in-flight. It seems sensible to treat all read errors during
     681                 :             :        * closing as an expected thing that doesn't trip exit-on-close.
     682                 :             :        *
     683                 :             :        * Because close_expected can't be set until we get into the worker
     684                 :             :        * thread, but the cancellable is signalled sooner (from another
     685                 :             :        * thread), we do still need to check the error.
     686                 :             :        */
     687                 :         206 :       if (worker->close_expected ||
     688                 :         100 :           g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
     689                 :         106 :         _g_dbus_worker_emit_disconnected (worker, FALSE, NULL);
     690                 :             :       else
     691                 :           0 :         _g_dbus_worker_emit_disconnected (worker, TRUE, error);
     692                 :             : 
     693                 :         106 :       g_error_free (error);
     694                 :         106 :       goto out;
     695                 :             :     }
     696                 :             : 
     697                 :             : #if 0
     698                 :             :   g_debug ("read %d bytes (is_closed=%d blocking=%d condition=0x%02x) stream %p, %p",
     699                 :             :            (gint) bytes_read,
     700                 :             :            g_socket_is_closed (g_socket_connection_get_socket (G_SOCKET_CONNECTION (worker->stream))),
     701                 :             :            g_socket_get_blocking (g_socket_connection_get_socket (G_SOCKET_CONNECTION (worker->stream))),
     702                 :             :            g_socket_condition_check (g_socket_connection_get_socket (G_SOCKET_CONNECTION (worker->stream)),
     703                 :             :                                      G_IO_IN | G_IO_OUT | G_IO_HUP),
     704                 :             :            worker->stream,
     705                 :             :            worker);
     706                 :             : #endif
     707                 :             : 
     708                 :             :   /* The read failed, which could mean the dbus-daemon was sent SIGTERM. */
     709                 :       55402 :   if (bytes_read == 0)
     710                 :             :     {
     711                 :         431 :       g_set_error (&error,
     712                 :             :                    G_IO_ERROR,
     713                 :             :                    G_IO_ERROR_FAILED,
     714                 :             :                    "Underlying GIOStream returned 0 bytes on an async read");
     715                 :         431 :       _g_dbus_worker_emit_disconnected (worker, TRUE, error);
     716                 :         431 :       g_error_free (error);
     717                 :         431 :       goto out;
     718                 :             :     }
     719                 :             : 
     720                 :       54971 :   read_message_print_transport_debug (bytes_read, worker);
     721                 :             : 
     722                 :       54971 :   worker->read_buffer_cur_size += bytes_read;
     723                 :       54971 :   if (worker->read_buffer_bytes_wanted == worker->read_buffer_cur_size)
     724                 :             :     {
     725                 :             :       /* OK, got what we asked for! */
     726                 :       54841 :       if (worker->read_buffer_bytes_wanted == 16)
     727                 :             :         {
     728                 :             :           gssize message_len;
     729                 :             :           /* OK, got the header - determine how many more bytes are needed */
     730                 :       27423 :           error = NULL;
     731                 :       27423 :           message_len = g_dbus_message_bytes_needed ((guchar *) worker->read_buffer,
     732                 :             :                                                      16,
     733                 :             :                                                      &error);
     734                 :       27423 :           if (message_len == -1)
     735                 :             :             {
     736                 :           0 :               g_warning ("_g_dbus_worker_do_read_cb: error determining bytes needed: %s", error->message);
     737                 :           0 :               _g_dbus_worker_emit_disconnected (worker, FALSE, error);
     738                 :           0 :               g_error_free (error);
     739                 :           0 :               goto out;
     740                 :             :             }
     741                 :             : 
     742                 :       27423 :           worker->read_buffer_bytes_wanted = message_len;
     743                 :       27423 :           _g_dbus_worker_do_read_unlocked (worker);
     744                 :             :         }
     745                 :             :       else
     746                 :             :         {
     747                 :             :           GDBusMessage *message;
     748                 :       27418 :           error = NULL;
     749                 :             : 
     750                 :             :           /* TODO: use connection->priv->auth to decode the message */
     751                 :             : 
     752                 :       27418 :           message = g_dbus_message_new_from_blob ((guchar *) worker->read_buffer,
     753                 :             :                                                   worker->read_buffer_cur_size,
     754                 :             :                                                   worker->capabilities,
     755                 :             :                                                   &error);
     756                 :       27418 :           if (message == NULL)
     757                 :             :             {
     758                 :             :               gchar *s;
     759                 :           0 :               s = _g_dbus_hexdump (worker->read_buffer, worker->read_buffer_cur_size, 2);
     760                 :           0 :               g_warning ("Error decoding D-Bus message of %" G_GSIZE_FORMAT " bytes\n"
     761                 :             :                          "The error is: %s\n"
     762                 :             :                          "The payload is as follows:\n"
     763                 :             :                          "%s",
     764                 :             :                          worker->read_buffer_cur_size,
     765                 :             :                          error->message,
     766                 :             :                          s);
     767                 :           0 :               g_free (s);
     768                 :           0 :               _g_dbus_worker_emit_disconnected (worker, FALSE, error);
     769                 :           0 :               g_error_free (error);
     770                 :           0 :               goto out;
     771                 :             :             }
     772                 :             : 
     773                 :             : #ifdef G_OS_UNIX
     774                 :       27418 :           if (worker->read_fd_list != NULL)
     775                 :             :             {
     776                 :          15 :               g_dbus_message_set_unix_fd_list (message, worker->read_fd_list);
     777                 :          15 :               g_object_unref (worker->read_fd_list);
     778                 :          15 :               worker->read_fd_list = NULL;
     779                 :             :             }
     780                 :             : #endif
     781                 :             : 
     782                 :       27418 :           if (G_UNLIKELY (_g_dbus_debug_message ()))
     783                 :             :             {
     784                 :             :               gchar *s;
     785                 :           0 :               _g_dbus_debug_print_lock ();
     786                 :           0 :               g_print ("========================================================================\n"
     787                 :             :                        "GDBus-debug:Message:\n"
     788                 :             :                        "  <<<< RECEIVED D-Bus message (%" G_GSIZE_FORMAT " bytes)\n",
     789                 :             :                        worker->read_buffer_cur_size);
     790                 :           0 :               s = g_dbus_message_print (message, 2);
     791                 :           0 :               g_print ("%s", s);
     792                 :           0 :               g_free (s);
     793                 :           0 :               if (G_UNLIKELY (_g_dbus_debug_payload ()))
     794                 :             :                 {
     795                 :           0 :                   s = _g_dbus_hexdump (worker->read_buffer, worker->read_buffer_cur_size, 2);
     796                 :           0 :                   g_print ("%s\n", s);
     797                 :           0 :                   g_free (s);
     798                 :             :                 }
     799                 :           0 :               _g_dbus_debug_print_unlock ();
     800                 :             :             }
     801                 :             : 
     802                 :             :           /* yay, got a message, go deliver it */
     803                 :       27418 :           _g_dbus_worker_queue_or_deliver_received_message (worker, g_steal_pointer (&message));
     804                 :             : 
     805                 :             :           /* start reading another message! */
     806                 :       27418 :           worker->read_buffer_bytes_wanted = 0;
     807                 :       27418 :           worker->read_buffer_cur_size = 0;
     808                 :       27418 :           _g_dbus_worker_do_read_unlocked (worker);
     809                 :             :         }
     810                 :             :     }
     811                 :             :   else
     812                 :             :     {
     813                 :             :       /* didn't get all the bytes we requested - so repeat the request... */
     814                 :         130 :       _g_dbus_worker_do_read_unlocked (worker);
     815                 :             :     }
     816                 :             : 
     817                 :       57128 :  out:
     818                 :       57128 :   g_mutex_unlock (&worker->read_lock);
     819                 :             : 
     820                 :             :   /* check if there is any pending close */
     821                 :       57128 :   schedule_pending_close (worker);
     822                 :             : 
     823                 :             :   /* gives up the reference acquired when calling g_input_stream_read_async() */
     824                 :       57128 :   _g_dbus_worker_unref (worker);
     825                 :       57128 : }
     826                 :             : 
     827                 :             : /* called in private thread shared by all GDBusConnection instances (with read-lock held) */
     828                 :             : static void
     829                 :       57181 : _g_dbus_worker_do_read_unlocked (GDBusWorker *worker)
     830                 :             : {
     831                 :             :   /* Note that we do need to keep trying to read even if close_expected is
     832                 :             :    * true, because only failing a read causes us to signal 'closed'.
     833                 :             :    */
     834                 :             : 
     835                 :             :   /* if bytes_wanted is zero, it means start reading a message */
     836                 :       57181 :   if (worker->read_buffer_bytes_wanted == 0)
     837                 :             :     {
     838                 :       29628 :       worker->read_buffer_cur_size = 0;
     839                 :       29628 :       worker->read_buffer_bytes_wanted = 16;
     840                 :             :     }
     841                 :             : 
     842                 :             :   /* ensure we have a (big enough) buffer */
     843                 :       57181 :   if (worker->read_buffer == NULL || worker->read_buffer_bytes_wanted > worker->read_buffer_allocated_size)
     844                 :             :     {
     845                 :             :       /* TODO: 4096 is randomly chosen; might want a better chosen default minimum */
     846                 :        2222 :       worker->read_buffer_allocated_size = MAX (worker->read_buffer_bytes_wanted, 4096);
     847                 :        2222 :       worker->read_buffer = g_realloc (worker->read_buffer, worker->read_buffer_allocated_size);
     848                 :             :     }
     849                 :             : 
     850                 :       57181 :   if (worker->socket == NULL)
     851                 :         411 :     g_input_stream_read_async (g_io_stream_get_input_stream (worker->stream),
     852                 :         411 :                                worker->read_buffer + worker->read_buffer_cur_size,
     853                 :         411 :                                worker->read_buffer_bytes_wanted - worker->read_buffer_cur_size,
     854                 :             :                                G_PRIORITY_DEFAULT,
     855                 :             :                                worker->cancellable,
     856                 :             :                                (GAsyncReadyCallback) _g_dbus_worker_do_read_cb,
     857                 :         411 :                                _g_dbus_worker_ref (worker));
     858                 :             :   else
     859                 :             :     {
     860                 :       56770 :       worker->read_ancillary_messages = NULL;
     861                 :       56770 :       worker->read_num_ancillary_messages = 0;
     862                 :       56770 :       _g_socket_read_with_control_messages (worker->socket,
     863                 :       56770 :                                             worker->read_buffer + worker->read_buffer_cur_size,
     864                 :       56770 :                                             worker->read_buffer_bytes_wanted - worker->read_buffer_cur_size,
     865                 :             :                                             &worker->read_ancillary_messages,
     866                 :             :                                             &worker->read_num_ancillary_messages,
     867                 :             :                                             G_PRIORITY_DEFAULT,
     868                 :             :                                             worker->cancellable,
     869                 :             :                                             (GAsyncReadyCallback) _g_dbus_worker_do_read_cb,
     870                 :       56770 :                                             _g_dbus_worker_ref (worker));
     871                 :             :     }
     872                 :       57181 : }
     873                 :             : 
     874                 :             : /* called in private thread shared by all GDBusConnection instances (without read-lock held) */
     875                 :             : static gboolean
     876                 :        2210 : _g_dbus_worker_do_initial_read (gpointer data)
     877                 :             : {
     878                 :        2210 :   GDBusWorker *worker = data;
     879                 :        2210 :   g_mutex_lock (&worker->read_lock);
     880                 :        2210 :   _g_dbus_worker_do_read_unlocked (worker);
     881                 :        2210 :   g_mutex_unlock (&worker->read_lock);
     882                 :        2210 :   return FALSE;
     883                 :             : }
     884                 :             : 
     885                 :             : /* ---------------------------------------------------------------------------------------------------- */
     886                 :             : 
     887                 :             : struct _MessageToWriteData
     888                 :             : {
     889                 :             :   GDBusWorker  *worker;
     890                 :             :   GDBusMessage *message;  /* (owned) */
     891                 :             :   gchar        *blob;
     892                 :             :   gsize         blob_size;
     893                 :             : 
     894                 :             :   gsize         total_written;
     895                 :             :   GTask        *task;  /* (owned) and (nullable) before writing starts and after g_task_return_*() is called */
     896                 :             : };
     897                 :             : 
     898                 :             : static void
     899                 :       14735 : message_to_write_data_free (MessageToWriteData *data)
     900                 :             : {
     901                 :       14735 :   _g_dbus_worker_unref (data->worker);
     902                 :       14735 :   g_clear_object (&data->message);
     903                 :       14735 :   g_free (data->blob);
     904                 :             : 
     905                 :             :   /* The task must either not have been created, or have been created, returned
     906                 :             :    * and finalised by now. */
     907                 :       14735 :   g_assert (data->task == NULL);
     908                 :             : 
     909                 :       14735 :   g_slice_free (MessageToWriteData, data);
     910                 :       14735 : }
     911                 :             : 
     912                 :             : /* ---------------------------------------------------------------------------------------------------- */
     913                 :             : 
     914                 :             : static void write_message_continue_writing (MessageToWriteData *data);
     915                 :             : 
     916                 :             : /* called in private thread shared by all GDBusConnection instances
     917                 :             :  *
     918                 :             :  * write-lock is not held on entry
     919                 :             :  * output_pending is PENDING_WRITE on entry
     920                 :             :  * @user_data is (transfer full)
     921                 :             :  */
     922                 :             : static void
     923                 :         660 : write_message_async_cb (GObject      *source_object,
     924                 :             :                         GAsyncResult *res,
     925                 :             :                         gpointer      user_data)
     926                 :             : {
     927                 :         660 :   MessageToWriteData *data = g_steal_pointer (&user_data);
     928                 :             :   gssize bytes_written;
     929                 :             :   GError *error;
     930                 :             : 
     931                 :             :   /* The ownership of @data is a bit odd in this function: it’s (transfer full)
     932                 :             :    * when the function is called, but the code paths which call g_task_return_*()
     933                 :             :    * on @data->task will indirectly cause it to be freed, because @data is
     934                 :             :    * always guaranteed to be the user_data in the #GTask. So that’s why it looks
     935                 :             :    * like @data is not always freed on every code path in this function. */
     936                 :             : 
     937                 :         660 :   error = NULL;
     938                 :         660 :   bytes_written = g_output_stream_write_finish (G_OUTPUT_STREAM (source_object),
     939                 :             :                                                 res,
     940                 :             :                                                 &error);
     941                 :         660 :   if (bytes_written == -1)
     942                 :             :     {
     943                 :         111 :       GTask *task = g_steal_pointer (&data->task);
     944                 :         111 :       g_task_return_error (task, error);
     945                 :         111 :       g_clear_object (&task);
     946                 :         111 :       goto out;
     947                 :             :     }
     948                 :         549 :   g_assert (bytes_written > 0); /* zero is never returned */
     949                 :             : 
     950                 :         549 :   write_message_print_transport_debug (bytes_written, data);
     951                 :             : 
     952                 :         549 :   data->total_written += bytes_written;
     953                 :         549 :   g_assert (data->total_written <= data->blob_size);
     954                 :         549 :   if (data->total_written == data->blob_size)
     955                 :             :     {
     956                 :           8 :       GTask *task = g_steal_pointer (&data->task);
     957                 :           8 :       g_task_return_boolean (task, TRUE);
     958                 :           8 :       g_clear_object (&task);
     959                 :           8 :       goto out;
     960                 :             :     }
     961                 :             : 
     962                 :         541 :   write_message_continue_writing (g_steal_pointer (&data));
     963                 :             : 
     964                 :         660 :  out:
     965                 :             :   ;
     966                 :         660 : }
     967                 :             : 
     968                 :             : /* called in private thread shared by all GDBusConnection instances
     969                 :             :  *
     970                 :             :  * write-lock is not held on entry
     971                 :             :  * output_pending is PENDING_WRITE on entry
     972                 :             :  */
     973                 :             : #ifdef G_OS_UNIX
     974                 :             : static gboolean
     975                 :           0 : on_socket_ready (GSocket      *socket,
     976                 :             :                  GIOCondition  condition,
     977                 :             :                  gpointer      user_data)
     978                 :             : {
     979                 :           0 :   MessageToWriteData *data = g_steal_pointer (&user_data);
     980                 :           0 :   write_message_continue_writing (g_steal_pointer (&data));
     981                 :           0 :   return G_SOURCE_REMOVE;
     982                 :             : }
     983                 :             : #endif
     984                 :             : 
     985                 :             : /* called in private thread shared by all GDBusConnection instances
     986                 :             :  *
     987                 :             :  * write-lock is not held on entry
     988                 :             :  * output_pending is PENDING_WRITE on entry
     989                 :             :  * @data is (transfer full)
     990                 :             :  */
     991                 :             : static void
     992                 :       15059 : write_message_continue_writing (MessageToWriteData *data)
     993                 :             : {
     994                 :             :   GOutputStream *ostream;
     995                 :             : #ifdef G_OS_UNIX
     996                 :             :   GUnixFDList *fd_list;
     997                 :             : #endif
     998                 :             : 
     999                 :             :   /* The ownership of @data is a bit odd in this function: it’s (transfer full)
    1000                 :             :    * when the function is called, but the code paths which call g_task_return_*()
    1001                 :             :    * on @data->task will indirectly cause it to be freed, because @data is
    1002                 :             :    * always guaranteed to be the user_data in the #GTask. So that’s why it looks
    1003                 :             :    * like @data is not always freed on every code path in this function. */
    1004                 :             : 
    1005                 :       15059 :   ostream = g_io_stream_get_output_stream (data->worker->stream);
    1006                 :             : #ifdef G_OS_UNIX
    1007                 :       15059 :   fd_list = g_dbus_message_get_unix_fd_list (data->message);
    1008                 :             : #endif
    1009                 :             : 
    1010                 :       15059 :   g_assert (!g_output_stream_has_pending (ostream));
    1011                 :       15059 :   g_assert_cmpint (data->total_written, <, data->blob_size);
    1012                 :             : 
    1013                 :             :   if (FALSE)
    1014                 :             :     {
    1015                 :             :     }
    1016                 :             : #ifdef G_OS_UNIX
    1017                 :       15059 :   else if (G_IS_SOCKET_OUTPUT_STREAM (ostream) && data->total_written == 0)
    1018                 :           5 :     {
    1019                 :             :       GOutputVector vector;
    1020                 :             :       GSocketControlMessage *control_message;
    1021                 :             :       gssize bytes_written;
    1022                 :             :       GError *error;
    1023                 :             : 
    1024                 :       14399 :       vector.buffer = data->blob;
    1025                 :       14399 :       vector.size = data->blob_size;
    1026                 :             : 
    1027                 :       14399 :       control_message = NULL;
    1028                 :       14399 :       if (fd_list != NULL && g_unix_fd_list_get_length (fd_list) > 0)
    1029                 :             :         {
    1030                 :          17 :           if (!(data->worker->capabilities & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING))
    1031                 :             :             {
    1032                 :           0 :               GTask *task = g_steal_pointer (&data->task);
    1033                 :           0 :               g_task_return_new_error_literal (task,
    1034                 :             :                                                G_IO_ERROR,
    1035                 :             :                                                G_IO_ERROR_FAILED,
    1036                 :             :                                                "Tried sending a file descriptor "
    1037                 :             :                                                "but remote peer does not support "
    1038                 :             :                                                "this capability");
    1039                 :           0 :               g_clear_object (&task);
    1040                 :           0 :               goto out;
    1041                 :             :             }
    1042                 :          17 :           control_message = g_unix_fd_message_new_with_fd_list (fd_list);
    1043                 :             :         }
    1044                 :             : 
    1045                 :       14399 :       error = NULL;
    1046                 :       14399 :       bytes_written = g_socket_send_message (data->worker->socket,
    1047                 :             :                                              NULL, /* address */
    1048                 :             :                                              &vector,
    1049                 :             :                                              1,
    1050                 :       14399 :                                              control_message != NULL ? &control_message : NULL,
    1051                 :             :                                              control_message != NULL ? 1 : 0,
    1052                 :             :                                              G_SOCKET_MSG_NONE,
    1053                 :       14399 :                                              data->worker->cancellable,
    1054                 :             :                                              &error);
    1055                 :       14399 :       if (control_message != NULL)
    1056                 :          17 :         g_object_unref (control_message);
    1057                 :             : 
    1058                 :       14399 :       if (bytes_written == -1)
    1059                 :             :         {
    1060                 :             :           /* Handle WOULD_BLOCK by waiting until there's room in the buffer */
    1061                 :          33 :           if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
    1062                 :             :             {
    1063                 :             :               GSource *source;
    1064                 :           0 :               source = g_socket_create_source (data->worker->socket,
    1065                 :             :                                                G_IO_OUT | G_IO_HUP | G_IO_ERR,
    1066                 :           0 :                                                data->worker->cancellable);
    1067                 :           0 :               g_source_set_callback (source,
    1068                 :             :                                      (GSourceFunc) on_socket_ready,
    1069                 :             :                                      g_steal_pointer (&data),
    1070                 :             :                                      NULL); /* GDestroyNotify */
    1071                 :           0 :               g_source_attach (source, g_main_context_get_thread_default ());
    1072                 :           0 :               g_source_unref (source);
    1073                 :           0 :               g_error_free (error);
    1074                 :           0 :               goto out;
    1075                 :             :             }
    1076                 :             :           else
    1077                 :             :             {
    1078                 :          33 :               GTask *task = g_steal_pointer (&data->task);
    1079                 :          33 :               g_task_return_error (task, error);
    1080                 :          33 :               g_clear_object (&task);
    1081                 :          33 :               goto out;
    1082                 :             :             }
    1083                 :             :         }
    1084                 :       14366 :       g_assert (bytes_written > 0); /* zero is never returned */
    1085                 :             : 
    1086                 :       14366 :       write_message_print_transport_debug (bytes_written, data);
    1087                 :             : 
    1088                 :       14366 :       data->total_written += bytes_written;
    1089                 :       14366 :       g_assert (data->total_written <= data->blob_size);
    1090                 :       14366 :       if (data->total_written == data->blob_size)
    1091                 :             :         {
    1092                 :       14361 :           GTask *task = g_steal_pointer (&data->task);
    1093                 :       14361 :           g_task_return_boolean (task, TRUE);
    1094                 :       14361 :           g_clear_object (&task);
    1095                 :       14361 :           goto out;
    1096                 :             :         }
    1097                 :             : 
    1098                 :           5 :       write_message_continue_writing (g_steal_pointer (&data));
    1099                 :             :     }
    1100                 :             : #endif
    1101                 :             :   else
    1102                 :             :     {
    1103                 :             : #ifdef G_OS_UNIX
    1104                 :         660 :       if (data->total_written == 0 && fd_list != NULL)
    1105                 :             :         {
    1106                 :             :           /* We were trying to write byte 0 of the message, which needs
    1107                 :             :            * the fd list to be attached to it, but this connection doesn't
    1108                 :             :            * support doing that. */
    1109                 :           0 :           GTask *task = g_steal_pointer (&data->task);
    1110                 :           0 :           g_task_return_new_error (task,
    1111                 :             :                                    G_IO_ERROR,
    1112                 :             :                                    G_IO_ERROR_FAILED,
    1113                 :             :                                    "Tried sending a file descriptor on unsupported stream of type %s",
    1114                 :           0 :                                    g_type_name (G_TYPE_FROM_INSTANCE (ostream)));
    1115                 :           0 :           g_clear_object (&task);
    1116                 :           0 :           goto out;
    1117                 :             :         }
    1118                 :             : #endif
    1119                 :             : 
    1120                 :         660 :       g_output_stream_write_async (ostream,
    1121                 :         660 :                                    (const gchar *) data->blob + data->total_written,
    1122                 :         660 :                                    data->blob_size - data->total_written,
    1123                 :             :                                    G_PRIORITY_DEFAULT,
    1124                 :         660 :                                    data->worker->cancellable,
    1125                 :             :                                    write_message_async_cb,
    1126                 :             :                                    data);  /* steal @data */
    1127                 :             :     }
    1128                 :             : #ifdef G_OS_UNIX
    1129                 :       15059 :  out:
    1130                 :             : #endif
    1131                 :             :   ;
    1132                 :       15059 : }
    1133                 :             : 
    1134                 :             : /* called in private thread shared by all GDBusConnection instances
    1135                 :             :  *
    1136                 :             :  * write-lock is not held on entry
    1137                 :             :  * output_pending is PENDING_WRITE on entry
    1138                 :             :  */
    1139                 :             : static void
    1140                 :       14513 : write_message_async (GDBusWorker         *worker,
    1141                 :             :                      MessageToWriteData  *data,
    1142                 :             :                      GAsyncReadyCallback  callback,
    1143                 :             :                      gpointer             user_data)
    1144                 :             : {
    1145                 :       14513 :   data->task = g_task_new (NULL, NULL, callback, user_data);
    1146                 :       14513 :   g_task_set_source_tag (data->task, write_message_async);
    1147                 :       14513 :   g_task_set_name (data->task, "[gio] D-Bus write message");
    1148                 :       14513 :   data->total_written = 0;
    1149                 :       14513 :   write_message_continue_writing (g_steal_pointer (&data));
    1150                 :       14513 : }
    1151                 :             : 
    1152                 :             : /* called in private thread shared by all GDBusConnection instances (with write-lock held) */
    1153                 :             : static gboolean
    1154                 :       14513 : write_message_finish (GAsyncResult   *res,
    1155                 :             :                       GError        **error)
    1156                 :             : {
    1157                 :       14513 :   g_return_val_if_fail (g_task_is_valid (res, NULL), FALSE);
    1158                 :             : 
    1159                 :       14513 :   return g_task_propagate_boolean (G_TASK (res), error);
    1160                 :             : }
    1161                 :             : /* ---------------------------------------------------------------------------------------------------- */
    1162                 :             : 
    1163                 :             : static void continue_writing (GDBusWorker *worker);
    1164                 :             : 
    1165                 :             : typedef struct
    1166                 :             : {
    1167                 :             :   GDBusWorker *worker;
    1168                 :             :   GList *flushers;
    1169                 :             : } FlushAsyncData;
    1170                 :             : 
    1171                 :             : static void
    1172                 :        2167 : flush_data_list_complete (const GList  *flushers,
    1173                 :             :                           const GError *error)
    1174                 :             : {
    1175                 :             :   const GList *l;
    1176                 :             : 
    1177                 :        2275 :   for (l = flushers; l != NULL; l = l->next)
    1178                 :             :     {
    1179                 :         108 :       FlushData *f = l->data;
    1180                 :             : 
    1181                 :         108 :       f->error = error != NULL ? g_error_copy (error) : NULL;
    1182                 :             : 
    1183                 :         108 :       g_mutex_lock (&f->mutex);
    1184                 :         108 :       f->finished = TRUE;
    1185                 :         108 :       g_cond_signal (&f->cond);
    1186                 :         108 :       g_mutex_unlock (&f->mutex);
    1187                 :             :     }
    1188                 :        2167 : }
    1189                 :             : 
    1190                 :             : /* called in private thread shared by all GDBusConnection instances
    1191                 :             :  *
    1192                 :             :  * write-lock is not held on entry
    1193                 :             :  * output_pending is PENDING_FLUSH on entry
    1194                 :             :  */
    1195                 :             : static void
    1196                 :         108 : ostream_flush_cb (GObject      *source_object,
    1197                 :             :                   GAsyncResult *res,
    1198                 :             :                   gpointer      user_data)
    1199                 :             : {
    1200                 :         108 :   FlushAsyncData *data = user_data;
    1201                 :             :   GError *error;
    1202                 :             : 
    1203                 :         108 :   error = NULL;
    1204                 :         108 :   g_output_stream_flush_finish (G_OUTPUT_STREAM (source_object),
    1205                 :             :                                 res,
    1206                 :             :                                 &error);
    1207                 :             : 
    1208                 :         108 :   if (error == NULL)
    1209                 :             :     {
    1210                 :         108 :       if (G_UNLIKELY (_g_dbus_debug_transport ()))
    1211                 :             :         {
    1212                 :           0 :           _g_dbus_debug_print_lock ();
    1213                 :           0 :           g_print ("========================================================================\n"
    1214                 :             :                    "GDBus-debug:Transport:\n"
    1215                 :             :                    "  ---- FLUSHED stream of type %s\n",
    1216                 :           0 :                    g_type_name (G_TYPE_FROM_INSTANCE (g_io_stream_get_output_stream (data->worker->stream))));
    1217                 :           0 :           _g_dbus_debug_print_unlock ();
    1218                 :             :         }
    1219                 :             :     }
    1220                 :             : 
    1221                 :             :   /* Make sure we tell folks that we don't have additional
    1222                 :             :      flushes pending */
    1223                 :         108 :   g_mutex_lock (&data->worker->write_lock);
    1224                 :         108 :   data->worker->write_num_messages_flushed = data->worker->write_num_messages_written;
    1225                 :         108 :   g_assert (data->worker->output_pending == PENDING_FLUSH);
    1226                 :         108 :   data->worker->output_pending = PENDING_NONE;
    1227                 :         108 :   g_mutex_unlock (&data->worker->write_lock);
    1228                 :             : 
    1229                 :         108 :   g_assert (data->flushers != NULL);
    1230                 :         108 :   flush_data_list_complete (data->flushers, error);
    1231                 :         108 :   g_list_free (data->flushers);
    1232                 :         108 :   if (error != NULL)
    1233                 :           0 :     g_error_free (error);
    1234                 :             : 
    1235                 :             :   /* OK, cool, finally kick off the next write */
    1236                 :         108 :   continue_writing (data->worker);
    1237                 :             : 
    1238                 :         108 :   _g_dbus_worker_unref (data->worker);
    1239                 :         108 :   g_free (data);
    1240                 :         108 : }
    1241                 :             : 
    1242                 :             : /* called in private thread shared by all GDBusConnection instances
    1243                 :             :  *
    1244                 :             :  * write-lock is not held on entry
    1245                 :             :  * output_pending is PENDING_FLUSH on entry
    1246                 :             :  */
    1247                 :             : static void
    1248                 :         108 : start_flush (FlushAsyncData *data)
    1249                 :             : {
    1250                 :         108 :   g_output_stream_flush_async (g_io_stream_get_output_stream (data->worker->stream),
    1251                 :             :                                G_PRIORITY_DEFAULT,
    1252                 :         108 :                                data->worker->cancellable,
    1253                 :             :                                ostream_flush_cb,
    1254                 :             :                                data);
    1255                 :         108 : }
    1256                 :             : 
    1257                 :             : /* called in private thread shared by all GDBusConnection instances
    1258                 :             :  *
    1259                 :             :  * write-lock is held on entry
    1260                 :             :  * output_pending is PENDING_NONE on entry
    1261                 :             :  */
    1262                 :             : static void
    1263                 :       14513 : message_written_unlocked (GDBusWorker *worker,
    1264                 :             :                           MessageToWriteData *message_data)
    1265                 :             : {
    1266                 :       14513 :   if (G_UNLIKELY (_g_dbus_debug_message ()))
    1267                 :             :     {
    1268                 :             :       gchar *s;
    1269                 :           0 :       _g_dbus_debug_print_lock ();
    1270                 :           0 :       g_print ("========================================================================\n"
    1271                 :             :                "GDBus-debug:Message:\n"
    1272                 :             :                "  >>>> SENT D-Bus message (%" G_GSIZE_FORMAT " bytes)\n",
    1273                 :             :                message_data->blob_size);
    1274                 :           0 :       s = g_dbus_message_print (message_data->message, 2);
    1275                 :           0 :       g_print ("%s", s);
    1276                 :           0 :       g_free (s);
    1277                 :           0 :       if (G_UNLIKELY (_g_dbus_debug_payload ()))
    1278                 :             :         {
    1279                 :           0 :           s = _g_dbus_hexdump (message_data->blob, message_data->blob_size, 2);
    1280                 :           0 :           g_print ("%s\n", s);
    1281                 :           0 :           g_free (s);
    1282                 :             :         }
    1283                 :           0 :       _g_dbus_debug_print_unlock ();
    1284                 :             :     }
    1285                 :             : 
    1286                 :       14513 :   worker->write_num_messages_written += 1;
    1287                 :       14513 : }
    1288                 :             : 
    1289                 :             : /* called in private thread shared by all GDBusConnection instances
    1290                 :             :  *
    1291                 :             :  * write-lock is held on entry
    1292                 :             :  * output_pending is PENDING_NONE on entry
    1293                 :             :  *
    1294                 :             :  * Returns: non-%NULL, setting @output_pending, if we need to flush now
    1295                 :             :  */
    1296                 :             : static FlushAsyncData *
    1297                 :       22432 : prepare_flush_unlocked (GDBusWorker *worker)
    1298                 :             : {
    1299                 :             :   GList *l;
    1300                 :             :   GList *ll;
    1301                 :             :   GList *flushers;
    1302                 :             : 
    1303                 :       22432 :   flushers = NULL;
    1304                 :       22594 :   for (l = worker->write_pending_flushes; l != NULL; l = ll)
    1305                 :             :     {
    1306                 :         162 :       FlushData *f = l->data;
    1307                 :         162 :       ll = l->next;
    1308                 :             : 
    1309                 :         162 :       if (f->number_to_wait_for == worker->write_num_messages_written)
    1310                 :             :         {
    1311                 :         108 :           flushers = g_list_append (flushers, f);
    1312                 :         108 :           worker->write_pending_flushes = g_list_delete_link (worker->write_pending_flushes, l);
    1313                 :             :         }
    1314                 :             :     }
    1315                 :       22432 :   if (flushers != NULL)
    1316                 :             :     {
    1317                 :         108 :       g_assert (worker->output_pending == PENDING_NONE);
    1318                 :         108 :       worker->output_pending = PENDING_FLUSH;
    1319                 :             :     }
    1320                 :             : 
    1321                 :       22432 :   if (flushers != NULL)
    1322                 :             :     {
    1323                 :             :       FlushAsyncData *data;
    1324                 :             : 
    1325                 :         108 :       data = g_new0 (FlushAsyncData, 1);
    1326                 :         108 :       data->worker = _g_dbus_worker_ref (worker);
    1327                 :         108 :       data->flushers = flushers;
    1328                 :         108 :       return data;
    1329                 :             :     }
    1330                 :             : 
    1331                 :       22324 :   return NULL;
    1332                 :             : }
    1333                 :             : 
    1334                 :             : /* called in private thread shared by all GDBusConnection instances
    1335                 :             :  *
    1336                 :             :  * write-lock is not held on entry
    1337                 :             :  * output_pending is PENDING_WRITE on entry
    1338                 :             :  * @user_data is (transfer full)
    1339                 :             :  */
    1340                 :             : static void
    1341                 :       14513 : write_message_cb (GObject       *source_object,
    1342                 :             :                   GAsyncResult  *res,
    1343                 :             :                   gpointer       user_data)
    1344                 :             : {
    1345                 :       14513 :   MessageToWriteData *data = user_data;
    1346                 :             :   GError *error;
    1347                 :             : 
    1348                 :       14513 :   g_mutex_lock (&data->worker->write_lock);
    1349                 :       14513 :   g_assert (data->worker->output_pending == PENDING_WRITE);
    1350                 :       14513 :   data->worker->output_pending = PENDING_NONE;
    1351                 :             : 
    1352                 :       14513 :   error = NULL;
    1353                 :       14513 :   if (!write_message_finish (res, &error))
    1354                 :             :     {
    1355                 :         144 :       g_mutex_unlock (&data->worker->write_lock);
    1356                 :             : 
    1357                 :             :       /* TODO: handle */
    1358                 :         144 :       _g_dbus_worker_emit_disconnected (data->worker, TRUE, error);
    1359                 :         144 :       g_error_free (error);
    1360                 :             : 
    1361                 :         144 :       g_mutex_lock (&data->worker->write_lock);
    1362                 :             :     }
    1363                 :             : 
    1364                 :       14513 :   message_written_unlocked (data->worker, data);
    1365                 :             : 
    1366                 :       14513 :   g_mutex_unlock (&data->worker->write_lock);
    1367                 :             : 
    1368                 :       14513 :   continue_writing (data->worker);
    1369                 :             : 
    1370                 :       14513 :   message_to_write_data_free (data);
    1371                 :       14513 : }
    1372                 :             : 
    1373                 :             : /* called in private thread shared by all GDBusConnection instances
    1374                 :             :  *
    1375                 :             :  * write-lock is not held on entry
    1376                 :             :  * output_pending is PENDING_CLOSE on entry
    1377                 :             :  */
    1378                 :             : static void
    1379                 :        2059 : iostream_close_cb (GObject      *source_object,
    1380                 :             :                    GAsyncResult *res,
    1381                 :             :                    gpointer      user_data)
    1382                 :             : {
    1383                 :        2059 :   GDBusWorker *worker = user_data;
    1384                 :        2059 :   GError *error = NULL;
    1385                 :             :   GList *pending_close_attempts, *pending_flush_attempts;
    1386                 :             :   GQueue *send_queue;
    1387                 :             : 
    1388                 :        2059 :   g_io_stream_close_finish (worker->stream, res, &error);
    1389                 :             : 
    1390                 :        2059 :   g_mutex_lock (&worker->write_lock);
    1391                 :             : 
    1392                 :        2059 :   pending_close_attempts = worker->pending_close_attempts;
    1393                 :        2059 :   worker->pending_close_attempts = NULL;
    1394                 :             : 
    1395                 :        2059 :   pending_flush_attempts = worker->write_pending_flushes;
    1396                 :        2059 :   worker->write_pending_flushes = NULL;
    1397                 :             : 
    1398                 :        2059 :   send_queue = worker->write_queue;
    1399                 :        2059 :   worker->write_queue = g_queue_new ();
    1400                 :             : 
    1401                 :        2059 :   g_assert (worker->output_pending == PENDING_CLOSE);
    1402                 :        2059 :   worker->output_pending = PENDING_NONE;
    1403                 :             : 
    1404                 :             :   /* Ensure threads waiting for pending flushes to finish will be unblocked. */
    1405                 :        2059 :   worker->write_num_messages_flushed =
    1406                 :        2059 :     worker->write_num_messages_written + g_list_length(pending_flush_attempts);
    1407                 :             : 
    1408                 :        2059 :   g_mutex_unlock (&worker->write_lock);
    1409                 :             : 
    1410                 :        4118 :   while (pending_close_attempts != NULL)
    1411                 :             :     {
    1412                 :        2059 :       CloseData *close_data = pending_close_attempts->data;
    1413                 :             : 
    1414                 :        2059 :       pending_close_attempts = g_list_delete_link (pending_close_attempts,
    1415                 :             :                                                    pending_close_attempts);
    1416                 :             : 
    1417                 :        2059 :       if (close_data->task != NULL)
    1418                 :             :         {
    1419                 :         106 :           if (error != NULL)
    1420                 :           0 :             g_task_return_error (close_data->task, g_error_copy (error));
    1421                 :             :           else
    1422                 :         106 :             g_task_return_boolean (close_data->task, TRUE);
    1423                 :             :         }
    1424                 :             : 
    1425                 :        2059 :       close_data_free (close_data);
    1426                 :             :     }
    1427                 :             : 
    1428                 :        2059 :   g_clear_error (&error);
    1429                 :             : 
    1430                 :             :   /* all messages queued for sending are discarded */
    1431                 :        2059 :   g_queue_free_full (send_queue, (GDestroyNotify) message_to_write_data_free);
    1432                 :             :   /* all queued flushes fail */
    1433                 :        2059 :   error = g_error_new (G_IO_ERROR, G_IO_ERROR_CANCELLED,
    1434                 :             :                        _("Operation was cancelled"));
    1435                 :        2059 :   flush_data_list_complete (pending_flush_attempts, error);
    1436                 :        2059 :   g_list_free (pending_flush_attempts);
    1437                 :        2059 :   g_clear_error (&error);
    1438                 :             : 
    1439                 :        2059 :   _g_dbus_worker_unref (worker);
    1440                 :        2059 : }
    1441                 :             : 
    1442                 :             : /* called in private thread shared by all GDBusConnection instances
    1443                 :             :  *
    1444                 :             :  * write-lock is not held on entry
    1445                 :             :  * output_pending must be PENDING_NONE on entry
    1446                 :             :  */
    1447                 :             : static void
    1448                 :       24674 : continue_writing (GDBusWorker *worker)
    1449                 :             : {
    1450                 :             :   MessageToWriteData *data;
    1451                 :             :   FlushAsyncData *flush_async_data;
    1452                 :             : 
    1453                 :       24674 :  write_next:
    1454                 :             :   /* we mustn't try to write two things at once */
    1455                 :       24674 :   g_assert (worker->output_pending == PENDING_NONE);
    1456                 :             : 
    1457                 :       24674 :   g_mutex_lock (&worker->write_lock);
    1458                 :             : 
    1459                 :       24674 :   data = NULL;
    1460                 :       24674 :   flush_async_data = NULL;
    1461                 :             : 
    1462                 :             :   /* if we want to close the connection, that takes precedence */
    1463                 :       24674 :   if (worker->pending_close_attempts != NULL)
    1464                 :             :     {
    1465                 :        2242 :       GInputStream *input = g_io_stream_get_input_stream (worker->stream);
    1466                 :             : 
    1467                 :        2242 :       if (!g_input_stream_has_pending (input))
    1468                 :             :         {
    1469                 :        2060 :           worker->close_expected = TRUE;
    1470                 :        2060 :           worker->output_pending = PENDING_CLOSE;
    1471                 :             : 
    1472                 :        2060 :           g_io_stream_close_async (worker->stream, G_PRIORITY_DEFAULT,
    1473                 :             :                                    NULL, iostream_close_cb,
    1474                 :        2060 :                                    _g_dbus_worker_ref (worker));
    1475                 :             :         }
    1476                 :             :     }
    1477                 :             :   else
    1478                 :             :     {
    1479                 :       22432 :       flush_async_data = prepare_flush_unlocked (worker);
    1480                 :             : 
    1481                 :       22432 :       if (flush_async_data == NULL)
    1482                 :             :         {
    1483                 :       22324 :           data = g_queue_pop_head (worker->write_queue);
    1484                 :             : 
    1485                 :       22324 :           if (data != NULL)
    1486                 :       14513 :             worker->output_pending = PENDING_WRITE;
    1487                 :             :         }
    1488                 :             :     }
    1489                 :             : 
    1490                 :       24674 :   g_mutex_unlock (&worker->write_lock);
    1491                 :             : 
    1492                 :             :   /* Note that write_lock is only used for protecting the @write_queue
    1493                 :             :    * and @output_pending fields of the GDBusWorker struct ... which we
    1494                 :             :    * need to modify from arbitrary threads in _g_dbus_worker_send_message().
    1495                 :             :    *
    1496                 :             :    * Therefore, it's fine to drop it here when calling back into user
    1497                 :             :    * code and then writing the message out onto the GIOStream since this
    1498                 :             :    * function only runs on the worker thread.
    1499                 :             :    */
    1500                 :             : 
    1501                 :       24674 :   if (flush_async_data != NULL)
    1502                 :             :     {
    1503                 :         108 :       start_flush (flush_async_data);
    1504                 :         108 :       g_assert (data == NULL);
    1505                 :             :     }
    1506                 :       24566 :   else if (data != NULL)
    1507                 :             :     {
    1508                 :             :       GDBusMessage *old_message;
    1509                 :             :       guchar *new_blob;
    1510                 :             :       gsize new_blob_size;
    1511                 :             :       GError *error;
    1512                 :             : 
    1513                 :       14513 :       old_message = data->message;
    1514                 :       14513 :       data->message = _g_dbus_worker_emit_message_about_to_be_sent (worker, data->message);
    1515                 :       14513 :       if (data->message == old_message)
    1516                 :             :         {
    1517                 :             :           /* filters had no effect - do nothing */
    1518                 :             :         }
    1519                 :           1 :       else if (data->message == NULL)
    1520                 :             :         {
    1521                 :             :           /* filters dropped message */
    1522                 :           0 :           g_mutex_lock (&worker->write_lock);
    1523                 :           0 :           worker->output_pending = PENDING_NONE;
    1524                 :           0 :           g_mutex_unlock (&worker->write_lock);
    1525                 :           0 :           message_to_write_data_free (data);
    1526                 :           0 :           goto write_next;
    1527                 :             :         }
    1528                 :             :       else
    1529                 :             :         {
    1530                 :             :           /* filters altered the message -> re-encode */
    1531                 :           1 :           error = NULL;
    1532                 :           1 :           new_blob = g_dbus_message_to_blob (data->message,
    1533                 :             :                                              &new_blob_size,
    1534                 :             :                                              worker->capabilities,
    1535                 :             :                                              &error);
    1536                 :           1 :           if (new_blob == NULL)
    1537                 :             :             {
    1538                 :             :               /* if filter make the GDBusMessage unencodeable, just complain on stderr and send
    1539                 :             :                * the old message instead
    1540                 :             :                */
    1541                 :           0 :               g_warning ("Error encoding GDBusMessage with serial %d altered by filter function: %s",
    1542                 :             :                          g_dbus_message_get_serial (data->message),
    1543                 :             :                          error->message);
    1544                 :           0 :               g_error_free (error);
    1545                 :             :             }
    1546                 :             :           else
    1547                 :             :             {
    1548                 :           1 :               g_free (data->blob);
    1549                 :           1 :               data->blob = (gchar *) new_blob;
    1550                 :           1 :               data->blob_size = new_blob_size;
    1551                 :             :             }
    1552                 :             :         }
    1553                 :             : 
    1554                 :       14513 :       write_message_async (worker,
    1555                 :             :                            data,
    1556                 :             :                            write_message_cb,
    1557                 :             :                            data);  /* takes ownership of @data as user_data */
    1558                 :             :     }
    1559                 :       24674 : }
    1560                 :             : 
    1561                 :             : /* called in private thread shared by all GDBusConnection instances
    1562                 :             :  *
    1563                 :             :  * write-lock is not held on entry
    1564                 :             :  * output_pending may be anything
    1565                 :             :  */
    1566                 :             : static gboolean
    1567                 :       10478 : continue_writing_in_idle_cb (gpointer user_data)
    1568                 :             : {
    1569                 :       10478 :   GDBusWorker *worker = user_data;
    1570                 :             : 
    1571                 :             :   /* Because this is the worker thread, we can read this struct member
    1572                 :             :    * without holding the lock: no other thread ever modifies it.
    1573                 :             :    */
    1574                 :       10478 :   if (worker->output_pending == PENDING_NONE)
    1575                 :       10053 :     continue_writing (worker);
    1576                 :             : 
    1577                 :       10478 :   return FALSE;
    1578                 :             : }
    1579                 :             : 
    1580                 :             : /*
    1581                 :             :  * @write_data: (transfer full) (nullable):
    1582                 :             :  * @flush_data: (transfer full) (nullable):
    1583                 :             :  * @close_data: (transfer full) (nullable):
    1584                 :             :  *
    1585                 :             :  * Can be called from any thread
    1586                 :             :  *
    1587                 :             :  * write_lock is held on entry
    1588                 :             :  * output_pending may be anything
    1589                 :             :  */
    1590                 :             : static void
    1591                 :       18618 : schedule_writing_unlocked (GDBusWorker        *worker,
    1592                 :             :                            MessageToWriteData *write_data,
    1593                 :             :                            FlushData          *flush_data,
    1594                 :             :                            CloseData          *close_data)
    1595                 :             : {
    1596                 :       18618 :   if (write_data != NULL)
    1597                 :       14735 :     g_queue_push_tail (worker->write_queue, write_data);
    1598                 :             : 
    1599                 :       18618 :   if (flush_data != NULL)
    1600                 :         108 :     worker->write_pending_flushes = g_list_prepend (worker->write_pending_flushes, flush_data);
    1601                 :             : 
    1602                 :       18618 :   if (close_data != NULL)
    1603                 :        2061 :     worker->pending_close_attempts = g_list_prepend (worker->pending_close_attempts,
    1604                 :             :                                                      close_data);
    1605                 :             : 
    1606                 :             :   /* If we had output pending, the next bit of output will happen
    1607                 :             :    * automatically when it finishes, so we only need to do this
    1608                 :             :    * if nothing was pending.
    1609                 :             :    *
    1610                 :             :    * The idle callback will re-check that output_pending is still
    1611                 :             :    * PENDING_NONE, to guard against output starting before the idle.
    1612                 :             :    */
    1613                 :       18618 :   if (worker->output_pending == PENDING_NONE)
    1614                 :             :     {
    1615                 :             :       GSource *idle_source;
    1616                 :       10479 :       idle_source = g_idle_source_new ();
    1617                 :       10479 :       g_source_set_priority (idle_source, G_PRIORITY_DEFAULT);
    1618                 :       10479 :       g_source_set_callback (idle_source,
    1619                 :             :                              continue_writing_in_idle_cb,
    1620                 :       10479 :                              _g_dbus_worker_ref (worker),
    1621                 :             :                              (GDestroyNotify) _g_dbus_worker_unref);
    1622                 :       10479 :       g_source_set_static_name (idle_source, "[gio] continue_writing_in_idle_cb");
    1623                 :       10479 :       g_source_attach (idle_source, worker->shared_thread_data->context);
    1624                 :       10479 :       g_source_unref (idle_source);
    1625                 :             :     }
    1626                 :       18618 : }
    1627                 :             : 
    1628                 :             : static void
    1629                 :       57128 : schedule_pending_close (GDBusWorker *worker)
    1630                 :             : {
    1631                 :       57128 :   g_mutex_lock (&worker->write_lock);
    1632                 :       57128 :   if (worker->pending_close_attempts)
    1633                 :        1714 :     schedule_writing_unlocked (worker, NULL, NULL, NULL);
    1634                 :       57128 :   g_mutex_unlock (&worker->write_lock);
    1635                 :       57128 : }
    1636                 :             : 
    1637                 :             : /* ---------------------------------------------------------------------------------------------------- */
    1638                 :             : 
    1639                 :             : /* can be called from any thread - steals blob
    1640                 :             :  *
    1641                 :             :  * write_lock is not held on entry
    1642                 :             :  * output_pending may be anything
    1643                 :             :  */
    1644                 :             : void
    1645                 :       14735 : _g_dbus_worker_send_message (GDBusWorker    *worker,
    1646                 :             :                              GDBusMessage   *message,
    1647                 :             :                              gchar          *blob,
    1648                 :             :                              gsize           blob_len)
    1649                 :             : {
    1650                 :             :   MessageToWriteData *data;
    1651                 :             : 
    1652                 :       14735 :   g_return_if_fail (G_IS_DBUS_MESSAGE (message));
    1653                 :       14735 :   g_return_if_fail (blob != NULL);
    1654                 :       14735 :   g_return_if_fail (blob_len > 16);
    1655                 :             : 
    1656                 :       14735 :   data = g_slice_new0 (MessageToWriteData);
    1657                 :       14735 :   data->worker = _g_dbus_worker_ref (worker);
    1658                 :       14735 :   data->message = g_object_ref (message);
    1659                 :       14735 :   data->blob = blob; /* steal! */
    1660                 :       14735 :   data->blob_size = blob_len;
    1661                 :             : 
    1662                 :       14735 :   g_mutex_lock (&worker->write_lock);
    1663                 :       14735 :   schedule_writing_unlocked (worker, data, NULL, NULL);
    1664                 :       14735 :   g_mutex_unlock (&worker->write_lock);
    1665                 :             : }
    1666                 :             : 
    1667                 :             : /* ---------------------------------------------------------------------------------------------------- */
    1668                 :             : 
    1669                 :             : GDBusWorker *
    1670                 :        2210 : _g_dbus_worker_new (GIOStream                              *stream,
    1671                 :             :                     GDBusCapabilityFlags                    capabilities,
    1672                 :             :                     gboolean                                initially_frozen,
    1673                 :             :                     GDBusWorkerMessageReceivedCallback      message_received_callback,
    1674                 :             :                     GDBusWorkerMessageAboutToBeSentCallback message_about_to_be_sent_callback,
    1675                 :             :                     GDBusWorkerDisconnectedCallback         disconnected_callback,
    1676                 :             :                     gpointer                                user_data)
    1677                 :             : {
    1678                 :             :   GDBusWorker *worker;
    1679                 :             :   GSource *idle_source;
    1680                 :             : 
    1681                 :        2210 :   g_return_val_if_fail (G_IS_IO_STREAM (stream), NULL);
    1682                 :        2210 :   g_return_val_if_fail (message_received_callback != NULL, NULL);
    1683                 :        2210 :   g_return_val_if_fail (message_about_to_be_sent_callback != NULL, NULL);
    1684                 :        2210 :   g_return_val_if_fail (disconnected_callback != NULL, NULL);
    1685                 :             : 
    1686                 :        2210 :   worker = g_new0 (GDBusWorker, 1);
    1687                 :        2210 :   worker->ref_count = 1;
    1688                 :             : 
    1689                 :        2210 :   g_mutex_init (&worker->read_lock);
    1690                 :        2210 :   worker->message_received_callback = message_received_callback;
    1691                 :        2210 :   worker->message_about_to_be_sent_callback = message_about_to_be_sent_callback;
    1692                 :        2210 :   worker->disconnected_callback = disconnected_callback;
    1693                 :        2210 :   worker->user_data = user_data;
    1694                 :        2210 :   worker->stream = g_object_ref (stream);
    1695                 :        2210 :   worker->capabilities = capabilities;
    1696                 :        2210 :   worker->cancellable = g_cancellable_new ();
    1697                 :        2210 :   worker->output_pending = PENDING_NONE;
    1698                 :             : 
    1699                 :        2210 :   worker->frozen = initially_frozen;
    1700                 :        2210 :   worker->received_messages_while_frozen = g_queue_new ();
    1701                 :             : 
    1702                 :        2210 :   g_mutex_init (&worker->write_lock);
    1703                 :        2210 :   worker->write_queue = g_queue_new ();
    1704                 :             : 
    1705                 :        2210 :   if (G_IS_SOCKET_CONNECTION (worker->stream))
    1706                 :        1805 :     worker->socket = g_socket_connection_get_socket (G_SOCKET_CONNECTION (worker->stream));
    1707                 :             : 
    1708                 :        2210 :   worker->shared_thread_data = _g_dbus_shared_thread_ref ();
    1709                 :             : 
    1710                 :             :   /* begin reading */
    1711                 :        2210 :   idle_source = g_idle_source_new ();
    1712                 :        2210 :   g_source_set_priority (idle_source, G_PRIORITY_DEFAULT);
    1713                 :        2210 :   g_source_set_callback (idle_source,
    1714                 :             :                          _g_dbus_worker_do_initial_read,
    1715                 :        2210 :                          _g_dbus_worker_ref (worker),
    1716                 :             :                          (GDestroyNotify) _g_dbus_worker_unref);
    1717                 :        2210 :   g_source_set_static_name (idle_source, "[gio] _g_dbus_worker_do_initial_read");
    1718                 :        2210 :   g_source_attach (idle_source, worker->shared_thread_data->context);
    1719                 :        2210 :   g_source_unref (idle_source);
    1720                 :             : 
    1721                 :        2210 :   return worker;
    1722                 :             : }
    1723                 :             : 
    1724                 :             : /* ---------------------------------------------------------------------------------------------------- */
    1725                 :             : 
    1726                 :             : /* can be called from any thread
    1727                 :             :  *
    1728                 :             :  * write_lock is not held on entry
    1729                 :             :  * output_pending may be anything
    1730                 :             :  */
    1731                 :             : void
    1732                 :        2061 : _g_dbus_worker_close (GDBusWorker         *worker,
    1733                 :             :                       GTask               *task)
    1734                 :             : {
    1735                 :             :   CloseData *close_data;
    1736                 :             : 
    1737                 :        2061 :   close_data = g_slice_new0 (CloseData);
    1738                 :        2061 :   close_data->worker = _g_dbus_worker_ref (worker);
    1739                 :        2061 :   close_data->task = (task == NULL ? NULL : g_object_ref (task));
    1740                 :             : 
    1741                 :             :   /* Don't set worker->close_expected here - we're in the wrong thread.
    1742                 :             :    * It'll be set before the actual close happens.
    1743                 :             :    */
    1744                 :        2061 :   g_cancellable_cancel (worker->cancellable);
    1745                 :        2061 :   g_mutex_lock (&worker->write_lock);
    1746                 :        2061 :   schedule_writing_unlocked (worker, NULL, NULL, close_data);
    1747                 :        2061 :   g_mutex_unlock (&worker->write_lock);
    1748                 :        2061 : }
    1749                 :             : 
    1750                 :             : /* This can be called from any thread - frees worker. Note that
    1751                 :             :  * callbacks might still happen if called from another thread than the
    1752                 :             :  * worker - use your own synchronization primitive in the callbacks.
    1753                 :             :  *
    1754                 :             :  * write_lock is not held on entry
    1755                 :             :  * output_pending may be anything
    1756                 :             :  */
    1757                 :             : void
    1758                 :        1955 : _g_dbus_worker_stop (GDBusWorker *worker)
    1759                 :             : {
    1760                 :        1955 :   g_atomic_int_set (&worker->stopped, TRUE);
    1761                 :             : 
    1762                 :             :   /* Cancel any pending operations and schedule a close of the underlying I/O
    1763                 :             :    * stream in the worker thread
    1764                 :             :    */
    1765                 :        1955 :   _g_dbus_worker_close (worker, NULL);
    1766                 :             : 
    1767                 :             :   /* _g_dbus_worker_close holds a ref until after an idle in the worker
    1768                 :             :    * thread has run, so we no longer need to unref in an idle like in
    1769                 :             :    * commit 322e25b535
    1770                 :             :    */
    1771                 :        1955 :   _g_dbus_worker_unref (worker);
    1772                 :        1955 : }
    1773                 :             : 
    1774                 :             : /* ---------------------------------------------------------------------------------------------------- */
    1775                 :             : 
    1776                 :             : /* can be called from any thread (except the worker thread) - blocks
    1777                 :             :  * calling thread until all queued outgoing messages are written and
    1778                 :             :  * the transport has been flushed
    1779                 :             :  *
    1780                 :             :  * write_lock is not held on entry
    1781                 :             :  * output_pending may be anything
    1782                 :             :  */
    1783                 :             : gboolean
    1784                 :         110 : _g_dbus_worker_flush_sync (GDBusWorker    *worker,
    1785                 :             :                            GCancellable   *cancellable,
    1786                 :             :                            GError        **error)
    1787                 :             : {
    1788                 :             :   gboolean ret;
    1789                 :             :   FlushData *data;
    1790                 :             :   guint64 pending_writes;
    1791                 :             : 
    1792                 :         110 :   data = NULL;
    1793                 :         110 :   ret = TRUE;
    1794                 :             : 
    1795                 :         110 :   g_mutex_lock (&worker->write_lock);
    1796                 :             : 
    1797                 :             :   /* if the queue is empty, no write is in-flight and we haven't written
    1798                 :             :    * anything since the last flush, then there's nothing to wait for
    1799                 :             :    */
    1800                 :         110 :   pending_writes = g_queue_get_length (worker->write_queue);
    1801                 :             : 
    1802                 :             :   /* if a write is in-flight, we shouldn't be satisfied until the first
    1803                 :             :    * flush operation that follows it
    1804                 :             :    */
    1805                 :         110 :   if (worker->output_pending == PENDING_WRITE)
    1806                 :          15 :     pending_writes += 1;
    1807                 :             : 
    1808                 :         110 :   if (pending_writes > 0 ||
    1809                 :          42 :       worker->write_num_messages_written != worker->write_num_messages_flushed)
    1810                 :             :     {
    1811                 :         108 :       data = g_new0 (FlushData, 1);
    1812                 :         108 :       g_mutex_init (&data->mutex);
    1813                 :         108 :       g_cond_init (&data->cond);
    1814                 :         108 :       data->number_to_wait_for = worker->write_num_messages_written + pending_writes;
    1815                 :         108 :       data->finished = FALSE;
    1816                 :         108 :       g_mutex_lock (&data->mutex);
    1817                 :             : 
    1818                 :         108 :       schedule_writing_unlocked (worker, NULL, data, NULL);
    1819                 :             :     }
    1820                 :         110 :   g_mutex_unlock (&worker->write_lock);
    1821                 :             : 
    1822                 :         110 :   if (data != NULL)
    1823                 :             :     {
    1824                 :             :       /* Wait for flush operations to finish. */
    1825                 :         216 :       while (!data->finished)
    1826                 :             :         {
    1827                 :         108 :           g_cond_wait (&data->cond, &data->mutex);
    1828                 :             :         }
    1829                 :             : 
    1830                 :         108 :       g_mutex_unlock (&data->mutex);
    1831                 :         108 :       g_cond_clear (&data->cond);
    1832                 :         108 :       g_mutex_clear (&data->mutex);
    1833                 :         108 :       if (data->error != NULL)
    1834                 :             :         {
    1835                 :           0 :           ret = FALSE;
    1836                 :           0 :           g_propagate_error (error, data->error);
    1837                 :             :         }
    1838                 :         108 :       g_free (data);
    1839                 :             :     }
    1840                 :             : 
    1841                 :         110 :   return ret;
    1842                 :             : }
    1843                 :             : 
    1844                 :             : /* ---------------------------------------------------------------------------------------------------- */
    1845                 :             : 
    1846                 :             : #define G_DBUS_DEBUG_AUTHENTICATION (1<<0)
    1847                 :             : #define G_DBUS_DEBUG_TRANSPORT      (1<<1)
    1848                 :             : #define G_DBUS_DEBUG_MESSAGE        (1<<2)
    1849                 :             : #define G_DBUS_DEBUG_PAYLOAD        (1<<3)
    1850                 :             : #define G_DBUS_DEBUG_CALL           (1<<4)
    1851                 :             : #define G_DBUS_DEBUG_SIGNAL         (1<<5)
    1852                 :             : #define G_DBUS_DEBUG_INCOMING       (1<<6)
    1853                 :             : #define G_DBUS_DEBUG_RETURN         (1<<7)
    1854                 :             : #define G_DBUS_DEBUG_EMISSION       (1<<8)
    1855                 :             : #define G_DBUS_DEBUG_ADDRESS        (1<<9)
    1856                 :             : #define G_DBUS_DEBUG_PROXY          (1<<10)
    1857                 :             : 
    1858                 :             : static gint _gdbus_debug_flags = 0;
    1859                 :             : 
    1860                 :             : gboolean
    1861                 :       36394 : _g_dbus_debug_authentication (void)
    1862                 :             : {
    1863                 :       36394 :   _g_dbus_initialize ();
    1864                 :       36394 :   return (_gdbus_debug_flags & G_DBUS_DEBUG_AUTHENTICATION) != 0;
    1865                 :             : }
    1866                 :             : 
    1867                 :             : gboolean
    1868                 :       70100 : _g_dbus_debug_transport (void)
    1869                 :             : {
    1870                 :       70100 :   _g_dbus_initialize ();
    1871                 :       70100 :   return (_gdbus_debug_flags & G_DBUS_DEBUG_TRANSPORT) != 0;
    1872                 :             : }
    1873                 :             : 
    1874                 :             : gboolean
    1875                 :       41931 : _g_dbus_debug_message (void)
    1876                 :             : {
    1877                 :       41931 :   _g_dbus_initialize ();
    1878                 :       41931 :   return (_gdbus_debug_flags & G_DBUS_DEBUG_MESSAGE) != 0;
    1879                 :             : }
    1880                 :             : 
    1881                 :             : gboolean
    1882                 :           0 : _g_dbus_debug_payload (void)
    1883                 :             : {
    1884                 :           0 :   _g_dbus_initialize ();
    1885                 :           0 :   return (_gdbus_debug_flags & G_DBUS_DEBUG_PAYLOAD) != 0;
    1886                 :             : }
    1887                 :             : 
    1888                 :             : gboolean
    1889                 :       17198 : _g_dbus_debug_call (void)
    1890                 :             : {
    1891                 :       17198 :   _g_dbus_initialize ();
    1892                 :       17198 :   return (_gdbus_debug_flags & G_DBUS_DEBUG_CALL) != 0;
    1893                 :             : }
    1894                 :             : 
    1895                 :             : gboolean
    1896                 :       13827 : _g_dbus_debug_signal (void)
    1897                 :             : {
    1898                 :       13827 :   _g_dbus_initialize ();
    1899                 :       13827 :   return (_gdbus_debug_flags & G_DBUS_DEBUG_SIGNAL) != 0;
    1900                 :             : }
    1901                 :             : 
    1902                 :             : gboolean
    1903                 :        1566 : _g_dbus_debug_incoming (void)
    1904                 :             : {
    1905                 :        1566 :   _g_dbus_initialize ();
    1906                 :        1566 :   return (_gdbus_debug_flags & G_DBUS_DEBUG_INCOMING) != 0;
    1907                 :             : }
    1908                 :             : 
    1909                 :             : gboolean
    1910                 :         578 : _g_dbus_debug_return (void)
    1911                 :             : {
    1912                 :         578 :   _g_dbus_initialize ();
    1913                 :         578 :   return (_gdbus_debug_flags & G_DBUS_DEBUG_RETURN) != 0;
    1914                 :             : }
    1915                 :             : 
    1916                 :             : gboolean
    1917                 :         710 : _g_dbus_debug_emission (void)
    1918                 :             : {
    1919                 :         710 :   _g_dbus_initialize ();
    1920                 :         710 :   return (_gdbus_debug_flags & G_DBUS_DEBUG_EMISSION) != 0;
    1921                 :             : }
    1922                 :             : 
    1923                 :             : gboolean
    1924                 :        3339 : _g_dbus_debug_address (void)
    1925                 :             : {
    1926                 :        3339 :   _g_dbus_initialize ();
    1927                 :        3339 :   return (_gdbus_debug_flags & G_DBUS_DEBUG_ADDRESS) != 0;
    1928                 :             : }
    1929                 :             : 
    1930                 :             : gboolean
    1931                 :           2 : _g_dbus_debug_proxy (void)
    1932                 :             : {
    1933                 :           2 :   _g_dbus_initialize ();
    1934                 :           2 :   return (_gdbus_debug_flags & G_DBUS_DEBUG_PROXY) != 0;
    1935                 :             : }
    1936                 :             : 
    1937                 :             : G_LOCK_DEFINE_STATIC (print_lock);
    1938                 :             : 
    1939                 :             : void
    1940                 :           0 : _g_dbus_debug_print_lock (void)
    1941                 :             : {
    1942                 :           0 :   G_LOCK (print_lock);
    1943                 :           0 : }
    1944                 :             : 
    1945                 :             : void
    1946                 :           0 : _g_dbus_debug_print_unlock (void)
    1947                 :             : {
    1948                 :           0 :   G_UNLOCK (print_lock);
    1949                 :           0 : }
    1950                 :             : 
    1951                 :             : /**
    1952                 :             :  * _g_dbus_initialize:
    1953                 :             :  *
    1954                 :             :  * Does various one-time init things such as
    1955                 :             :  *
    1956                 :             :  *  - registering the G_DBUS_ERROR error domain
    1957                 :             :  *  - parses the G_DBUS_DEBUG environment variable
    1958                 :             :  */
    1959                 :             : void
    1960                 :      189221 : _g_dbus_initialize (void)
    1961                 :             : {
    1962                 :             :   static gsize initialized = 0;
    1963                 :             : 
    1964                 :      189221 :   if (g_once_init_enter (&initialized))
    1965                 :             :     {
    1966                 :             :       const gchar *debug;
    1967                 :             : 
    1968                 :             :       /* Ensure the domain is registered. */
    1969                 :         123 :       g_dbus_error_quark ();
    1970                 :             : 
    1971                 :         123 :       debug = g_getenv ("G_DBUS_DEBUG");
    1972                 :         123 :       if (debug != NULL)
    1973                 :             :         {
    1974                 :           0 :           const GDebugKey keys[] = {
    1975                 :             :             { "authentication", G_DBUS_DEBUG_AUTHENTICATION },
    1976                 :             :             { "transport",      G_DBUS_DEBUG_TRANSPORT      },
    1977                 :             :             { "message",        G_DBUS_DEBUG_MESSAGE        },
    1978                 :             :             { "payload",        G_DBUS_DEBUG_PAYLOAD        },
    1979                 :             :             { "call",           G_DBUS_DEBUG_CALL           },
    1980                 :             :             { "signal",         G_DBUS_DEBUG_SIGNAL         },
    1981                 :             :             { "incoming",       G_DBUS_DEBUG_INCOMING       },
    1982                 :             :             { "return",         G_DBUS_DEBUG_RETURN         },
    1983                 :             :             { "emission",       G_DBUS_DEBUG_EMISSION       },
    1984                 :             :             { "address",        G_DBUS_DEBUG_ADDRESS        },
    1985                 :             :             { "proxy",          G_DBUS_DEBUG_PROXY          }
    1986                 :             :           };
    1987                 :             : 
    1988                 :           0 :           _gdbus_debug_flags = g_parse_debug_string (debug, keys, G_N_ELEMENTS (keys));
    1989                 :           0 :           if (_gdbus_debug_flags & G_DBUS_DEBUG_PAYLOAD)
    1990                 :           0 :             _gdbus_debug_flags |= G_DBUS_DEBUG_MESSAGE;
    1991                 :             :         }
    1992                 :             : 
    1993                 :             :       /* Work-around for https://bugzilla.gnome.org/show_bug.cgi?id=627724 */
    1994                 :         123 :       ensure_required_types ();
    1995                 :             : 
    1996                 :         123 :       g_once_init_leave (&initialized, 1);
    1997                 :             :     }
    1998                 :      189221 : }
    1999                 :             : 
    2000                 :             : /* ---------------------------------------------------------------------------------------------------- */
    2001                 :             : 
    2002                 :             : GVariantType *
    2003                 :        1558 : _g_dbus_compute_complete_signature (GDBusArgInfo **args)
    2004                 :             : {
    2005                 :             :   const GVariantType *arg_types[256];
    2006                 :             :   guint n;
    2007                 :             : 
    2008                 :        1558 :   if (args)
    2009                 :        3127 :     for (n = 0; args[n] != NULL; n++)
    2010                 :             :       {
    2011                 :             :         /* DBus places a hard limit of 255 on signature length.
    2012                 :             :          * therefore number of args must be less than 256.
    2013                 :             :          */
    2014                 :        1670 :         g_assert (n < 256);
    2015                 :             : 
    2016                 :        1670 :         arg_types[n] = G_VARIANT_TYPE (args[n]->signature);
    2017                 :             : 
    2018                 :        1670 :         if G_UNLIKELY (arg_types[n] == NULL)
    2019                 :           0 :           return NULL;
    2020                 :             :       }
    2021                 :             :   else
    2022                 :         101 :     n = 0;
    2023                 :             : 
    2024                 :        1558 :   return g_variant_type_new_tuple (arg_types, n);
    2025                 :             : }
    2026                 :             : 
    2027                 :             : /* ---------------------------------------------------------------------------------------------------- */
    2028                 :             : 
    2029                 :             : #ifdef G_OS_WIN32
    2030                 :             : 
    2031                 :             : #define DBUS_DAEMON_ADDRESS_INFO L"DBusDaemonAddressInfo"
    2032                 :             : #define DBUS_DAEMON_MUTEX L"DBusDaemonMutex"
    2033                 :             : #define UNIQUE_DBUS_INIT_MUTEX L"UniqueDBusInitMutex"
    2034                 :             : #define DBUS_AUTOLAUNCH_MUTEX L"DBusAutolaunchMutex"
    2035                 :             : 
    2036                 :             : static void
    2037                 :             : release_mutex (HANDLE mutex)
    2038                 :             : {
    2039                 :             :   ReleaseMutex (mutex);
    2040                 :             :   CloseHandle (mutex);
    2041                 :             : }
    2042                 :             : 
    2043                 :             : static HANDLE
    2044                 :             : acquire_mutex (const wchar_t *mutexname)
    2045                 :             : {
    2046                 :             :   HANDLE mutex;
    2047                 :             :   DWORD res;
    2048                 :             : 
    2049                 :             :   mutex = CreateMutex (NULL, FALSE, mutexname);
    2050                 :             :   if (!mutex)
    2051                 :             :     return 0;
    2052                 :             : 
    2053                 :             :   res = WaitForSingleObject (mutex, INFINITE);
    2054                 :             :   switch (res)
    2055                 :             :     {
    2056                 :             :     case WAIT_ABANDONED:
    2057                 :             :       release_mutex (mutex);
    2058                 :             :       return 0;
    2059                 :             :     case WAIT_FAILED:
    2060                 :             :     case WAIT_TIMEOUT:
    2061                 :             :       return 0;
    2062                 :             :     }
    2063                 :             : 
    2064                 :             :   return mutex;
    2065                 :             : }
    2066                 :             : 
    2067                 :             : static gboolean
    2068                 :             : is_mutex_owned (const wchar_t *mutexname)
    2069                 :             : {
    2070                 :             :   HANDLE mutex;
    2071                 :             :   gboolean res = FALSE;
    2072                 :             : 
    2073                 :             :   mutex = CreateMutex (NULL, FALSE, mutexname);
    2074                 :             :   if (WaitForSingleObject (mutex, 10) == WAIT_TIMEOUT)
    2075                 :             :     res = TRUE;
    2076                 :             :   else
    2077                 :             :     ReleaseMutex (mutex);
    2078                 :             :   CloseHandle (mutex);
    2079                 :             : 
    2080                 :             :   return res;
    2081                 :             : }
    2082                 :             : 
    2083                 :             : static char *
    2084                 :             : read_shm (const wchar_t *shm_name)
    2085                 :             : {
    2086                 :             :   HANDLE shared_mem;
    2087                 :             :   char *shared_data;
    2088                 :             :   char *res;
    2089                 :             :   int i;
    2090                 :             : 
    2091                 :             :   res = NULL;
    2092                 :             : 
    2093                 :             :   for (i = 0; i < 20; i++)
    2094                 :             :     {
    2095                 :             :       shared_mem = OpenFileMapping (FILE_MAP_READ, FALSE, shm_name);
    2096                 :             :       if (shared_mem != 0)
    2097                 :             :         break;
    2098                 :             :       Sleep (100);
    2099                 :             :     }
    2100                 :             : 
    2101                 :             :   if (shared_mem != 0)
    2102                 :             :     {
    2103                 :             :       shared_data = MapViewOfFile (shared_mem, FILE_MAP_READ, 0, 0, 0);
    2104                 :             :       /* It looks that a race is possible here:
    2105                 :             :        * if the dbus process already created mapping but didn't fill it
    2106                 :             :        * the code below may read incorrect address.
    2107                 :             :        * Also this is a bit complicated by the fact that
    2108                 :             :        * any change in the "synchronization contract" between processes
    2109                 :             :        * should be accompanied with renaming all of used win32 named objects:
    2110                 :             :        * otherwise libgio-2.0-0.dll of different versions shipped with
    2111                 :             :        * different apps may break each other due to protocol difference.
    2112                 :             :        */
    2113                 :             :       if (shared_data != NULL)
    2114                 :             :         {
    2115                 :             :           res = g_strdup (shared_data);
    2116                 :             :           UnmapViewOfFile (shared_data);
    2117                 :             :         }
    2118                 :             :       CloseHandle (shared_mem);
    2119                 :             :     }
    2120                 :             : 
    2121                 :             :   return res;
    2122                 :             : }
    2123                 :             : 
    2124                 :             : static HANDLE
    2125                 :             : set_shm (const wchar_t *shm_name, const char *value)
    2126                 :             : {
    2127                 :             :   HANDLE shared_mem;
    2128                 :             :   char *shared_data;
    2129                 :             : 
    2130                 :             :   shared_mem = CreateFileMapping (INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
    2131                 :             :                                   0, strlen (value) + 1, shm_name);
    2132                 :             :   if (shared_mem == 0)
    2133                 :             :     return 0;
    2134                 :             : 
    2135                 :             :   shared_data = MapViewOfFile (shared_mem, FILE_MAP_WRITE, 0, 0, 0 );
    2136                 :             :   if (shared_data == NULL)
    2137                 :             :     return 0;
    2138                 :             : 
    2139                 :             :   strcpy (shared_data, value);
    2140                 :             : 
    2141                 :             :   UnmapViewOfFile (shared_data);
    2142                 :             : 
    2143                 :             :   return shared_mem;
    2144                 :             : }
    2145                 :             : 
    2146                 :             : /* These keep state between publish_session_bus and unpublish_session_bus */
    2147                 :             : static HANDLE published_daemon_mutex;
    2148                 :             : static HANDLE published_shared_mem;
    2149                 :             : 
    2150                 :             : static gboolean
    2151                 :             : publish_session_bus (const char *address)
    2152                 :             : {
    2153                 :             :   HANDLE init_mutex;
    2154                 :             : 
    2155                 :             :   init_mutex = acquire_mutex (UNIQUE_DBUS_INIT_MUTEX);
    2156                 :             : 
    2157                 :             :   published_daemon_mutex = CreateMutex (NULL, FALSE, DBUS_DAEMON_MUTEX);
    2158                 :             :   if (WaitForSingleObject (published_daemon_mutex, 10 ) != WAIT_OBJECT_0)
    2159                 :             :     {
    2160                 :             :       release_mutex (init_mutex);
    2161                 :             :       CloseHandle (published_daemon_mutex);
    2162                 :             :       published_daemon_mutex = NULL;
    2163                 :             :       return FALSE;
    2164                 :             :     }
    2165                 :             : 
    2166                 :             :   published_shared_mem = set_shm (DBUS_DAEMON_ADDRESS_INFO, address);
    2167                 :             :   if (!published_shared_mem)
    2168                 :             :     {
    2169                 :             :       release_mutex (init_mutex);
    2170                 :             :       CloseHandle (published_daemon_mutex);
    2171                 :             :       published_daemon_mutex = NULL;
    2172                 :             :       return FALSE;
    2173                 :             :     }
    2174                 :             : 
    2175                 :             :   release_mutex (init_mutex);
    2176                 :             :   return TRUE;
    2177                 :             : }
    2178                 :             : 
    2179                 :             : static void
    2180                 :             : unpublish_session_bus (void)
    2181                 :             : {
    2182                 :             :   HANDLE init_mutex;
    2183                 :             : 
    2184                 :             :   init_mutex = acquire_mutex (UNIQUE_DBUS_INIT_MUTEX);
    2185                 :             : 
    2186                 :             :   CloseHandle (published_shared_mem);
    2187                 :             :   published_shared_mem = NULL;
    2188                 :             : 
    2189                 :             :   release_mutex (published_daemon_mutex);
    2190                 :             :   published_daemon_mutex = NULL;
    2191                 :             : 
    2192                 :             :   release_mutex (init_mutex);
    2193                 :             : }
    2194                 :             : 
    2195                 :             : static void
    2196                 :             : wait_console_window (void)
    2197                 :             : {
    2198                 :             :   FILE *console = fopen ("CONOUT$", "w");
    2199                 :             : 
    2200                 :             :   SetConsoleTitleW (L"gdbus-daemon output. Type any character to close this window.");
    2201                 :             :   fprintf (console, _("(Type any character to close this window)\n"));
    2202                 :             :   fflush (console);
    2203                 :             :   _getch ();
    2204                 :             : }
    2205                 :             : 
    2206                 :             : static void
    2207                 :             : open_console_window (void)
    2208                 :             : {
    2209                 :             :   if (((HANDLE) _get_osfhandle (fileno (stdout)) == INVALID_HANDLE_VALUE ||
    2210                 :             :        (HANDLE) _get_osfhandle (fileno (stderr)) == INVALID_HANDLE_VALUE) && AllocConsole ())
    2211                 :             :     {
    2212                 :             :       if ((HANDLE) _get_osfhandle (fileno (stdout)) == INVALID_HANDLE_VALUE)
    2213                 :             :         freopen ("CONOUT$", "w", stdout);
    2214                 :             : 
    2215                 :             :       if ((HANDLE) _get_osfhandle (fileno (stderr)) == INVALID_HANDLE_VALUE)
    2216                 :             :         freopen ("CONOUT$", "w", stderr);
    2217                 :             : 
    2218                 :             :       SetConsoleTitleW (L"gdbus-daemon debug output.");
    2219                 :             : 
    2220                 :             :       atexit (wait_console_window);
    2221                 :             :     }
    2222                 :             : }
    2223                 :             : 
    2224                 :             : static void
    2225                 :             : idle_timeout_cb (GDBusDaemon *daemon, gpointer user_data)
    2226                 :             : {
    2227                 :             :   GMainLoop *loop = user_data;
    2228                 :             :   g_main_loop_quit (loop);
    2229                 :             : }
    2230                 :             : 
    2231                 :             : /* Satisfies STARTF_FORCEONFEEDBACK */
    2232                 :             : static void
    2233                 :             : turn_off_the_starting_cursor (void)
    2234                 :             : {
    2235                 :             :   MSG msg;
    2236                 :             :   BOOL bRet;
    2237                 :             : 
    2238                 :             :   PostQuitMessage (0);
    2239                 :             : 
    2240                 :             :   while ((bRet = GetMessage (&msg, 0, 0, 0)) != 0)
    2241                 :             :     {
    2242                 :             :       if (bRet == -1)
    2243                 :             :         continue;
    2244                 :             : 
    2245                 :             :       TranslateMessage (&msg);
    2246                 :             :       DispatchMessage (&msg);
    2247                 :             :     }
    2248                 :             : }
    2249                 :             : 
    2250                 :             : void __stdcall
    2251                 :             : g_win32_run_session_bus (void* hwnd, void* hinst, const char* cmdline, int cmdshow)
    2252                 :             : {
    2253                 :             :   GDBusDaemon *daemon;
    2254                 :             :   GMainLoop *loop;
    2255                 :             :   const char *address;
    2256                 :             :   GError *error = NULL;
    2257                 :             : 
    2258                 :             :   turn_off_the_starting_cursor ();
    2259                 :             : 
    2260                 :             :   if (g_getenv ("GDBUS_DAEMON_DEBUG") != NULL)
    2261                 :             :     open_console_window ();
    2262                 :             : 
    2263                 :             :   address = "nonce-tcp:";
    2264                 :             :   daemon = _g_dbus_daemon_new (address, NULL, &error);
    2265                 :             :   if (daemon == NULL)
    2266                 :             :     {
    2267                 :             :       g_printerr ("Can't init bus: %s\n", error->message);
    2268                 :             :       g_error_free (error);
    2269                 :             :       return;
    2270                 :             :     }
    2271                 :             : 
    2272                 :             :   loop = g_main_loop_new (NULL, FALSE);
    2273                 :             : 
    2274                 :             :   /* There is a subtle detail with "idle-timeout" signal of dbus daemon:
    2275                 :             :    * It is fired on idle after last client disconnection,
    2276                 :             :    * but (at least with glib 2.59.1) it is NEVER fired
    2277                 :             :    * if no clients connect to daemon at all.
    2278                 :             :    * This may lead to infinite run of this daemon process.
    2279                 :             :    */
    2280                 :             :   g_signal_connect (daemon, "idle-timeout", G_CALLBACK (idle_timeout_cb), loop);
    2281                 :             : 
    2282                 :             :   if (publish_session_bus (_g_dbus_daemon_get_address (daemon)))
    2283                 :             :     {
    2284                 :             :       g_main_loop_run (loop);
    2285                 :             : 
    2286                 :             :       unpublish_session_bus ();
    2287                 :             :     }
    2288                 :             : 
    2289                 :             :   g_main_loop_unref (loop);
    2290                 :             :   g_object_unref (daemon);
    2291                 :             : }
    2292                 :             : 
    2293                 :             : static gboolean autolaunch_binary_absent = FALSE;
    2294                 :             : 
    2295                 :             : static wchar_t *
    2296                 :             : find_dbus_process_path (void)
    2297                 :             : {
    2298                 :             :   wchar_t *dbus_path;
    2299                 :             :   gchar *exe_path = GLIB_PRIVATE_CALL (g_win32_find_helper_executable_path) ("gdbus.exe", _g_io_win32_get_module ());
    2300                 :             :   dbus_path = g_utf8_to_utf16 (exe_path, -1, NULL, NULL, NULL);
    2301                 :             :   g_free (exe_path);
    2302                 :             : 
    2303                 :             :   if (dbus_path == NULL)
    2304                 :             :     return NULL;
    2305                 :             : 
    2306                 :             :   if (GetFileAttributesW (dbus_path) == INVALID_FILE_ATTRIBUTES)
    2307                 :             :     {
    2308                 :             :       g_free (dbus_path);
    2309                 :             :       return NULL;
    2310                 :             :     }
    2311                 :             : 
    2312                 :             :   return dbus_path;
    2313                 :             : }
    2314                 :             : 
    2315                 :             : gchar *
    2316                 :             : _g_dbus_win32_get_session_address_dbus_launch (GError **error)
    2317                 :             : {
    2318                 :             :   HANDLE autolaunch_mutex, init_mutex;
    2319                 :             :   char *address = NULL;
    2320                 :             : 
    2321                 :             :   autolaunch_mutex = acquire_mutex (DBUS_AUTOLAUNCH_MUTEX);
    2322                 :             : 
    2323                 :             :   init_mutex = acquire_mutex (UNIQUE_DBUS_INIT_MUTEX);
    2324                 :             : 
    2325                 :             :   if (is_mutex_owned (DBUS_DAEMON_MUTEX))
    2326                 :             :     address = read_shm (DBUS_DAEMON_ADDRESS_INFO);
    2327                 :             : 
    2328                 :             :   release_mutex (init_mutex);
    2329                 :             : 
    2330                 :             :   if (address == NULL && !autolaunch_binary_absent)
    2331                 :             :     {
    2332                 :             :       wchar_t *dbus_path = find_dbus_process_path ();
    2333                 :             :       if (dbus_path == NULL)
    2334                 :             :         {
    2335                 :             :           /* warning won't be raised another time
    2336                 :             :            * since autolaunch_binary_absent would be already set.
    2337                 :             :            */
    2338                 :             :           autolaunch_binary_absent = TRUE;
    2339                 :             :           g_warning ("win32 session dbus binary not found");
    2340                 :             :         }
    2341                 :             :       else
    2342                 :             :         {
    2343                 :             :           PROCESS_INFORMATION pi = { 0 };
    2344                 :             :           STARTUPINFOW si = { 0 };
    2345                 :             :           BOOL res = FALSE;
    2346                 :             :           wchar_t args[MAX_PATH * 2 + 100] = { 0 };
    2347                 :             :           wchar_t working_dir[MAX_PATH + 2] = { 0 };
    2348                 :             :           wchar_t *p;
    2349                 :             : 
    2350                 :             :           wcscpy (working_dir, dbus_path);
    2351                 :             :           p = wcsrchr (working_dir, L'\\');
    2352                 :             :           if (p != NULL)
    2353                 :             :             *p = L'\0';
    2354                 :             : 
    2355                 :             :           wcscpy (args, L"\"");
    2356                 :             :           wcscat (args, dbus_path);
    2357                 :             :           wcscat (args, L"\" ");
    2358                 :             : #define _L_PREFIX_FOR_EXPANDED(arg) L##arg
    2359                 :             : #define _L_PREFIX(arg) _L_PREFIX_FOR_EXPANDED (arg)
    2360                 :             :           wcscat (args, _L_PREFIX (_GDBUS_ARG_WIN32_RUN_SESSION_BUS));
    2361                 :             : #undef _L_PREFIX
    2362                 :             : #undef _L_PREFIX_FOR_EXPANDED
    2363                 :             : 
    2364                 :             :           res = CreateProcessW (dbus_path, args,
    2365                 :             :                                 0, 0, FALSE,
    2366                 :             :                                 NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW | DETACHED_PROCESS,
    2367                 :             :                                 0, working_dir,
    2368                 :             :                                 &si, &pi);
    2369                 :             : 
    2370                 :             :           if (res)
    2371                 :             :             {
    2372                 :             :               address = read_shm (DBUS_DAEMON_ADDRESS_INFO);
    2373                 :             :               if (address == NULL)
    2374                 :             :                 g_warning ("%S dbus binary failed to launch bus, maybe incompatible version", dbus_path);
    2375                 :             :             }
    2376                 :             : 
    2377                 :             :           g_free (dbus_path);
    2378                 :             :         }
    2379                 :             :     }
    2380                 :             : 
    2381                 :             :   release_mutex (autolaunch_mutex);
    2382                 :             : 
    2383                 :             :   if (address == NULL)
    2384                 :             :     g_set_error (error,
    2385                 :             :                  G_IO_ERROR,
    2386                 :             :                  G_IO_ERROR_FAILED,
    2387                 :             :                  _("Session dbus not running, and autolaunch failed"));
    2388                 :             : 
    2389                 :             :   return address;
    2390                 :             : }
    2391                 :             : 
    2392                 :             : #endif
    2393                 :             : 
    2394                 :             : /* ---------------------------------------------------------------------------------------------------- */
    2395                 :             : 
    2396                 :             : gchar *
    2397                 :          61 : _g_dbus_get_machine_id (GError **error)
    2398                 :             : {
    2399                 :             : #ifdef G_OS_WIN32
    2400                 :             :   HW_PROFILE_INFO info;
    2401                 :             :   char *guid, *src, *dest, *res;
    2402                 :             :   int i;
    2403                 :             : 
    2404                 :             :   if (!GetCurrentHwProfile (&info))
    2405                 :             :     {
    2406                 :             :       char *message = g_win32_error_message (GetLastError ());
    2407                 :             :       g_set_error (error,
    2408                 :             :                    G_IO_ERROR,
    2409                 :             :                    G_IO_ERROR_FAILED,
    2410                 :             :                    _("Unable to get Hardware profile: %s"), message);
    2411                 :             :       g_free (message);
    2412                 :             :       return NULL;
    2413                 :             :     }
    2414                 :             : 
    2415                 :             :   if (!(guid = g_utf16_to_utf8 (info.szHwProfileGuid, -1, NULL, NULL, NULL)))
    2416                 :             :     return NULL;
    2417                 :             : 
    2418                 :             :   /* Guid is of the form: {12340001-4980-1920-6788-123456789012} */
    2419                 :             :   src = guid;
    2420                 :             : 
    2421                 :             :   res = g_malloc (32+1);
    2422                 :             :   dest = res;
    2423                 :             : 
    2424                 :             :   src++; /* Skip { */
    2425                 :             :   for (i = 0; i < 8; i++)
    2426                 :             :     *dest++ = *src++;
    2427                 :             :   src++; /* Skip - */
    2428                 :             :   for (i = 0; i < 4; i++)
    2429                 :             :     *dest++ = *src++;
    2430                 :             :   src++; /* Skip - */
    2431                 :             :   for (i = 0; i < 4; i++)
    2432                 :             :     *dest++ = *src++;
    2433                 :             :   src++; /* Skip - */
    2434                 :             :   for (i = 0; i < 4; i++)
    2435                 :             :     *dest++ = *src++;
    2436                 :             :   src++; /* Skip - */
    2437                 :             :   for (i = 0; i < 12; i++)
    2438                 :             :     *dest++ = *src++;
    2439                 :             :   *dest = 0;
    2440                 :             : 
    2441                 :             :   g_free (guid);
    2442                 :             : 
    2443                 :             :   return res;
    2444                 :             : #else
    2445                 :          61 :   gchar *ret = NULL;
    2446                 :          61 :   GError *first_error = NULL;
    2447                 :             :   gsize i;
    2448                 :          61 :   gboolean non_zero = FALSE;
    2449                 :             : 
    2450                 :             :   /* Copy what dbus.git does: allow the /var/lib path to be configurable at
    2451                 :             :    * build time, but hard-code the system-wide machine ID path in /etc. */
    2452                 :          61 :   const gchar *var_lib_path = LOCALSTATEDIR "/lib/dbus/machine-id";
    2453                 :          61 :   const gchar *etc_path = "/etc/machine-id";
    2454                 :             : 
    2455                 :          61 :   if (!g_file_get_contents (var_lib_path,
    2456                 :             :                             &ret,
    2457                 :             :                             NULL,
    2458                 :           0 :                             &first_error) &&
    2459                 :           0 :       !g_file_get_contents (etc_path,
    2460                 :             :                             &ret,
    2461                 :             :                             NULL,
    2462                 :             :                             NULL))
    2463                 :             :     {
    2464                 :           0 :       g_propagate_prefixed_error (error, g_steal_pointer (&first_error),
    2465                 :             :                                   /* Translators: Both placeholders are file paths */
    2466                 :             :                                   _("Unable to load %s or %s: "),
    2467                 :             :                                   var_lib_path, etc_path);
    2468                 :           0 :       return NULL;
    2469                 :             :     }
    2470                 :             : 
    2471                 :             :   /* ignore the error from the first try, if any */
    2472                 :          61 :   g_clear_error (&first_error);
    2473                 :             : 
    2474                 :             :   /* Validate the machine ID. From `man 5 machine-id`:
    2475                 :             :    * > The machine ID is a single newline-terminated, hexadecimal, 32-character,
    2476                 :             :    * > lowercase ID. When decoded from hexadecimal, this corresponds to a
    2477                 :             :    * > 16-byte/128-bit value. This ID may not be all zeros.
    2478                 :             :    */
    2479                 :        2013 :   for (i = 0; ret[i] != '\0' && ret[i] != '\n'; i++)
    2480                 :             :     {
    2481                 :             :       /* Break early if it’s invalid. */
    2482                 :        1952 :       if (!g_ascii_isxdigit (ret[i]) || g_ascii_isupper (ret[i]))
    2483                 :             :         break;
    2484                 :             : 
    2485                 :        1952 :       if (ret[i] != '0')
    2486                 :        1952 :         non_zero = TRUE;
    2487                 :             :     }
    2488                 :             : 
    2489                 :          61 :   if (i != 32 || ret[i] != '\n' || ret[i + 1] != '\0' || !non_zero)
    2490                 :             :     {
    2491                 :           0 :       g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
    2492                 :             :                    "Invalid machine ID in %s or %s",
    2493                 :             :                    var_lib_path, etc_path);
    2494                 :           0 :       g_free (ret);
    2495                 :           0 :       return NULL;
    2496                 :             :     }
    2497                 :             : 
    2498                 :             :   /* Strip trailing newline. */
    2499                 :          61 :   ret[32] = '\0';
    2500                 :             : 
    2501                 :          61 :   return g_steal_pointer (&ret);
    2502                 :             : #endif
    2503                 :             : }
    2504                 :             : 
    2505                 :             : /* ---------------------------------------------------------------------------------------------------- */
    2506                 :             : 
    2507                 :             : gchar *
    2508                 :           0 : _g_dbus_enum_to_string (GType enum_type, gint value)
    2509                 :             : {
    2510                 :             :   gchar *ret;
    2511                 :             :   GEnumClass *klass;
    2512                 :             :   GEnumValue *enum_value;
    2513                 :             : 
    2514                 :           0 :   klass = g_type_class_ref (enum_type);
    2515                 :           0 :   enum_value = g_enum_get_value (klass, value);
    2516                 :           0 :   if (enum_value != NULL)
    2517                 :           0 :     ret = g_strdup (enum_value->value_nick);
    2518                 :             :   else
    2519                 :           0 :     ret = g_strdup_printf ("unknown (value %d)", value);
    2520                 :           0 :   g_type_class_unref (klass);
    2521                 :           0 :   return ret;
    2522                 :             : }
    2523                 :             : 
    2524                 :             : /* ---------------------------------------------------------------------------------------------------- */
    2525                 :             : 
    2526                 :             : static void
    2527                 :       14915 : write_message_print_transport_debug (gssize bytes_written,
    2528                 :             :                                      MessageToWriteData *data)
    2529                 :             : {
    2530                 :       14915 :   if (G_LIKELY (!_g_dbus_debug_transport ()))
    2531                 :       14915 :     goto out;
    2532                 :             : 
    2533                 :           0 :   _g_dbus_debug_print_lock ();
    2534                 :           0 :   g_print ("========================================================================\n"
    2535                 :             :            "GDBus-debug:Transport:\n"
    2536                 :             :            "  >>>> WROTE %" G_GSSIZE_FORMAT " bytes of message with serial %d and\n"
    2537                 :             :            "       size %" G_GSIZE_FORMAT " from offset %" G_GSIZE_FORMAT " on a %s\n",
    2538                 :             :            bytes_written,
    2539                 :             :            g_dbus_message_get_serial (data->message),
    2540                 :             :            data->blob_size,
    2541                 :             :            data->total_written,
    2542                 :           0 :            g_type_name (G_TYPE_FROM_INSTANCE (g_io_stream_get_output_stream (data->worker->stream))));
    2543                 :           0 :   _g_dbus_debug_print_unlock ();
    2544                 :       14915 :  out:
    2545                 :             :   ;
    2546                 :       14915 : }
    2547                 :             : 
    2548                 :             : /* ---------------------------------------------------------------------------------------------------- */
    2549                 :             : 
    2550                 :             : static void
    2551                 :       54971 : read_message_print_transport_debug (gssize bytes_read,
    2552                 :             :                                     GDBusWorker *worker)
    2553                 :             : {
    2554                 :             :   gsize size;
    2555                 :             :   gint32 serial;
    2556                 :             :   gint32 message_length;
    2557                 :             : 
    2558                 :       54971 :   if (G_LIKELY (!_g_dbus_debug_transport ()))
    2559                 :       54971 :     goto out;
    2560                 :             : 
    2561                 :           0 :   size = bytes_read + worker->read_buffer_cur_size;
    2562                 :           0 :   serial = 0;
    2563                 :           0 :   message_length = 0;
    2564                 :           0 :   if (size >= 16)
    2565                 :           0 :     message_length = g_dbus_message_bytes_needed ((guchar *) worker->read_buffer, size, NULL);
    2566                 :           0 :   if (size >= 1)
    2567                 :             :     {
    2568                 :           0 :       switch (worker->read_buffer[0])
    2569                 :             :         {
    2570                 :           0 :         case 'l':
    2571                 :           0 :           if (size >= 12)
    2572                 :           0 :             serial = GUINT32_FROM_LE (((guint32 *) worker->read_buffer)[2]);
    2573                 :           0 :           break;
    2574                 :           0 :         case 'B':
    2575                 :           0 :           if (size >= 12)
    2576                 :           0 :             serial = GUINT32_FROM_BE (((guint32 *) worker->read_buffer)[2]);
    2577                 :           0 :           break;
    2578                 :           0 :         default:
    2579                 :             :           /* an error will be set elsewhere if this happens */
    2580                 :           0 :           goto out;
    2581                 :             :         }
    2582                 :             :     }
    2583                 :             : 
    2584                 :           0 :     _g_dbus_debug_print_lock ();
    2585                 :           0 :   g_print ("========================================================================\n"
    2586                 :             :            "GDBus-debug:Transport:\n"
    2587                 :             :            "  <<<< READ %" G_GSSIZE_FORMAT " bytes of message with serial %d and\n"
    2588                 :             :            "       size %d to offset %" G_GSIZE_FORMAT " from a %s\n",
    2589                 :             :            bytes_read,
    2590                 :             :            serial,
    2591                 :             :            message_length,
    2592                 :             :            worker->read_buffer_cur_size,
    2593                 :           0 :            g_type_name (G_TYPE_FROM_INSTANCE (g_io_stream_get_input_stream (worker->stream))));
    2594                 :           0 :   _g_dbus_debug_print_unlock ();
    2595                 :       54971 :  out:
    2596                 :             :   ;
    2597                 :       54971 : }
    2598                 :             : 
    2599                 :             : /* ---------------------------------------------------------------------------------------------------- */
    2600                 :             : 
    2601                 :             : gboolean
    2602                 :        1382 : _g_signal_accumulator_false_handled (GSignalInvocationHint *ihint,
    2603                 :             :                                      GValue                *return_accu,
    2604                 :             :                                      const GValue          *handler_return,
    2605                 :             :                                      gpointer               dummy)
    2606                 :             : {
    2607                 :             :   gboolean continue_emission;
    2608                 :             :   gboolean signal_return;
    2609                 :             : 
    2610                 :        1382 :   signal_return = g_value_get_boolean (handler_return);
    2611                 :        1382 :   g_value_set_boolean (return_accu, signal_return);
    2612                 :        1382 :   continue_emission = signal_return;
    2613                 :             : 
    2614                 :        1382 :   return continue_emission;
    2615                 :             : }
    2616                 :             : 
    2617                 :             : /* ---------------------------------------------------------------------------------------------------- */
    2618                 :             : 
    2619                 :             : static void
    2620                 :       11738 : append_nibble (GString *s, gint val)
    2621                 :             : {
    2622                 :       11738 :   g_string_append_c (s, val >= 10 ? ('a' + val - 10) : ('0' + val));
    2623                 :       11738 : }
    2624                 :             : 
    2625                 :             : /* ---------------------------------------------------------------------------------------------------- */
    2626                 :             : 
    2627                 :             : gchar *
    2628                 :         432 : _g_dbus_hexencode (const gchar *str,
    2629                 :             :                    gsize        str_len)
    2630                 :             : {
    2631                 :             :   gsize n;
    2632                 :             :   GString *s;
    2633                 :             : 
    2634                 :         432 :   s = g_string_new (NULL);
    2635                 :        6301 :   for (n = 0; n < str_len; n++)
    2636                 :             :     {
    2637                 :             :       gint val;
    2638                 :             :       gint upper_nibble;
    2639                 :             :       gint lower_nibble;
    2640                 :             : 
    2641                 :        5869 :       val = ((const guchar *) str)[n];
    2642                 :        5869 :       upper_nibble = val >> 4;
    2643                 :        5869 :       lower_nibble = val & 0x0f;
    2644                 :             : 
    2645                 :        5869 :       append_nibble (s, upper_nibble);
    2646                 :        5869 :       append_nibble (s, lower_nibble);
    2647                 :             :     }
    2648                 :             : 
    2649                 :         432 :   return g_string_free (s, FALSE);
    2650                 :             : }
        

Generated by: LCOV version 2.0-1