LCOV - code coverage report
Current view: top level - src/plugins/bluez - valent-bluez-muxer.c (source / functions) Coverage Total Hit
Test: Code Coverage Lines: 76.0 % 680 517
Test Date: 2025-11-09 04:19:42 Functions: 85.5 % 55 47
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 43.2 % 396 171

             Branch data     Line data    Source code
       1                 :             : // SPDX-License-Identifier: GPL-3.0-or-later
       2                 :             : // SPDX-FileCopyrightText: Andy Holmes <andrew.g.r.holmes@gmail.com>
       3                 :             : 
       4                 :             : #define G_LOG_DOMAIN "valent-bluez-muxer"
       5                 :             : 
       6                 :             : #include "config.h"
       7                 :             : 
       8                 :             : #ifndef _GNU_SOURCE
       9                 :             : # define _GNU_SOURCE
      10                 :             : #endif /* _GNU_SOURCE */
      11                 :             : 
      12                 :             : #include <unistd.h>
      13                 :             : #include <sys/eventfd.h>
      14                 :             : 
      15                 :             : #include <glib/gprintf.h>
      16                 :             : #include <glib-unix.h>
      17                 :             : #include <gio/gio.h>
      18                 :             : #include <valent.h>
      19                 :             : 
      20                 :             : #include "valent-bluez-channel.h"
      21                 :             : #include "valent-mux-io-stream.h"
      22                 :             : 
      23                 :             : #include "valent-bluez-muxer.h"
      24                 :             : 
      25                 :             : #define IDENTITY_BUFFER_MAX  (8192)
      26                 :             : 
      27                 :             : #define CERTIFICATE_HEADER "-----BEGIN CERTIFICATE-----\n"
      28                 :             : #define CERTIFICATE_FOOTER "-----END CERTIFICATE-----\n"
      29                 :             : 
      30                 :             : #define DEFAULT_BUFFER_SIZE (4096)
      31                 :             : #define HEADER_SIZE         (19)
      32                 :             : #define PRIMARY_UUID        "a0d0aaf4-1072-4d81-aa35-902a954b1266"
      33                 :             : #define PROTOCOL_MIN        (1)
      34                 :             : #define PROTOCOL_MAX        (1)
      35                 :             : 
      36                 :             : 
      37                 :             : struct _ValentBluezMuxer
      38                 :             : {
      39                 :             :   ValentObject   parent_instance;
      40                 :             : 
      41                 :             :   GIOStream     *base_stream;
      42                 :             :   uint16_t       buffer_size;
      43                 :             : 
      44                 :             :   GHashTable    *states;
      45                 :             :   GCancellable  *cancellable;
      46                 :             :   unsigned int   protocol_version;
      47                 :             : 
      48                 :             :   GThread       *input_thread;
      49                 :             :   GInputStream  *input_stream;
      50                 :             :   GOutputStream *output_stream;
      51                 :             : };
      52                 :             : 
      53   [ +  +  +  - ]:        3949 : G_DEFINE_FINAL_TYPE (ValentBluezMuxer, valent_bluez_muxer, VALENT_TYPE_OBJECT)
      54                 :             : 
      55                 :             : typedef enum {
      56                 :             :   PROP_BASE_STREAM = 1,
      57                 :             :   PROP_BUFFER_SIZE,
      58                 :             : } ValentBluezMuxerProperty;
      59                 :             : 
      60                 :             : static GParamSpec *properties[PROP_BUFFER_SIZE + 1] = { NULL, };
      61                 :             : 
      62                 :             : /**
      63                 :             :  * MessageType:
      64                 :             :  * @MESSAGE_PROTOCOL: The protocol version
      65                 :             :  * @MESSAGE_OPEN: A request to open a new multiplexed channel
      66                 :             :  * @MESSAGE_CLOSE: A request to close a multiplexed channel
      67                 :             :  * @MESSAGE_READ: A request for more bytes
      68                 :             :  * @MESSAGE_WRITE: A packet of bytes
      69                 :             :  *
      70                 :             :  * Enumeration of multiplex message types.
      71                 :             :  */
      72                 :             : typedef enum
      73                 :             : {
      74                 :             :   MESSAGE_PROTOCOL_VERSION,
      75                 :             :   MESSAGE_OPEN_CHANNEL,
      76                 :             :   MESSAGE_CLOSE_CHANNEL,
      77                 :             :   MESSAGE_READ,
      78                 :             :   MESSAGE_WRITE
      79                 :             : } MessageType;
      80                 :             : 
      81                 :             : /**
      82                 :             :  * ChannelState:
      83                 :             :  * @uuid: the channel UUID
      84                 :             :  * @mutex: a lock for changes to the state
      85                 :             :  * @cond: a `GCond` for blocking threads
      86                 :             :  * @eventfd: a file descriptor for pollable sources
      87                 :             :  * @condition: the `GIOCondition`
      88                 :             :  * @stream: a `GIOStream`
      89                 :             :  * @buffer: an input buffer
      90                 :             :  * @size: size of the input buffer
      91                 :             :  * @head: data start
      92                 :             :  * @tail: data end
      93                 :             :  * @count: bytes in the buffer
      94                 :             :  * @read_free: free space in the input buffer
      95                 :             :  * @write_free: amount of bytes that can be written
      96                 :             :  *
      97                 :             :  * A thread-safe struct, with a ring buffer, for tracking a multiplex channel.
      98                 :             :  *
      99                 :             :  * The @head and @tail offsets refer to the read and write positions,
     100                 :             :  * respectively, while @count indicates bytes in the buffer waiting to be read.
     101                 :             :  *
     102                 :             :  * @read_free is the amount of free space in the buffer for which a
     103                 :             :  * %MESSAGE_READ request has not been sent (i.e. @read_free <= @size - @count),
     104                 :             :  * while @write_free is the amount of bytes that can be written until another
     105                 :             :  * %MESSAGE_READ request is received.
     106                 :             :  */
     107                 :             : typedef struct
     108                 :             : {
     109                 :             :   char         *uuid;
     110                 :             :   GMutex        mutex;
     111                 :             :   GCond         cond;
     112                 :             :   int           eventfd;
     113                 :             :   GIOCondition  condition;
     114                 :             :   GIOStream    *stream;
     115                 :             : 
     116                 :             :   /* Input Buffer */
     117                 :             :   uint8_t      *buffer;
     118                 :             :   size_t        size;
     119                 :             :   size_t        head;
     120                 :             :   size_t        tail;
     121                 :             :   size_t        count;
     122                 :             : 
     123                 :             :   /* Muxer State */
     124                 :             :   uint16_t      read_free;
     125                 :             :   uint16_t      write_free;
     126                 :             : } ChannelState;
     127                 :             : 
     128                 :             : static ChannelState *
     129                 :           6 : channel_state_new (ValentBluezMuxer *muxer,
     130                 :             :                    const char       *uuid)
     131                 :             : {
     132                 :           6 :   ChannelState *state = NULL;
     133                 :             : 
     134                 :           6 :   state = g_atomic_rc_box_new0 (ChannelState);
     135                 :           6 :   g_mutex_init (&state->mutex);
     136                 :           6 :   g_mutex_lock (&state->mutex);
     137                 :           6 :   g_cond_init (&state->cond);
     138         [ -  + ]:           6 :   state->uuid = g_strdup (uuid);
     139                 :           6 :   state->size = muxer->buffer_size;
     140                 :           6 :   state->buffer = g_malloc0 (state->size);
     141                 :           6 :   state->stream = g_object_new (VALENT_TYPE_MUX_IO_STREAM,
     142                 :             :                                 "muxer", muxer,
     143                 :             :                                 "uuid",  uuid,
     144                 :             :                                 NULL);
     145                 :           6 :   state->eventfd = eventfd (0, EFD_NONBLOCK | EFD_CLOEXEC);
     146         [ -  + ]:           6 :   if (state->eventfd == -1)
     147                 :           0 :     g_critical ("%s(): %s", G_STRFUNC, g_strerror (errno));
     148                 :           6 :   g_mutex_unlock (&state->mutex);
     149                 :             : 
     150                 :           6 :   return state;
     151                 :             : }
     152                 :             : 
     153                 :             : static void
     154                 :           0 : channel_state_free (gpointer data)
     155                 :             : {
     156                 :           0 :   ChannelState *state = (ChannelState *)data;
     157                 :             : 
     158                 :           0 :   g_mutex_lock (&state->mutex);
     159         [ #  # ]:           0 :   g_clear_object (&state->stream);
     160         [ #  # ]:           0 :   g_clear_pointer (&state->buffer, g_free);
     161         [ #  # ]:           0 :   g_clear_pointer (&state->uuid, g_free);
     162                 :           0 :   g_clear_fd (&state->eventfd, NULL);
     163                 :           0 :   g_cond_clear (&state->cond);
     164                 :           0 :   g_mutex_unlock (&state->mutex);
     165                 :           0 :   g_mutex_clear (&state->mutex);
     166                 :           0 : }
     167                 :             : 
     168                 :             : static void
     169                 :        3967 : channel_state_unref (gpointer data)
     170                 :             : {
     171                 :           4 :   g_atomic_rc_box_release_full (data, channel_state_free);
     172                 :        3963 : }
     173                 :             : 
     174                 :             : static inline gboolean
     175                 :          31 : channel_state_flush_unlocked (ChannelState  *state,
     176                 :             :                               GError       **error)
     177                 :             : {
     178                 :          31 :   int64_t byte = 1;
     179                 :             : 
     180         [ -  + ]:          31 :   if (write (state->eventfd, &byte, sizeof (uint64_t)) == -1)
     181                 :             :     {
     182                 :           0 :       g_set_error_literal (error,
     183                 :             :                            G_IO_ERROR,
     184                 :           0 :                            g_io_error_from_errno (errno),
     185                 :           0 :                            g_strerror (errno));
     186                 :           0 :       return FALSE;
     187                 :             :     }
     188                 :          31 :   g_cond_broadcast (&state->cond);
     189                 :             : 
     190                 :          31 :   return TRUE;
     191                 :             : }
     192                 :             : 
     193                 :             : static inline gboolean
     194                 :          13 : channel_state_close_unlocked (ChannelState  *state,
     195                 :             :                               GError       **error)
     196                 :             : {
     197                 :          13 :   state->condition &= ~(G_IO_IN | G_IO_OUT);
     198                 :          13 :   state->condition |= G_IO_HUP;
     199                 :             : 
     200                 :           0 :   return channel_state_flush_unlocked (state, error);
     201                 :             : }
     202                 :             : 
     203                 :             : static inline gssize
     204                 :        3882 : channel_state_read_unlocked (ChannelState  *state,
     205                 :             :                              uint8_t       *buffer,
     206                 :             :                              size_t         count,
     207                 :             :                              GError       **error)
     208                 :             : {
     209                 :        3882 :   size_t tail_chunk;
     210                 :             : 
     211         [ -  + ]:        3882 :   if ((state->condition & G_IO_ERR) != 0)
     212                 :             :     {
     213                 :           0 :       g_set_error_literal (error,
     214                 :             :                            G_IO_ERROR,
     215                 :             :                            G_IO_ERROR_CLOSED,
     216                 :             :                            g_strerror (EPIPE));
     217                 :           0 :       return -1;
     218                 :             :     }
     219                 :             : 
     220                 :        3882 :   count = MIN (count, state->count);
     221         [ +  + ]:        3882 :   if (count == 0)
     222                 :             :     {
     223                 :             :       /* If the buffer has been emptied and the channel is marked closed,
     224                 :             :        * simulate EOF and set the error condition on the channel state
     225                 :             :        */
     226         [ +  - ]:           1 :       if ((state->condition & G_IO_HUP) != 0)
     227                 :             :         {
     228                 :           1 :           state->condition |= G_IO_ERR;
     229                 :           1 :           return 0;
     230                 :             :         }
     231                 :             : 
     232                 :           0 :       g_set_error_literal (error,
     233                 :             :                            G_IO_ERROR,
     234                 :             :                            G_IO_ERROR_WOULD_BLOCK,
     235                 :             :                            g_strerror (EAGAIN));
     236                 :           0 :       return -1;
     237                 :             :     }
     238                 :             : 
     239                 :        3881 :   tail_chunk = MIN (state->size - state->head, count);
     240                 :        3881 :   memcpy (buffer, state->buffer + state->head, tail_chunk);
     241         [ -  + ]:        3881 :   if (count > tail_chunk)
     242                 :           0 :     memcpy (buffer + tail_chunk, state->buffer, count - tail_chunk);
     243                 :             : 
     244                 :        3881 :   state->head = (state->head + count) % state->size;
     245                 :        3881 :   state->count -= count;
     246                 :             : 
     247         [ +  + ]:        3881 :   if (state->count == 0)
     248                 :           7 :     state->condition &= ~G_IO_IN;
     249                 :             : 
     250                 :        3881 :   return count;
     251                 :             : }
     252                 :             : 
     253                 :             : static inline ChannelState *
     254                 :        3950 : channel_state_lookup (ValentBluezMuxer  *self,
     255                 :             :                       const char        *uuid,
     256                 :             :                       GError           **error)
     257                 :             : {
     258                 :        3950 :   ChannelState *state = NULL;
     259                 :        3950 :   ChannelState *ret = NULL;
     260                 :             : 
     261                 :        3950 :   valent_object_lock (VALENT_OBJECT (self));
     262                 :        3950 :   state = g_hash_table_lookup (self->states, uuid);
     263         [ -  + ]:        3950 :   if (state == NULL)
     264                 :             :     {
     265                 :           0 :       g_set_error_literal (error,
     266                 :             :                            G_IO_ERROR,
     267                 :             :                            G_IO_ERROR_CLOSED,
     268                 :             :                            g_strerror (EPIPE));
     269                 :             :     }
     270                 :             :   else
     271                 :             :     {
     272                 :        3950 :       ret = g_atomic_rc_box_acquire (state);
     273                 :             :     }
     274                 :        3950 :   valent_object_unlock (VALENT_OBJECT (self));
     275                 :             : 
     276                 :        3950 :   return ret;
     277                 :             : }
     278                 :             : 
     279         [ +  + ]:        3956 : G_DEFINE_AUTOPTR_CLEANUP_FUNC (ChannelState, channel_state_unref)
     280                 :             : 
     281                 :             : /**
     282                 :             :  * pack_header:
     283                 :             :  * @hdr: (out): a 19-byte buffer
     284                 :             :  * @type: a `MessageType` type
     285                 :             :  * @size: size of the message data
     286                 :             :  * @uuid: channel UUID
     287                 :             :  *
     288                 :             :  * Pack a multiplex header into @hdr.
     289                 :             :  */
     290                 :             : static inline void
     291                 :          28 : pack_header (uint8_t     *hdr,
     292                 :             :              MessageType  type,
     293                 :             :              uint16_t     size,
     294                 :             :              const char  *uuid)
     295                 :             : {
     296                 :          28 :   static const uint8_t indices[16] = {
     297                 :             :     0, 2, 4, 6, 9, 11, 14, 16, 19, 21, 24, 26, 28, 30, 32, 34,
     298                 :             :   };
     299                 :             : 
     300                 :          28 :   hdr[0] = type;
     301                 :          28 :   hdr[1] = (size >> 8) & 0xff;
     302                 :          28 :   hdr[2] = size & 0xff;
     303                 :             : 
     304         [ +  + ]:         476 :   for (size_t i = 0; i < G_N_ELEMENTS (indices); i++)
     305                 :             :     {
     306                 :         448 :       int hi = g_ascii_xdigit_value (uuid[indices[i] + 0]);
     307                 :         448 :       int lo = g_ascii_xdigit_value (uuid[indices[i] + 1]);
     308                 :             : 
     309                 :         448 :       hdr[3 + i] = (hi << 4) | lo;
     310                 :             :     }
     311                 :          28 : }
     312                 :             : 
     313                 :             : /**
     314                 :             :  * unpack_header:
     315                 :             :  * @hdr: a 19-byte buffer
     316                 :             :  * @type: (out): a `MessageType` type
     317                 :             :  * @size: (out): size of the message data
     318                 :             :  * @uuid: (out): a 37-byte buffer
     319                 :             :  *
     320                 :             :  * Unpack the multiplex header @hdr into @type, @size and @uuid.
     321                 :             :  */
     322                 :             : static inline void
     323                 :          28 : unpack_header (const uint8_t *hdr,
     324                 :             :                MessageType   *type,
     325                 :             :                uint16_t      *size,
     326                 :             :                char          *uuid)
     327                 :             : {
     328         [ -  + ]:          28 :   g_assert (type != NULL);
     329         [ +  - ]:          28 :   g_assert (size != NULL);
     330                 :             : 
     331                 :          28 :   *type = hdr[0];
     332                 :          28 :   *size = (uint16_t)(hdr[1] << 8 | hdr[2]);
     333                 :          28 :   g_snprintf (uuid, 37,
     334                 :             :               "%02x%02x%02x%02x-"
     335                 :             :               "%02x%02x-%02x%02x-%02x%02x-"
     336                 :             :               "%02x%02x%02x%02x%02x%02x",
     337                 :          28 :               hdr[3], hdr[4], hdr[5], hdr[6],
     338                 :          28 :               hdr[7], hdr[8], hdr[9], hdr[10], hdr[11], hdr[12],
     339                 :          28 :               hdr[13], hdr[14], hdr[15], hdr[16], hdr[17], hdr[18]);
     340                 :          28 : }
     341                 :             : 
     342                 :             : /*
     343                 :             :  * Receive Helpers
     344                 :             :  */
     345                 :             : static inline gboolean
     346                 :          32 : recv_header (ValentBluezMuxer  *self,
     347                 :             :              MessageType       *type,
     348                 :             :              uint16_t          *size,
     349                 :             :              char              *uuid,
     350                 :             :              GCancellable      *cancellable,
     351                 :             :              GError           **error)
     352                 :             : {
     353                 :          32 :   uint8_t hdr[HEADER_SIZE] = { 0, };
     354                 :          32 :   gboolean ret;
     355                 :             : 
     356                 :          32 :   ret = g_input_stream_read_all (self->input_stream,
     357                 :             :                                  hdr,
     358                 :             :                                  sizeof (hdr),
     359                 :             :                                  NULL,
     360                 :             :                                  cancellable,
     361                 :             :                                  error);
     362         [ +  - ]:          28 :   if (ret)
     363                 :          28 :     unpack_header (hdr, type, size, uuid);
     364                 :             : 
     365                 :          28 :   return ret;
     366                 :             : }
     367                 :             : 
     368                 :             : static inline gboolean
     369                 :           4 : recv_protocol_version (ValentBluezMuxer  *self,
     370                 :             :                        GCancellable      *cancellable,
     371                 :             :                        GError           **error)
     372                 :             : {
     373                 :           4 :   gboolean ret;
     374                 :           4 :   uint16_t supported_versions[2] = { 0, };
     375                 :           4 :   uint16_t min_version, max_version;
     376                 :             : 
     377                 :           4 :   ret = g_input_stream_read_all (self->input_stream,
     378                 :             :                                  supported_versions,
     379                 :             :                                  sizeof (supported_versions),
     380                 :             :                                  NULL,
     381                 :             :                                  cancellable,
     382                 :             :                                  error);
     383         [ +  - ]:           4 :   if (ret)
     384                 :             :     {
     385                 :           4 :       min_version = GUINT16_FROM_BE (supported_versions[0]);
     386                 :           4 :       max_version = GUINT16_FROM_BE (supported_versions[1]);
     387         [ -  + ]:           4 :       if (min_version > PROTOCOL_MAX)
     388                 :             :         {
     389                 :           0 :           g_set_error (error,
     390                 :             :                        G_IO_ERROR,
     391                 :             :                        G_IO_ERROR_NOT_SUPPORTED,
     392                 :             :                        "Protocol version too high (v%u)",
     393                 :             :                        min_version);
     394                 :           0 :           return FALSE;
     395                 :             :         }
     396                 :             : 
     397                 :           4 :       self->protocol_version = MIN (max_version, PROTOCOL_MAX);
     398                 :             :       VALENT_NOTE ("Using multiplexer protocol v%u", self->protocol_version);
     399                 :             :     }
     400                 :             : 
     401                 :             :   return ret;
     402                 :             : }
     403                 :             : 
     404                 :             : static inline gboolean
     405                 :           1 : recv_open_channel (ValentBluezMuxer  *self,
     406                 :             :                    const char        *uuid,
     407                 :             :                    GCancellable      *cancellable,
     408                 :             :                    GError           **error)
     409                 :             : {
     410                 :           1 :   gboolean ret = TRUE;
     411                 :             : 
     412                 :           1 :   valent_object_lock (VALENT_OBJECT (self));
     413         [ -  + ]:           1 :   if (g_hash_table_contains (self->states, uuid))
     414                 :             :     {
     415                 :           0 :       g_set_error (error,
     416                 :             :                    G_IO_ERROR,
     417                 :             :                    G_IO_ERROR_ADDRESS_IN_USE,
     418                 :             :                    "Channel already open (%s)",
     419                 :             :                    uuid);
     420                 :           0 :       ret = FALSE;
     421                 :             :     }
     422                 :             :   else
     423                 :             :     {
     424                 :           1 :       g_autoptr (ChannelState) state = NULL;
     425                 :             : 
     426                 :             :       /* NOTE: the initial MESSAGE_READ request will be sent by
     427                 :             :        *       valent_bluez_muxer_channel_accept()
     428                 :             :        */
     429                 :           1 :       state = channel_state_new (self, uuid);
     430                 :           1 :       g_hash_table_replace (self->states,
     431                 :           1 :                             state->uuid,
     432                 :             :                             g_atomic_rc_box_acquire (state));
     433                 :             :     }
     434                 :           1 :   valent_object_unlock (VALENT_OBJECT (self));
     435                 :             : 
     436                 :           1 :   return ret;
     437                 :             : }
     438                 :             : 
     439                 :             : static inline gboolean
     440                 :          10 : recv_close_channel (ValentBluezMuxer  *self,
     441                 :             :                     const char        *uuid,
     442                 :             :                     GCancellable      *cancellable,
     443                 :             :                     GError           **error)
     444                 :             : {
     445                 :          10 :   g_autoptr (ChannelState) state = NULL;
     446                 :          10 :   gboolean ret;
     447                 :             : 
     448                 :          10 :   state = channel_state_lookup (self, uuid, NULL);
     449         [ +  - ]:          10 :   if (state == NULL)
     450                 :             :     return TRUE;
     451                 :             : 
     452                 :          10 :   g_mutex_lock (&state->mutex);
     453                 :          10 :   ret = channel_state_close_unlocked (state, error);
     454                 :          10 :   g_mutex_unlock (&state->mutex);
     455                 :             : 
     456                 :          10 :   return ret;
     457                 :             : }
     458                 :             : 
     459                 :             : static inline gboolean
     460                 :           6 : recv_read (ValentBluezMuxer  *self,
     461                 :             :            const char        *uuid,
     462                 :             :            GCancellable      *cancellable,
     463                 :             :            GError           **error)
     464                 :             : {
     465                 :           6 :   g_autoptr (ChannelState) state = NULL;
     466                 :           6 :   uint16_t size_request;
     467                 :           6 :   gboolean ret;
     468                 :             : 
     469                 :           6 :   state = channel_state_lookup (self, uuid, error);
     470         [ -  + ]:           6 :   if (state == NULL)
     471                 :             :     return FALSE;
     472                 :             : 
     473                 :           6 :   ret = g_input_stream_read_all (self->input_stream,
     474                 :             :                                  &size_request,
     475                 :             :                                  sizeof (size_request),
     476                 :             :                                  NULL,
     477                 :             :                                  cancellable,
     478                 :             :                                  error);
     479         [ -  + ]:           6 :   if (ret)
     480                 :             :     {
     481                 :           6 :       g_mutex_lock (&state->mutex);
     482                 :           6 :       state->write_free += GUINT16_FROM_BE (size_request);
     483                 :           6 :       state->condition |= G_IO_OUT;
     484                 :           6 :       ret = channel_state_flush_unlocked (state, error);
     485                 :           6 :       g_mutex_unlock (&state->mutex);
     486                 :             :     }
     487                 :             : 
     488                 :             :   return ret;
     489                 :             : }
     490                 :             : 
     491                 :             : static inline gboolean
     492                 :           7 : recv_write (ValentBluezMuxer  *self,
     493                 :             :             const char        *uuid,
     494                 :             :             uint16_t           size,
     495                 :             :             GCancellable      *cancellable,
     496                 :             :             GError           **error)
     497                 :             : {
     498                 :           7 :   g_autoptr (ChannelState) state = NULL;
     499                 :           7 :   size_t tail_free;
     500                 :           7 :   gboolean ret;
     501                 :             : 
     502                 :           7 :   state = channel_state_lookup (self, uuid, error);
     503         [ -  + ]:           7 :   if (state == NULL)
     504                 :             :     return FALSE;
     505                 :             : 
     506                 :           7 :   g_mutex_lock (&state->mutex);
     507         [ +  - ]:           7 :   if G_UNLIKELY (size > state->read_free)
     508                 :             :     {
     509                 :           0 :       g_set_error (error,
     510                 :             :                    G_IO_ERROR,
     511                 :             :                    G_IO_ERROR_MESSAGE_TOO_LARGE,
     512                 :             :                    "Write size (%u) exceeds requested (%u)",
     513                 :             :                    size, state->read_free);
     514                 :           0 :       g_mutex_unlock (&state->mutex);
     515                 :           0 :       return FALSE;
     516                 :             :     }
     517                 :             : 
     518                 :           7 :   tail_free = MIN (state->size - state->tail, size);
     519                 :          14 :   ret = g_input_stream_read_all (self->input_stream,
     520                 :           7 :                                  &state->buffer[state->tail],
     521                 :             :                                  tail_free,
     522                 :             :                                  NULL,
     523                 :             :                                  cancellable,
     524                 :             :                                  error);
     525   [ +  -  -  + ]:           7 :   if (ret && size > tail_free)
     526                 :             :     {
     527                 :           0 :       ret = g_input_stream_read_all (self->input_stream,
     528                 :           0 :                                      &state->buffer[0],
     529                 :           0 :                                      size - tail_free,
     530                 :             :                                      NULL,
     531                 :             :                                      cancellable,
     532                 :             :                                      error);
     533                 :             :     }
     534                 :             : 
     535         [ -  + ]:           7 :   if (ret)
     536                 :             :     {
     537                 :           7 :       state->tail = (state->tail + size) % state->size;
     538                 :           7 :       state->count += size;
     539                 :           7 :       state->read_free -= size;
     540                 :           7 :       state->condition |= G_IO_IN;
     541                 :           7 :       ret = channel_state_flush_unlocked (state, error);
     542                 :             :     }
     543                 :           7 :   g_mutex_unlock (&state->mutex);
     544                 :             : 
     545                 :           7 :   return ret;
     546                 :             : }
     547                 :             : 
     548                 :             : static gpointer
     549                 :           4 : valent_bluez_muxer_receive_loop (gpointer data)
     550                 :             : {
     551                 :           4 :   g_autoptr (ValentBluezMuxer) self = VALENT_BLUEZ_MUXER (data);
     552                 :           4 :   MessageType type;
     553                 :           4 :   uint16_t size;
     554                 :           4 :   char uuid[37] = { 0, };
     555                 :           0 :   g_autoptr (GError) error = NULL;
     556                 :             : 
     557         [ +  - ]:          32 :   while (recv_header (self, &type, &size, uuid, self->cancellable, &error))
     558                 :             :     {
     559   [ +  +  +  +  :          28 :       switch ((MessageType)type)
                   +  - ]
     560                 :             :         {
     561                 :           4 :         case MESSAGE_PROTOCOL_VERSION:
     562         [ -  + ]:           4 :           if (!recv_protocol_version (self, self->cancellable, &error))
     563                 :           0 :             VALENT_GOTO (out);
     564                 :             :           break;
     565                 :             : 
     566                 :           1 :         case MESSAGE_OPEN_CHANNEL:
     567         [ -  + ]:           1 :           if (!recv_open_channel (self, uuid, self->cancellable, &error))
     568                 :           0 :             VALENT_GOTO (out);
     569                 :             :           break;
     570                 :             : 
     571                 :          10 :         case MESSAGE_CLOSE_CHANNEL:
     572         [ -  + ]:          10 :           if (!recv_close_channel (self, uuid, self->cancellable, &error))
     573                 :           0 :             VALENT_GOTO (out);
     574                 :             :           break;
     575                 :             : 
     576                 :           6 :         case MESSAGE_READ:
     577         [ -  + ]:           6 :           if (!recv_read (self, uuid, self->cancellable, &error))
     578                 :           0 :             VALENT_GOTO (out);
     579                 :             :           break;
     580                 :             : 
     581                 :           7 :         case MESSAGE_WRITE:
     582         [ -  + ]:           7 :           if (!recv_write (self, uuid, size, self->cancellable, &error))
     583                 :           0 :             VALENT_GOTO (out);
     584                 :             :           break;
     585                 :             : 
     586                 :           0 :         default:
     587                 :           0 :           g_set_error (&error,
     588                 :             :                        G_IO_ERROR,
     589                 :             :                        G_IO_ERROR_INVALID_ARGUMENT,
     590                 :             :                        "Unknown message type (%u)",
     591                 :             :                        type);
     592                 :          32 :           VALENT_GOTO (out);
     593                 :             :         }
     594                 :             :     }
     595                 :             : 
     596                 :           0 : out:
     597         [ #  # ]:           0 :   if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
     598                 :             :     {
     599                 :           0 :       g_debug ("%s(): %s", G_STRFUNC, error->message);
     600                 :           0 :       valent_bluez_muxer_close (self, NULL, NULL);
     601                 :             :     }
     602                 :             : 
     603         [ #  # ]:           0 :   return NULL;
     604                 :             : }
     605                 :             : 
     606                 :             : static inline gboolean
     607                 :           4 : send_protocol_version (ValentBluezMuxer  *self,
     608                 :             :                        GCancellable      *cancellable,
     609                 :             :                        GError           **error)
     610                 :             : {
     611                 :           4 :   uint8_t message[HEADER_SIZE + 4] = { 0, };
     612                 :             : 
     613                 :             :   /* Pack the versions big-endian
     614                 :             :    */
     615                 :           4 :   pack_header (message, MESSAGE_PROTOCOL_VERSION, 4, PRIMARY_UUID);
     616                 :           4 :   message[HEADER_SIZE + 0] = (PROTOCOL_MIN >> 8) & 0xff;
     617                 :           4 :   message[HEADER_SIZE + 1] = PROTOCOL_MIN & 0xff;
     618                 :           4 :   message[HEADER_SIZE + 2] = (PROTOCOL_MAX >> 8) & 0xff;
     619                 :           4 :   message[HEADER_SIZE + 3] = PROTOCOL_MAX & 0xff;
     620                 :             : 
     621                 :           4 :   return g_output_stream_write_all (self->output_stream,
     622                 :             :                                     &message,
     623                 :             :                                     sizeof (message),
     624                 :             :                                     NULL,
     625                 :             :                                     cancellable,
     626                 :             :                                     error);
     627                 :             : }
     628                 :             : 
     629                 :             : static inline gboolean
     630                 :           1 : send_open_channel (ValentBluezMuxer  *self,
     631                 :             :                    const char        *uuid,
     632                 :             :                    GCancellable      *cancellable,
     633                 :             :                    GError           **error)
     634                 :             : {
     635                 :           1 :   uint8_t message[HEADER_SIZE] = { 0, };
     636                 :             : 
     637                 :           1 :   pack_header (message, MESSAGE_OPEN_CHANNEL, 0, uuid);
     638                 :             : 
     639                 :           1 :   return g_output_stream_write_all (self->output_stream,
     640                 :             :                                     &message,
     641                 :             :                                     sizeof (message),
     642                 :             :                                     NULL,
     643                 :             :                                     cancellable,
     644                 :             :                                     error);
     645                 :             : }
     646                 :             : 
     647                 :             : static inline gboolean
     648                 :          10 : send_close_channel (ValentBluezMuxer  *self,
     649                 :             :                     const char        *uuid,
     650                 :             :                     GCancellable      *cancellable,
     651                 :             :                     GError           **error)
     652                 :             : {
     653                 :          10 :   uint8_t message[HEADER_SIZE] = { 0, };
     654                 :             : 
     655                 :          10 :   pack_header (message, MESSAGE_CLOSE_CHANNEL, 0, uuid);
     656                 :             : 
     657                 :          10 :   return g_output_stream_write_all (self->output_stream,
     658                 :             :                                     &message,
     659                 :             :                                     sizeof (message),
     660                 :             :                                     NULL,
     661                 :             :                                     cancellable,
     662                 :             :                                     error);
     663                 :             : }
     664                 :             : 
     665                 :             : static inline gboolean
     666                 :           6 : send_read (ValentBluezMuxer  *self,
     667                 :             :            const char        *uuid,
     668                 :             :            uint16_t           size_request,
     669                 :             :            GCancellable      *cancellable,
     670                 :             :            GError           **error)
     671                 :             : {
     672                 :           6 :   uint8_t message[HEADER_SIZE + 2] = { 0, };
     673                 :             : 
     674                 :             :   /* Pack the request big-endian
     675                 :             :    */
     676                 :           6 :   pack_header (message, MESSAGE_READ, 2, uuid);
     677                 :           6 :   message[HEADER_SIZE + 0] = (size_request >> 8) & 0xff;
     678                 :           6 :   message[HEADER_SIZE + 1] = size_request & 0xff;
     679                 :             : 
     680                 :           6 :   return g_output_stream_write_all (self->output_stream,
     681                 :             :                                     &message,
     682                 :             :                                     sizeof (message),
     683                 :             :                                     NULL,
     684                 :             :                                     cancellable,
     685                 :             :                                     error);
     686                 :             : }
     687                 :             : 
     688                 :             : static inline gboolean
     689                 :           7 : send_write (ValentBluezMuxer  *self,
     690                 :             :             const char        *uuid,
     691                 :             :             uint16_t           size,
     692                 :             :             const void        *buffer,
     693                 :             :             GCancellable      *cancellable,
     694                 :             :             GError           **error)
     695                 :             : {
     696                 :           7 :   uint8_t message[HEADER_SIZE] = { 0, };
     697                 :           7 :   gboolean ret;
     698                 :             : 
     699                 :           7 :   pack_header (message, MESSAGE_WRITE, size, uuid);
     700                 :             : 
     701                 :           7 :   ret = g_output_stream_write_all (self->output_stream,
     702                 :             :                                    message,
     703                 :             :                                    sizeof (message),
     704                 :             :                                    NULL,
     705                 :             :                                    cancellable,
     706                 :             :                                    error);
     707         [ +  - ]:           7 :   if (ret)
     708                 :             :     {
     709                 :           7 :       ret = g_output_stream_write_all (self->output_stream,
     710                 :             :                                        buffer,
     711                 :             :                                        size,
     712                 :             :                                        NULL,
     713                 :             :                                        cancellable,
     714                 :             :                                        error);
     715                 :             :     }
     716                 :             : 
     717                 :           7 :   return ret;
     718                 :             : }
     719                 :             : 
     720                 :             : /*
     721                 :             :  * ValentObject
     722                 :             :  */
     723                 :             : static void
     724                 :           0 : valent_bluez_muxer_destroy (ValentObject *object)
     725                 :             : {
     726                 :           0 :   ValentBluezMuxer *self = VALENT_BLUEZ_MUXER (object);
     727                 :             : 
     728                 :           0 :   valent_bluez_muxer_close (self, NULL, NULL);
     729                 :             : 
     730                 :           0 :   VALENT_OBJECT_CLASS (valent_bluez_muxer_parent_class)->destroy (object);
     731                 :           0 : }
     732                 :             : 
     733                 :             : /*
     734                 :             :  * GObject
     735                 :             :  *
     736                 :             :  * TODO: GAsyncInitable or merge with ValentMuxChannel
     737                 :             :  */
     738                 :             : static void
     739                 :           4 : valent_bluez_muxer_constructed (GObject *object)
     740                 :             : {
     741                 :           4 :   ValentBluezMuxer *self = VALENT_BLUEZ_MUXER (object);
     742                 :             : 
     743                 :           4 :   G_OBJECT_CLASS (valent_bluez_muxer_parent_class)->constructed (object);
     744                 :             : 
     745                 :           4 :   valent_object_lock (VALENT_OBJECT (self));
     746   [ +  -  +  -  :           4 :   g_assert (G_IS_IO_STREAM (self->base_stream));
             +  -  -  + ]
     747                 :           4 :   self->input_stream = g_io_stream_get_input_stream (self->base_stream);
     748                 :           4 :   self->output_stream = g_io_stream_get_output_stream (self->base_stream);
     749                 :           4 :   valent_object_unlock (VALENT_OBJECT (self));
     750                 :           4 : }
     751                 :             : 
     752                 :             : static void
     753                 :           0 : valent_bluez_muxer_finalize (GObject *object)
     754                 :             : {
     755                 :           0 :   ValentBluezMuxer *self = VALENT_BLUEZ_MUXER (object);
     756                 :             : 
     757                 :           0 :   valent_object_lock (VALENT_OBJECT (self));
     758         [ #  # ]:           0 :   g_clear_object (&self->base_stream);
     759         [ #  # ]:           0 :   g_clear_object (&self->cancellable);
     760         [ #  # ]:           0 :   g_clear_pointer (&self->states, g_hash_table_unref);
     761                 :           0 :   valent_object_unlock (VALENT_OBJECT (self));
     762                 :             : 
     763                 :           0 :   G_OBJECT_CLASS (valent_bluez_muxer_parent_class)->finalize (object);
     764                 :           0 : }
     765                 :             : 
     766                 :             : static void
     767                 :           0 : valent_bluez_muxer_get_property (GObject    *object,
     768                 :             :                                  guint       prop_id,
     769                 :             :                                  GValue     *value,
     770                 :             :                                  GParamSpec *pspec)
     771                 :             : {
     772                 :           0 :   ValentBluezMuxer *self = VALENT_BLUEZ_MUXER (object);
     773                 :             : 
     774      [ #  #  # ]:           0 :   switch ((ValentBluezMuxerProperty)prop_id)
     775                 :             :     {
     776                 :           0 :     case PROP_BASE_STREAM:
     777                 :           0 :       g_value_set_object (value, self->base_stream);
     778                 :           0 :       break;
     779                 :             : 
     780                 :           0 :     case PROP_BUFFER_SIZE:
     781                 :           0 :       g_value_set_uint (value, self->buffer_size);
     782                 :           0 :       break;
     783                 :             : 
     784                 :           0 :     default:
     785                 :           0 :       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     786                 :             :     }
     787                 :           0 : }
     788                 :             : 
     789                 :             : static void
     790                 :           8 : valent_bluez_muxer_set_property (GObject      *object,
     791                 :             :                                  guint         prop_id,
     792                 :             :                                  const GValue *value,
     793                 :             :                                  GParamSpec   *pspec)
     794                 :             : {
     795                 :           8 :   ValentBluezMuxer *self = VALENT_BLUEZ_MUXER (object);
     796                 :             : 
     797      [ +  +  - ]:           8 :   switch ((ValentBluezMuxerProperty)prop_id)
     798                 :             :     {
     799                 :           4 :     case PROP_BASE_STREAM:
     800                 :           4 :       self->base_stream = g_value_dup_object (value);
     801                 :           4 :       break;
     802                 :             : 
     803                 :           4 :     case PROP_BUFFER_SIZE:
     804                 :           4 :       self->buffer_size = g_value_get_uint (value);
     805                 :           4 :       break;
     806                 :             : 
     807                 :           0 :     default:
     808                 :           0 :       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     809                 :             :     }
     810                 :           8 : }
     811                 :             : 
     812                 :             : static void
     813                 :           1 : valent_bluez_muxer_class_init (ValentBluezMuxerClass *klass)
     814                 :             : {
     815                 :           1 :   GObjectClass *object_class = G_OBJECT_CLASS (klass);
     816                 :           1 :   ValentObjectClass *vobject_class = VALENT_OBJECT_CLASS (klass);
     817                 :             : 
     818                 :           1 :   object_class->constructed = valent_bluez_muxer_constructed;
     819                 :           1 :   object_class->finalize = valent_bluez_muxer_finalize;
     820                 :           1 :   object_class->get_property = valent_bluez_muxer_get_property;
     821                 :           1 :   object_class->set_property = valent_bluez_muxer_set_property;
     822                 :             : 
     823                 :           1 :   vobject_class->destroy = valent_bluez_muxer_destroy;
     824                 :             : 
     825                 :             :   /**
     826                 :             :    * ValentBluezMuxer:base-stream:
     827                 :             :    *
     828                 :             :    * The `GIOStream` being wrapped.
     829                 :             :    */
     830                 :           2 :   properties [PROP_BASE_STREAM] =
     831                 :           1 :     g_param_spec_object ("base-stream", NULL, NULL,
     832                 :             :                          G_TYPE_IO_STREAM,
     833                 :             :                          (G_PARAM_READWRITE |
     834                 :             :                           G_PARAM_CONSTRUCT_ONLY |
     835                 :             :                           G_PARAM_EXPLICIT_NOTIFY |
     836                 :             :                           G_PARAM_STATIC_STRINGS));
     837                 :             : 
     838                 :             :   /**
     839                 :             :    * ValentBluezMuxer:buffer-size:
     840                 :             :    *
     841                 :             :    * Size of the input buffer allocated to each multiplex channel.
     842                 :             :    */
     843                 :           2 :   properties [PROP_BUFFER_SIZE] =
     844                 :           1 :     g_param_spec_uint ("buffer-size", NULL, NULL,
     845                 :             :                        1024, G_MAXUINT16,
     846                 :             :                        DEFAULT_BUFFER_SIZE,
     847                 :             :                        (G_PARAM_READWRITE |
     848                 :             :                         G_PARAM_CONSTRUCT_ONLY |
     849                 :             :                         G_PARAM_EXPLICIT_NOTIFY |
     850                 :             :                         G_PARAM_STATIC_STRINGS));
     851                 :             : 
     852                 :           1 :   g_object_class_install_properties (object_class, G_N_ELEMENTS (properties), properties);
     853                 :           1 : }
     854                 :             : 
     855                 :             : static void
     856                 :           4 : valent_bluez_muxer_init (ValentBluezMuxer *self)
     857                 :             : {
     858                 :           4 :   valent_object_lock (VALENT_OBJECT (self));
     859                 :           4 :   self->cancellable = g_cancellable_new ();
     860                 :           4 :   self->protocol_version = PROTOCOL_MAX;
     861                 :           4 :   self->states = g_hash_table_new_full (g_str_hash,
     862                 :             :                                         g_str_equal,
     863                 :             :                                         NULL,
     864                 :             :                                         channel_state_unref);
     865                 :           4 :   valent_object_unlock (VALENT_OBJECT (self));
     866                 :           4 : }
     867                 :             : 
     868                 :             : typedef enum
     869                 :             : {
     870                 :             :   HANDSHAKE_ENCRYPTED =     (1 << 0),
     871                 :             :   HANDSHAKE_IDENTITY_READ = (1 << 1),
     872                 :             :   HANDSHAKE_IDENTITY_SENT = (1 << 2),
     873                 :             :   HANDSHAKE_FAILED =        (1 << 3),
     874                 :             :   HANDSHAKE_COMPLETE =      (HANDSHAKE_ENCRYPTED |
     875                 :             :                              HANDSHAKE_IDENTITY_READ |
     876                 :             :                              HANDSHAKE_IDENTITY_SENT),
     877                 :             : } HandshakeFlags;
     878                 :             : 
     879                 :             : typedef struct
     880                 :             : {
     881                 :             :   GIOStream      *connection;
     882                 :             :   JsonNode       *identity;
     883                 :             :   JsonNode       *peer_identity;
     884                 :             :   HandshakeFlags  flags;
     885                 :             : } HandshakeData;
     886                 :             : 
     887                 :             : static void
     888                 :           4 : handshake_data_free (gpointer user_data)
     889                 :             : {
     890                 :           4 :   HandshakeData *data = (HandshakeData *)user_data;
     891                 :             : 
     892         [ +  - ]:           4 :   g_clear_object (&data->connection);
     893         [ +  - ]:           4 :   g_clear_pointer (&data->identity, json_node_unref);
     894         [ +  - ]:           4 :   g_clear_pointer (&data->peer_identity, json_node_unref);
     895                 :           4 :   g_free (data);
     896                 :           4 : }
     897                 :             : 
     898                 :             : static void
     899                 :           4 : handshake_task_complete (GTask *task)
     900                 :             : {
     901                 :           4 :   ValentBluezMuxer *self = g_task_get_source_object (task);
     902                 :           4 :   HandshakeData *data = g_task_get_task_data (task);
     903                 :           4 :   g_autoptr (ValentChannel) channel = NULL;
     904         [ +  - ]:           4 :   g_autoptr (GTlsCertificate) certificate = NULL;
     905   [ +  -  -  - ]:           4 :   g_autoptr (GTlsCertificate) peer_certificate = NULL;
     906                 :           4 :   const char *certificate_pem;
     907                 :           4 :   const char *peer_certificate_pem;
     908                 :           4 :   GError *error = NULL;
     909                 :             : 
     910         [ +  - ]:           4 :   if (valent_packet_get_string (data->identity, "certificate", &certificate_pem))
     911                 :             :     {
     912                 :           4 :       certificate = g_tls_certificate_new_from_pem (certificate_pem, -1, &error);
     913         [ -  + ]:           4 :       if (certificate == NULL)
     914                 :             :         {
     915                 :           0 :           g_task_return_error (task, g_steal_pointer (&error));
     916                 :           0 :           return;
     917                 :             :         }
     918                 :             :     }
     919                 :             : 
     920         [ +  - ]:           4 :   if (valent_packet_get_string (data->peer_identity, "certificate", &peer_certificate_pem))
     921                 :             :     {
     922                 :           0 :       g_autofree char *pem = NULL;
     923                 :             : 
     924                 :             :       /* Some implementations might not include the header/footer
     925                 :             :        */
     926   [ +  -  +  -  :           4 :       if (!g_str_has_prefix (peer_certificate_pem, CERTIFICATE_HEADER))
                   -  + ]
     927                 :             :         {
     928                 :           0 :           pem = g_strconcat (CERTIFICATE_HEADER,
     929                 :             :                              peer_certificate_pem,
     930                 :             :                              CERTIFICATE_FOOTER,
     931                 :             :                              NULL);
     932                 :             :         }
     933                 :             :       else
     934                 :             :         {
     935         [ -  + ]:           4 :           pem = g_strdup (peer_certificate_pem);
     936                 :             :         }
     937                 :             : 
     938                 :           4 :       peer_certificate = g_tls_certificate_new_from_pem (pem, -1, &error);
     939         [ -  + ]:           4 :       if (peer_certificate == NULL)
     940                 :             :         {
     941                 :           0 :           g_task_return_error (task, g_steal_pointer (&error));
     942                 :           0 :           return;
     943                 :             :         }
     944                 :             :     }
     945                 :             :   else
     946                 :             :     {
     947                 :           0 :       g_task_return_new_error (task,
     948                 :             :                                G_TLS_ERROR,
     949                 :             :                                G_TLS_ERROR_CERTIFICATE_REQUIRED,
     950                 :             :                                "Peer failed to send TLS certificate");
     951                 :           0 :       return;
     952                 :             :     }
     953                 :             : 
     954                 :           4 :   channel = g_object_new (VALENT_TYPE_BLUEZ_CHANNEL,
     955                 :             :                           "base-stream",      data->connection,
     956                 :             :                           "certificate",      certificate,
     957                 :             :                           "identity",         data->identity,
     958                 :             :                           "peer-certificate", peer_certificate,
     959                 :             :                           "peer-identity",    data->peer_identity,
     960                 :             :                           "muxer",            self,
     961                 :             :                           NULL);
     962                 :           4 :   g_task_return_pointer (task, g_object_ref (channel), g_object_unref);
     963                 :             : }
     964                 :             : 
     965                 :             : static void
     966                 :           4 : handshake_read_identity_cb (GInputStream *stream,
     967                 :             :                             GAsyncResult *result,
     968                 :             :                             gpointer      user_data)
     969                 :             : {
     970                 :           8 :   g_autoptr (GTask) task = G_TASK (g_steal_pointer (&user_data));
     971                 :           4 :   HandshakeData *data = g_task_get_task_data (task);
     972   [ -  -  +  - ]:           4 :   g_autoptr (JsonNode) secure_identity = NULL;
     973                 :           4 :   GError *error = NULL;
     974                 :             : 
     975                 :           4 :   secure_identity = valent_packet_from_stream_finish (stream, result, &error);
     976         [ -  + ]:           4 :   if (secure_identity == NULL)
     977                 :             :     {
     978         [ #  # ]:           0 :       if ((data->flags & HANDSHAKE_FAILED) == 0)
     979                 :             :         {
     980                 :           0 :           data->flags |= HANDSHAKE_FAILED;
     981                 :           0 :           g_task_return_error (task, g_steal_pointer (&error));
     982                 :             :         }
     983                 :             : 
     984         [ #  # ]:           0 :       return;
     985                 :             :     }
     986                 :             : 
     987         [ -  + ]:           4 :   g_clear_pointer (&data->peer_identity, json_node_unref);
     988         [ +  - ]:           4 :   data->peer_identity = g_steal_pointer (&secure_identity);
     989                 :             : 
     990                 :           4 :   data->flags |= HANDSHAKE_IDENTITY_READ;
     991         [ +  - ]:           4 :   if (data->flags == HANDSHAKE_COMPLETE)
     992                 :           4 :     handshake_task_complete (task);
     993                 :             : }
     994                 :             : 
     995                 :             : static void
     996                 :           4 : handshake_write_identity_cb (GOutputStream *stream,
     997                 :             :                              GAsyncResult  *result,
     998                 :             :                              gpointer       user_data)
     999                 :             : {
    1000                 :           8 :   g_autoptr (GTask) task = G_TASK (g_steal_pointer (&user_data));
    1001                 :           4 :   HandshakeData *data = g_task_get_task_data (task);
    1002                 :           4 :   GError *error = NULL;
    1003                 :             : 
    1004         [ -  + ]:           4 :   if (!valent_packet_to_stream_finish (stream, result, &error))
    1005                 :             :     {
    1006         [ #  # ]:           0 :       if ((data->flags & HANDSHAKE_FAILED) == 0)
    1007                 :             :         {
    1008                 :           0 :           data->flags |= HANDSHAKE_FAILED;
    1009                 :           0 :           g_task_return_error (task, g_steal_pointer (&error));
    1010                 :             :         }
    1011                 :             : 
    1012         [ #  # ]:           0 :       return;
    1013                 :             :     }
    1014                 :             : 
    1015                 :           4 :   data->flags |= HANDSHAKE_IDENTITY_SENT;
    1016         [ -  + ]:           4 :   if (data->flags == HANDSHAKE_COMPLETE)
    1017                 :           0 :     handshake_task_complete (task);
    1018                 :             : }
    1019                 :             : 
    1020                 :             : static void
    1021                 :           4 : handshake_protocol_task_cb (GObject      *object,
    1022                 :             :                             GAsyncResult *result,
    1023                 :             :                             gpointer      user_data)
    1024                 :             : {
    1025                 :           8 :   g_autoptr (GTask) task = G_TASK (g_steal_pointer (&user_data));
    1026                 :           4 :   ValentBluezMuxer *self = g_task_get_source_object (task);
    1027                 :           4 :   HandshakeData *data = g_task_get_task_data (task);
    1028                 :           4 :   GCancellable *cancellable = g_task_get_cancellable (task);
    1029   [ +  -  -  - ]:           4 :   g_autoptr (GIOStream) stream = NULL;
    1030                 :           4 :   GError *error = NULL;
    1031                 :             : 
    1032                 :           4 :   stream = g_task_propagate_pointer (G_TASK (result), &error);
    1033         [ -  + ]:           4 :   if (stream == NULL)
    1034                 :             :     {
    1035                 :           0 :       g_task_return_error (task, g_steal_pointer (&error));
    1036                 :           0 :       return;
    1037                 :             :     }
    1038                 :             : 
    1039                 :           4 :   self->input_thread = g_thread_try_new ("valent-bluez-muxer",
    1040                 :             :                                          valent_bluez_muxer_receive_loop,
    1041                 :             :                                          g_object_ref (self),
    1042                 :             :                                          &error);
    1043         [ -  + ]:           4 :   if (self->input_thread == NULL)
    1044                 :             :     {
    1045                 :           0 :       g_task_return_error (task, g_steal_pointer (&error));
    1046                 :           0 :       return;
    1047                 :             :     }
    1048                 :             : 
    1049                 :           4 :   data->connection = g_object_ref (stream);
    1050                 :           4 :   valent_packet_to_stream (g_io_stream_get_output_stream (data->connection),
    1051                 :             :                            data->identity,
    1052                 :             :                            cancellable,
    1053                 :             :                            (GAsyncReadyCallback)handshake_write_identity_cb,
    1054                 :             :                            g_object_ref (task));
    1055                 :           4 :   valent_packet_from_stream (g_io_stream_get_input_stream (data->connection),
    1056                 :             :                              IDENTITY_BUFFER_MAX,
    1057                 :             :                              cancellable,
    1058                 :             :                              (GAsyncReadyCallback)handshake_read_identity_cb,
    1059                 :             :                              g_object_ref (task));
    1060                 :             : }
    1061                 :             : 
    1062                 :             : static void
    1063                 :           4 : handshake_protocol_task (GTask        *task,
    1064                 :             :                          gpointer      source_object,
    1065                 :             :                          gpointer      task_data,
    1066                 :             :                          GCancellable *cancellable)
    1067                 :             : {
    1068                 :           4 :   ValentBluezMuxer *self = VALENT_BLUEZ_MUXER (source_object);
    1069                 :           4 :   ChannelState *state = (ChannelState *)task_data;
    1070                 :           8 :   g_autoptr (GIOStream) ret = NULL;
    1071                 :           4 :   uint16_t size_request;
    1072                 :           4 :   GError *error = NULL;
    1073                 :             : 
    1074                 :           4 :   g_mutex_lock (&state->mutex);
    1075                 :           4 :   state->read_free += state->size;
    1076                 :           4 :   size_request = state->size;
    1077                 :           4 :   ret = g_object_ref (state->stream);
    1078                 :           4 :   g_mutex_unlock (&state->mutex);
    1079                 :             : 
    1080                 :           4 :   valent_object_lock (VALENT_OBJECT (self));
    1081   [ +  -  -  + ]:           8 :   if (!send_protocol_version (self, cancellable, &error) ||
    1082                 :           4 :       !send_read (self, PRIMARY_UUID, size_request, cancellable, &error))
    1083                 :             :     {
    1084         [ #  # ]:           0 :       g_clear_object (&ret);
    1085                 :           0 :       valent_bluez_muxer_close (self, NULL, NULL);
    1086                 :             :     }
    1087                 :           4 :   valent_object_unlock (VALENT_OBJECT (self));
    1088                 :             : 
    1089         [ +  - ]:           4 :   if (ret != NULL)
    1090                 :           4 :     g_task_return_pointer (task, g_object_ref (ret), g_object_unref);
    1091                 :             :   else
    1092                 :           0 :     g_task_return_error (task, g_steal_pointer (&error));
    1093                 :           4 : }
    1094                 :             : 
    1095                 :             : /**
    1096                 :             :  * valent_bluez_muxer_handshake:
    1097                 :             :  * @muxer: a `ValentBluezMuxer`
    1098                 :             :  * @identity: a KDE Connect identity packet
    1099                 :             :  * @cancellable: (nullable): a `GCancellable`
    1100                 :             :  * @callback: (scope async): a `GAsyncReadyCallback`
    1101                 :             :  * @user_data: user supplied data
    1102                 :             :  *
    1103                 :             :  * Attempt to negotiate a multiplex channel on @muxer. This is a two-part
    1104                 :             :  * process involving negotiating the protocol version (currently only version 1)
    1105                 :             :  * and exchanging identity packets.
    1106                 :             :  *
    1107                 :             :  * Call [class@Valent.BluezMuxer.handshake_finish] to get the result.
    1108                 :             :  *
    1109                 :             :  * Returns: (transfer full): a `ValentChannel`
    1110                 :             :  */
    1111                 :             : void
    1112                 :           4 : valent_bluez_muxer_handshake (GIOStream           *base_stream,
    1113                 :             :                               JsonNode            *identity,
    1114                 :             :                               GCancellable        *cancellable,
    1115                 :             :                               GAsyncReadyCallback  callback,
    1116                 :             :                               gpointer             user_data)
    1117                 :             : {
    1118                 :           4 :   g_autoptr (ValentBluezMuxer) muxer = NULL;
    1119                 :           4 :   g_autoptr (ChannelState) state = NULL;
    1120                 :           4 :   g_autoptr (GTask) protocol = NULL;
    1121         [ +  - ]:           4 :   g_autoptr (GTask) task = NULL;
    1122                 :           4 :   HandshakeData *data = NULL;
    1123                 :             : 
    1124   [ +  -  +  -  :           4 :   g_return_if_fail (G_IS_IO_STREAM (base_stream));
             +  -  -  + ]
    1125         [ +  - ]:           4 :   g_return_if_fail (VALENT_IS_PACKET (identity));
    1126   [ +  +  +  -  :           4 :   g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
             -  +  -  - ]
    1127                 :             : 
    1128                 :           4 :   muxer = g_object_new (VALENT_TYPE_BLUEZ_MUXER,
    1129                 :             :                         "base-stream", base_stream,
    1130                 :             :                         "buffer-size", DEFAULT_BUFFER_SIZE,
    1131                 :             :                         NULL);
    1132                 :             : 
    1133                 :           4 :   valent_object_lock (VALENT_OBJECT (muxer));
    1134                 :           4 :   state = channel_state_new (muxer, PRIMARY_UUID);
    1135                 :           4 :   g_hash_table_replace (muxer->states,
    1136                 :           4 :                         state->uuid,
    1137                 :             :                         g_atomic_rc_box_acquire (state));
    1138                 :           4 :   valent_object_unlock (VALENT_OBJECT (muxer));
    1139                 :             : 
    1140                 :           4 :   data = g_new0 (HandshakeData, 1);
    1141                 :           4 :   data->identity = json_node_ref (identity);
    1142                 :           4 :   data->flags |= HANDSHAKE_ENCRYPTED;
    1143                 :             : 
    1144                 :           4 :   task = g_task_new (muxer, cancellable, callback, user_data);
    1145         [ +  - ]:           4 :   g_task_set_source_tag (task, valent_bluez_muxer_handshake);
    1146                 :           4 :   g_task_set_task_data (task, g_steal_pointer (&data), handshake_data_free);
    1147                 :             : 
    1148                 :           4 :   protocol = g_task_new (muxer, cancellable, handshake_protocol_task_cb, g_object_ref (task));
    1149         [ +  - ]:           4 :   g_task_set_source_tag (protocol, handshake_protocol_task);
    1150                 :           4 :   g_task_set_task_data (protocol, g_steal_pointer (&state), channel_state_unref);
    1151         [ +  - ]:           4 :   g_task_run_in_thread (protocol, handshake_protocol_task);
    1152                 :             : }
    1153                 :             : 
    1154                 :             : /**
    1155                 :             :  * valent_bluez_muxer_handshake_finish:
    1156                 :             :  * @muxer: a `ValentBluezMuxer`
    1157                 :             :  * @result: a `GAsyncResult`
    1158                 :             :  * @error: (nullable): a `GError`
    1159                 :             :  *
    1160                 :             :  * Finishes an operation started by [class@Valent.BluezMuxer.handshake].
    1161                 :             :  *
    1162                 :             :  * Returns: (transfer full): a `ValentChannel`
    1163                 :             :  */
    1164                 :             : ValentChannel *
    1165                 :           4 : valent_bluez_muxer_handshake_finish (ValentBluezMuxer  *muxer,
    1166                 :             :                                      GAsyncResult      *result,
    1167                 :             :                                      GError           **error)
    1168                 :             : {
    1169         [ -  + ]:           4 :   g_return_val_if_fail (VALENT_IS_BLUEZ_MUXER (muxer), NULL);
    1170         [ +  - ]:           4 :   g_return_val_if_fail (g_task_is_valid (result, muxer), NULL);
    1171   [ +  -  +  - ]:           4 :   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
    1172                 :             : 
    1173                 :           4 :   return g_task_propagate_pointer (G_TASK (result), error);
    1174                 :             : }
    1175                 :             : 
    1176                 :             : /**
    1177                 :             :  * valent_bluez_muxer_close:
    1178                 :             :  * @muxer: a `ValentBluezMuxer`
    1179                 :             :  * @cancellable: (nullable): a `GCancellable`
    1180                 :             :  * @error: (nullable): a `GError`
    1181                 :             :  *
    1182                 :             :  * Close the multiplex connection.
    1183                 :             :  *
    1184                 :             :  * Returns: %TRUE if successful, or %FALSE with @error set
    1185                 :             :  */
    1186                 :             : gboolean
    1187                 :           0 : valent_bluez_muxer_close (ValentBluezMuxer  *muxer,
    1188                 :             :                           GCancellable      *cancellable,
    1189                 :             :                           GError           **error)
    1190                 :             : {
    1191                 :           0 :   GHashTableIter iter;
    1192                 :           0 :   ChannelState *state;
    1193                 :           0 :   gboolean ret = TRUE;
    1194                 :             : 
    1195                 :           0 :   VALENT_ENTRY;
    1196                 :             : 
    1197         [ #  # ]:           0 :   g_assert (VALENT_IS_BLUEZ_MUXER (muxer));
    1198                 :             : 
    1199                 :           0 :   valent_object_lock (VALENT_OBJECT (muxer));
    1200                 :           0 :   ret = g_io_stream_close (muxer->base_stream, cancellable, error);
    1201   [ #  #  #  # ]:           0 :   if (muxer->input_thread != NULL && muxer->input_thread != g_thread_self ())
    1202                 :             :     {
    1203                 :           0 :       g_cancellable_cancel (muxer->cancellable);
    1204                 :           0 :       g_thread_join (g_steal_pointer (&muxer->input_thread));
    1205                 :             : 
    1206                 :           0 :       g_hash_table_iter_init (&iter, muxer->states);
    1207         [ #  # ]:           0 :       while (g_hash_table_iter_next (&iter, NULL, (void **)&state))
    1208                 :             :         {
    1209                 :           0 :           g_mutex_lock (&state->mutex);
    1210                 :           0 :           channel_state_close_unlocked (state, NULL);
    1211                 :           0 :           g_mutex_unlock (&state->mutex);
    1212                 :           0 :           g_hash_table_iter_remove (&iter);
    1213                 :             :         }
    1214                 :             :     }
    1215                 :           0 :   valent_object_unlock (VALENT_OBJECT (muxer));
    1216                 :             : 
    1217                 :           0 :   VALENT_RETURN (ret);
    1218                 :             : }
    1219                 :             : 
    1220                 :             : /**
    1221                 :             :  * valent_bluez_muxer_channel_accept:
    1222                 :             :  * @muxer: a `ValentBluezMuxer`
    1223                 :             :  * @uuid: a channel UUID
    1224                 :             :  * @cancellable: (nullable): a `GCancellable`
    1225                 :             :  * @error: (nullable): a `GError`
    1226                 :             :  *
    1227                 :             :  * Blocks waiting for a channel to be opened for @uuid.
    1228                 :             :  *
    1229                 :             :  * Returns: (transfer full): a `GIOStream`
    1230                 :             :  */
    1231                 :             : GIOStream *
    1232                 :           1 : valent_bluez_muxer_channel_accept (ValentBluezMuxer  *muxer,
    1233                 :             :                                    const char        *uuid,
    1234                 :             :                                    GCancellable      *cancellable,
    1235                 :             :                                    GError           **error)
    1236                 :             : {
    1237                 :           1 :   g_autoptr (ChannelState) state = NULL;
    1238                 :           1 :   GIOStream *ret = NULL;
    1239                 :             : 
    1240         [ -  + ]:           1 :   g_assert (VALENT_IS_BLUEZ_MUXER (muxer));
    1241         [ +  - ]:           1 :   g_assert (g_uuid_string_is_valid (uuid));
    1242   [ -  +  -  -  :           1 :   g_assert (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
             -  -  -  - ]
    1243   [ +  -  -  + ]:           1 :   g_assert (error == NULL || *error == NULL);
    1244                 :             : 
    1245                 :             :   /* HACK: Loop every second and check for the channel
    1246                 :             :    */
    1247         [ +  - ]:           1 :   while (!g_cancellable_set_error_if_cancelled (cancellable, error))
    1248                 :             :     {
    1249                 :           1 :       state = channel_state_lookup (muxer, uuid, NULL);
    1250         [ +  - ]:           1 :       if (state != NULL)
    1251                 :             :         {
    1252                 :           1 :           uint16_t size_request;
    1253                 :             : 
    1254                 :           1 :           g_mutex_lock (&state->mutex);
    1255                 :           1 :           state->read_free += state->size;
    1256                 :           1 :           size_request = state->size;
    1257                 :           1 :           ret = g_object_ref (state->stream);
    1258                 :           1 :           g_mutex_unlock (&state->mutex);
    1259                 :             : 
    1260                 :           1 :           valent_object_lock (VALENT_OBJECT (muxer));
    1261         [ -  + ]:           1 :           if (!send_read (muxer, uuid, size_request, cancellable, error))
    1262                 :             :             {
    1263         [ #  # ]:           0 :               g_clear_object (&ret);
    1264                 :           0 :               valent_bluez_muxer_close (muxer, NULL, NULL);
    1265                 :             :             }
    1266                 :           1 :           valent_object_unlock (VALENT_OBJECT (muxer));
    1267                 :           1 :           break;
    1268                 :             :         }
    1269                 :             : 
    1270                 :           0 :       g_usleep (G_USEC_PER_SEC);
    1271                 :             :     }
    1272                 :             : 
    1273                 :           1 :   return g_steal_pointer (&ret);
    1274                 :             : }
    1275                 :             : 
    1276                 :             : /**
    1277                 :             :  * valent_bluez_muxer_channel_close:
    1278                 :             :  * @muxer: a `ValentBluezMuxer`
    1279                 :             :  * @uuid: a channel UUID
    1280                 :             :  * @cancellable: (nullable): a `GCancellable`
    1281                 :             :  * @error: (nullable): a `GError`
    1282                 :             :  *
    1283                 :             :  * Close the stream for the channel with @uuid associated with the
    1284                 :             :  * condition for @condition.
    1285                 :             :  *
    1286                 :             :  * Returns: %TRUE, or %FALSE with @error set
    1287                 :             :  */
    1288                 :             : gboolean
    1289                 :          10 : valent_bluez_muxer_channel_close (ValentBluezMuxer  *muxer,
    1290                 :             :                                   const char        *uuid,
    1291                 :             :                                   GCancellable      *cancellable,
    1292                 :             :                                   GError           **error)
    1293                 :             : {
    1294                 :          10 :   g_autoptr (ChannelState) state = NULL;
    1295                 :          10 :   gboolean ret = TRUE;
    1296                 :             : 
    1297         [ -  + ]:          10 :   g_assert (VALENT_IS_BLUEZ_MUXER (muxer));
    1298         [ +  - ]:          10 :   g_assert (g_uuid_string_is_valid (uuid));
    1299   [ -  +  -  -  :          10 :   g_assert (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
             -  -  -  - ]
    1300   [ +  +  +  - ]:          10 :   g_assert (error == NULL || *error == NULL);
    1301                 :             : 
    1302                 :          10 :   state = channel_state_lookup (muxer, uuid, error);
    1303         [ +  - ]:          10 :   if (state == NULL)
    1304                 :             :     return FALSE;
    1305                 :             : 
    1306                 :          10 :   valent_object_lock (VALENT_OBJECT (muxer));
    1307                 :          10 :   ret = send_close_channel (muxer, uuid, cancellable, error);
    1308   [ +  +  -  + ]:          10 :   if (error != NULL && *error != NULL)
    1309                 :           6 :     error = NULL;
    1310                 :          10 :   valent_object_unlock (VALENT_OBJECT (muxer));
    1311                 :             : 
    1312                 :          10 :   g_mutex_lock (&state->mutex);
    1313         [ +  + ]:          10 :   if ((state->condition & (G_IO_HUP | G_IO_ERR)) == 0)
    1314                 :             :     {
    1315                 :           3 :       ret |= channel_state_close_unlocked (state, error);
    1316                 :             :     }
    1317                 :          10 :   g_mutex_unlock (&state->mutex);
    1318                 :             : 
    1319                 :          10 :   return ret;
    1320                 :             : }
    1321                 :             : 
    1322                 :             : /**
    1323                 :             :  * valent_bluez_muxer_channel_flush:
    1324                 :             :  * @muxer: a `ValentBluezMuxer`
    1325                 :             :  * @uuid: a channel UUID
    1326                 :             :  * @cancellable: (nullable): a `GCancellable`
    1327                 :             :  * @error: (nullable): a `GError`
    1328                 :             :  *
    1329                 :             :  * Flush the streams by notifying any pollable sources or waiting threads
    1330                 :             :  * of a condition change.
    1331                 :             :  *
    1332                 :             :  * Returns: %TRUE, or %FALSE with @error set
    1333                 :             :  */
    1334                 :             : gboolean
    1335                 :           5 : valent_bluez_muxer_channel_flush (ValentBluezMuxer  *muxer,
    1336                 :             :                                   const char        *uuid,
    1337                 :             :                                   GCancellable      *cancellable,
    1338                 :             :                                   GError           **error)
    1339                 :             : {
    1340                 :           5 :   g_autoptr (ChannelState) state = NULL;
    1341                 :           5 :   gboolean ret;
    1342                 :             : 
    1343         [ -  + ]:           5 :   g_assert (VALENT_IS_BLUEZ_MUXER (muxer));
    1344         [ +  - ]:           5 :   g_assert (g_uuid_string_is_valid (uuid));
    1345   [ -  +  -  -  :           5 :   g_assert (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
             -  -  -  - ]
    1346   [ +  +  +  - ]:           5 :   g_assert (error == NULL || *error == NULL);
    1347                 :             : 
    1348                 :           5 :   state = channel_state_lookup (muxer, uuid, error);
    1349         [ +  - ]:           5 :   if (state == NULL)
    1350                 :             :     return FALSE;
    1351                 :             : 
    1352                 :           5 :   g_mutex_lock (&state->mutex);
    1353                 :           5 :   ret = channel_state_flush_unlocked (state, error);
    1354                 :           5 :   g_mutex_unlock (&state->mutex);
    1355                 :             : 
    1356                 :           5 :   return ret;
    1357                 :             : }
    1358                 :             : 
    1359                 :             : /**
    1360                 :             :  * valent_bluez_muxer_channel_open:
    1361                 :             :  * @muxer: a `ValentBluezMuxer`
    1362                 :             :  * @uuid: a channel UUID
    1363                 :             :  * @cancellable: (nullable): a `GCancellable`
    1364                 :             :  * @error: (nullable): a `GError`
    1365                 :             :  *
    1366                 :             :  * Attempt to open a muxed channel for @uuid.
    1367                 :             :  *
    1368                 :             :  * Returns: (transfer full): a `GIOStream`
    1369                 :             :  */
    1370                 :             : GIOStream *
    1371                 :           1 : valent_bluez_muxer_channel_open (ValentBluezMuxer  *muxer,
    1372                 :             :                                  const char        *uuid,
    1373                 :             :                                  GCancellable      *cancellable,
    1374                 :             :                                  GError           **error)
    1375                 :             : {
    1376                 :           1 :   g_autoptr (ChannelState) state = NULL;
    1377                 :           1 :   uint16_t size_request;
    1378                 :           1 :   GIOStream *ret = NULL;
    1379                 :             : 
    1380         [ -  + ]:           1 :   g_assert (VALENT_IS_BLUEZ_MUXER (muxer));
    1381         [ +  - ]:           1 :   g_assert (g_uuid_string_is_valid (uuid));
    1382   [ -  +  -  -  :           1 :   g_assert (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
             -  -  -  - ]
    1383   [ +  -  +  - ]:           1 :   g_assert (error == NULL || *error == NULL);
    1384                 :             : 
    1385                 :           1 :   valent_object_lock (VALENT_OBJECT (muxer));
    1386         [ -  + ]:           1 :   if (g_hash_table_contains (muxer->states, uuid))
    1387                 :             :     {
    1388                 :           0 :       g_set_error (error,
    1389                 :             :                    G_IO_ERROR,
    1390                 :             :                    G_IO_ERROR_ADDRESS_IN_USE,
    1391                 :             :                    "Channel already open (%s)",
    1392                 :             :                    uuid);
    1393                 :             :     }
    1394                 :             :   else
    1395                 :             :     {
    1396                 :           1 :       state = channel_state_new (muxer, uuid);
    1397                 :           1 :       g_hash_table_replace (muxer->states,
    1398                 :           1 :                             state->uuid,
    1399                 :             :                             g_atomic_rc_box_acquire (state));
    1400                 :             : 
    1401                 :           1 :       g_mutex_lock (&state->mutex);
    1402                 :           1 :       state->read_free += state->size;
    1403                 :           1 :       size_request = state->size;
    1404                 :           1 :       ret = g_object_ref (state->stream);
    1405                 :           1 :       g_mutex_unlock (&state->mutex);
    1406                 :             : 
    1407   [ +  -  -  + ]:           2 :       if (!send_open_channel (muxer, uuid, cancellable, error) ||
    1408                 :           1 :           !send_read (muxer, uuid, size_request, cancellable, error))
    1409                 :             :         {
    1410         [ #  # ]:           0 :           g_clear_object (&ret);
    1411                 :           0 :           valent_bluez_muxer_close (muxer, NULL, NULL);
    1412                 :             :         }
    1413                 :             :     }
    1414                 :           1 :   valent_object_unlock (VALENT_OBJECT (muxer));
    1415                 :             : 
    1416                 :           1 :   return g_steal_pointer (&ret);
    1417                 :             : }
    1418                 :             : 
    1419                 :             : /**
    1420                 :             :  * valent_bluez_muxer_channel_read:
    1421                 :             :  * @muxer: a `ValentBluezMuxer`
    1422                 :             :  * @uuid: a channel UUID
    1423                 :             :  * @buffer: a buffer to read data into
    1424                 :             :  * @count: the number of bytes that will be read from the stream
    1425                 :             :  * @blocking: whether to do blocking or non-blocking I/O
    1426                 :             :  * @cancellable: (nullable): a `GCancellable`
    1427                 :             :  * @error: (nullable): a `GError`
    1428                 :             :  *
    1429                 :             :  * Tries to read count bytes from the channel @uuid into the buffer starting at
    1430                 :             :  * @buffer.
    1431                 :             :  *
    1432                 :             :  * If @blocking is %TRUE, this function will block during the operation,
    1433                 :             :  * otherwise it may return `G_IO_ERROR_WOULD_BLOCK`.
    1434                 :             :  *
    1435                 :             :  * This is used by `ValentMuxInputStream` to implement g_input_stream_read().
    1436                 :             :  *
    1437                 :             :  * Returns: number of bytes read, or -1 on error, or 0 on end of file
    1438                 :             :  */
    1439                 :             : gssize
    1440                 :        3888 : valent_bluez_muxer_channel_read (ValentBluezMuxer  *muxer,
    1441                 :             :                                  const char        *uuid,
    1442                 :             :                                  void              *buffer,
    1443                 :             :                                  size_t             count,
    1444                 :             :                                  gboolean           blocking,
    1445                 :             :                                  GCancellable      *cancellable,
    1446                 :             :                                  GError           **error)
    1447                 :             : {
    1448                 :        3888 :   g_autoptr (ChannelState) state = NULL;
    1449                 :        3888 :   gssize read;
    1450                 :        3888 :   uint16_t size_request = 0;
    1451                 :             : 
    1452         [ -  + ]:        3888 :   g_assert (VALENT_IS_BLUEZ_MUXER (muxer));
    1453         [ +  - ]:        3888 :   g_assert (g_uuid_string_is_valid (uuid));
    1454   [ +  +  +  -  :        3888 :   g_assert (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
             -  +  -  - ]
    1455   [ +  -  +  - ]:        3888 :   g_assert (error == NULL || *error == NULL);
    1456                 :             : 
    1457                 :        3888 :   state = channel_state_lookup (muxer, uuid, error);
    1458         [ -  + ]:        3888 :   if (state == NULL)
    1459                 :             :     return -1;
    1460                 :             : 
    1461                 :        3888 :   g_mutex_lock (&state->mutex);
    1462         [ +  + ]:        3888 :   if ((state->condition & (G_IO_HUP | G_IO_ERR)) != 0)
    1463                 :             :     {
    1464                 :           1 :       read = channel_state_read_unlocked (state, buffer, count, error);
    1465                 :           1 :       g_mutex_unlock (&state->mutex);
    1466                 :           1 :       return read;
    1467                 :             :     }
    1468                 :             : 
    1469         [ +  + ]:        3887 :   if (blocking)
    1470                 :             :     {
    1471         [ +  + ]:        3884 :       while ((state->condition & (G_IO_IN | G_IO_HUP | G_IO_ERR)) == 0)
    1472                 :             :         {
    1473         [ -  + ]:           6 :           if (g_cancellable_set_error_if_cancelled (cancellable, error))
    1474                 :             :             {
    1475                 :           0 :               g_mutex_unlock (&state->mutex);
    1476                 :           0 :               return -1;
    1477                 :             :             }
    1478                 :             : 
    1479                 :           6 :           g_cond_wait (&state->cond, &state->mutex);
    1480                 :             :         }
    1481                 :             :     }
    1482         [ +  + ]:           9 :   else if ((state->condition & G_IO_IN) == 0)
    1483                 :             :     {
    1484                 :           6 :       g_set_error_literal (error,
    1485                 :             :                            G_IO_ERROR,
    1486                 :             :                            G_IO_ERROR_WOULD_BLOCK,
    1487                 :             :                            g_strerror (EAGAIN));
    1488                 :           6 :       g_mutex_unlock (&state->mutex);
    1489                 :           6 :       return -1;
    1490                 :             :     }
    1491                 :             : 
    1492                 :        3881 :   read = channel_state_read_unlocked (state, buffer, count, error);
    1493         [ -  + ]:        3881 :   if (read < 1)
    1494                 :             :     {
    1495                 :           0 :       g_mutex_unlock (&state->mutex);
    1496                 :           0 :       return read;
    1497                 :             :     }
    1498                 :             : 
    1499                 :        3881 :   size_request = (state->size - state->count) - state->read_free;
    1500         [ -  + ]:        3881 :   if ((double)size_request < state->size * 0.5)
    1501                 :             :     size_request = 0;
    1502                 :             :   else
    1503                 :           0 :     state->read_free += size_request;
    1504                 :        3881 :   g_mutex_unlock (&state->mutex);
    1505                 :             : 
    1506                 :             :   /* Any failure sending a multiplex message closes the connection,
    1507                 :             :    * but the buffer may be emptied after G_IO_HUP
    1508                 :             :    */
    1509         [ +  - ]:        3881 :   if (size_request > 0)
    1510                 :             :     {
    1511                 :           0 :       valent_object_lock (VALENT_OBJECT (muxer));
    1512         [ #  # ]:           0 :       if (!send_read (muxer, uuid, size_request, cancellable, error))
    1513                 :           0 :         valent_bluez_muxer_close (muxer, NULL, NULL);
    1514                 :           0 :       valent_object_unlock (VALENT_OBJECT (muxer));
    1515                 :             :     }
    1516                 :             : 
    1517                 :             :   return read;
    1518                 :             : }
    1519                 :             : 
    1520                 :             : /**
    1521                 :             :  * valent_bluez_muxer_channel_write:
    1522                 :             :  * @muxer: a `ValentBluezMuxer`
    1523                 :             :  * @uuid: a channel UUID
    1524                 :             :  * @buffer: data to write
    1525                 :             :  * @count: size of the write
    1526                 :             :  * @blocking: whether to do blocking or non-blocking I/O
    1527                 :             :  * @cancellable: (nullable): a `GCancellable`
    1528                 :             :  * @error: (nullable): a `GError`
    1529                 :             :  *
    1530                 :             :  * Tries to write @count bytes from @buffer into the stream for @uuid.
    1531                 :             :  *
    1532                 :             :  * If @blocking is %TRUE, this function will block during the operation,
    1533                 :             :  * otherwise it may return `G_IO_ERROR_WOULD_BLOCK`.
    1534                 :             :  *
    1535                 :             :  * This is used by `ValentMuxOutputStream` to implement g_output_stream_write().
    1536                 :             :  *
    1537                 :             :  * Returns: number of bytes written, or -1 with @error set
    1538                 :             :  */
    1539                 :             : gssize
    1540                 :          12 : valent_bluez_muxer_channel_write (ValentBluezMuxer  *muxer,
    1541                 :             :                                   const char        *uuid,
    1542                 :             :                                   const void        *buffer,
    1543                 :             :                                   size_t             count,
    1544                 :             :                                   gboolean           blocking,
    1545                 :             :                                   GCancellable      *cancellable,
    1546                 :             :                                   GError           **error)
    1547                 :             : {
    1548                 :          12 :   g_autoptr (ChannelState) state = NULL;
    1549                 :          12 :   gssize written;
    1550                 :             : 
    1551         [ -  + ]:          12 :   g_assert (VALENT_IS_BLUEZ_MUXER (muxer));
    1552         [ +  - ]:          12 :   g_assert (g_uuid_string_is_valid (uuid));
    1553   [ -  +  -  -  :          12 :   g_assert (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
             -  -  -  - ]
    1554   [ +  -  +  - ]:          12 :   g_assert (error == NULL || *error == NULL);
    1555                 :             : 
    1556                 :          12 :   state = channel_state_lookup (muxer, uuid, error);
    1557         [ -  + ]:          12 :   if (state == NULL)
    1558                 :             :     return -1;
    1559                 :             : 
    1560                 :          12 :   g_mutex_lock (&state->mutex);
    1561         [ -  + ]:          12 :   if ((state->condition & (G_IO_HUP | G_IO_ERR)) != 0)
    1562                 :             :     {
    1563                 :           0 :       g_set_error_literal (error,
    1564                 :             :                            G_IO_ERROR,
    1565                 :             :                            G_IO_ERROR_CLOSED,
    1566                 :             :                            g_strerror (EPIPE));
    1567                 :           0 :       g_mutex_unlock (&state->mutex);
    1568                 :           0 :       return -1;
    1569                 :             :     }
    1570                 :             : 
    1571         [ -  + ]:          12 :   if (blocking)
    1572                 :             :     {
    1573         [ #  # ]:           0 :       while ((state->condition & (G_IO_OUT | G_IO_HUP | G_IO_ERR)) == 0)
    1574                 :             :         {
    1575         [ #  # ]:           0 :           if (g_cancellable_set_error_if_cancelled (cancellable, error))
    1576                 :             :             {
    1577                 :           0 :               g_mutex_unlock (&state->mutex);
    1578                 :           0 :               return -1;
    1579                 :             :             }
    1580                 :             : 
    1581                 :           0 :           g_cond_wait (&state->cond, &state->mutex);
    1582                 :             :         }
    1583                 :             : 
    1584         [ #  # ]:           0 :       if ((state->condition & (G_IO_HUP | G_IO_ERR)) != 0)
    1585                 :             :         {
    1586                 :           0 :           g_set_error_literal (error,
    1587                 :             :                                G_IO_ERROR,
    1588                 :             :                                G_IO_ERROR_CLOSED,
    1589                 :             :                                g_strerror (EPIPE));
    1590                 :           0 :           g_mutex_unlock (&state->mutex);
    1591                 :           0 :           return -1;
    1592                 :             :         }
    1593                 :             :     }
    1594         [ +  + ]:          12 :   else if ((state->condition & G_IO_OUT) == 0)
    1595                 :             :     {
    1596                 :           5 :       g_set_error_literal (error,
    1597                 :             :                            G_IO_ERROR,
    1598                 :             :                            G_IO_ERROR_WOULD_BLOCK,
    1599                 :             :                            g_strerror (EAGAIN));
    1600                 :           5 :       g_mutex_unlock (&state->mutex);
    1601                 :           5 :       return -1;
    1602                 :             :     }
    1603                 :             : 
    1604                 :           7 :   written = MIN (count, state->write_free);
    1605                 :           7 :   state->write_free -= written;
    1606         [ -  + ]:           7 :   if (state->write_free == 0)
    1607                 :           0 :     state->condition &= ~G_IO_OUT;
    1608                 :           7 :   g_mutex_unlock (&state->mutex);
    1609                 :             : 
    1610                 :             :   /* Any failure sending a multiplex message closes the connection
    1611                 :             :    */
    1612                 :           7 :   valent_object_lock (VALENT_OBJECT (muxer));
    1613         [ -  + ]:           7 :   if (!send_write (muxer, uuid, written, buffer, cancellable, error))
    1614                 :             :     {
    1615                 :           0 :       valent_bluez_muxer_close (muxer, NULL, NULL);
    1616                 :           0 :       written = -1;
    1617                 :             :     }
    1618                 :           7 :   valent_object_unlock (VALENT_OBJECT (muxer));
    1619                 :             : 
    1620                 :           7 :   return written;
    1621                 :             : }
    1622                 :             : 
    1623                 :             : static gboolean
    1624                 :           0 : broken_dispatch (GSource     *source,
    1625                 :             :                  GSourceFunc  callback,
    1626                 :             :                  gpointer     user_data)
    1627                 :             : {
    1628                 :           0 :   return TRUE;
    1629                 :             : }
    1630                 :             : 
    1631                 :             : static GSourceFuncs broken_funcs =
    1632                 :             : {
    1633                 :             :   .dispatch = broken_dispatch,
    1634                 :             : };
    1635                 :             : 
    1636                 :             : typedef struct
    1637                 :             : {
    1638                 :             :   GSource       source;
    1639                 :             :   ChannelState *state;
    1640                 :             :   GIOCondition  condition;
    1641                 :             :   gpointer      eventfd_tag;
    1642                 :             : } ValentMuxerSource;
    1643                 :             : 
    1644                 :             : static gboolean
    1645                 :          64 : muxer_stream_source_prepare (GSource *source,
    1646                 :             :                              int     *timeout)
    1647                 :             : {
    1648                 :          64 :   ValentMuxerSource *stream_source = (ValentMuxerSource *)source;
    1649                 :          64 :   ChannelState *state = stream_source->state;
    1650                 :          64 :   gboolean ret = FALSE;
    1651                 :             : 
    1652                 :          64 :   g_mutex_lock (&state->mutex);
    1653                 :          64 :   ret = (state->condition & stream_source->condition) != 0;
    1654                 :          64 :   g_mutex_unlock (&state->mutex);
    1655                 :             : 
    1656         [ +  + ]:          64 :   if (ret)
    1657                 :           7 :     *timeout = 0;
    1658                 :             : 
    1659                 :          64 :   return ret;
    1660                 :             : }
    1661                 :             : 
    1662                 :             : static gboolean
    1663                 :          57 : muxer_stream_source_check (GSource *source)
    1664                 :             : {
    1665                 :          57 :   ValentMuxerSource *stream_source = (ValentMuxerSource *)source;
    1666                 :          57 :   ChannelState *state = stream_source->state;
    1667                 :          57 :   gboolean ret = FALSE;
    1668                 :          57 :   uint64_t buf;
    1669                 :             : 
    1670                 :          57 :   g_mutex_lock (&state->mutex);
    1671                 :          57 :   ret = (state->condition & stream_source->condition) != 0;
    1672         [ +  + ]:          57 :   if (read (state->eventfd, &buf, sizeof (uint64_t)) == -1)
    1673                 :             :     {
    1674         [ -  + ]:          53 :       if (errno != EAGAIN && errno != EWOULDBLOCK)
    1675                 :             :         {
    1676                 :           0 :           g_critical ("%s(): %s", G_STRFUNC, g_strerror (errno));
    1677                 :           0 :           ret = FALSE;
    1678                 :             :         }
    1679                 :             :     }
    1680                 :          57 :   g_mutex_unlock (&state->mutex);
    1681                 :             : 
    1682                 :          57 :   return ret;
    1683                 :             : }
    1684                 :             : 
    1685                 :             : static gboolean
    1686                 :          11 : muxer_stream_source_dispatch (GSource     *source,
    1687                 :             :                               GSourceFunc  callback,
    1688                 :             :                               gpointer     user_data)
    1689                 :             : {
    1690         [ +  - ]:          11 :   if (callback != NULL)
    1691                 :          11 :     return callback (user_data);
    1692                 :             : 
    1693                 :             :   return G_SOURCE_REMOVE;
    1694                 :             : }
    1695                 :             : 
    1696                 :             : static void
    1697                 :          11 : muxer_stream_source_finalize (GSource *source)
    1698                 :             : {
    1699                 :          11 :   ValentMuxerSource *stream_source = (ValentMuxerSource *)source;
    1700                 :             : 
    1701         [ +  - ]:          11 :   g_clear_pointer (&stream_source->state, channel_state_unref);
    1702                 :          11 : }
    1703                 :             : 
    1704                 :             : static gboolean
    1705                 :          11 : muxer_stream_source_closure_callback (gpointer data)
    1706                 :             : {
    1707                 :          11 :   GClosure *closure = (GClosure *)data;
    1708                 :          11 :   GValue result_value = G_VALUE_INIT;
    1709                 :          11 :   gboolean result;
    1710                 :             : 
    1711                 :          11 :   g_value_init (&result_value, G_TYPE_BOOLEAN);
    1712                 :          11 :   g_closure_invoke (closure, &result_value, 0, NULL, NULL);
    1713                 :          11 :   result = g_value_get_boolean (&result_value);
    1714                 :          11 :   g_value_unset (&result_value);
    1715                 :             : 
    1716                 :          11 :   return result;
    1717                 :             : }
    1718                 :             : 
    1719                 :             : static GSourceFuncs muxer_stream_source_funcs =
    1720                 :             : {
    1721                 :             :   .prepare = muxer_stream_source_prepare,
    1722                 :             :   .check = muxer_stream_source_check,
    1723                 :             :   .dispatch = muxer_stream_source_dispatch,
    1724                 :             :   .finalize = muxer_stream_source_finalize,
    1725                 :             :   .closure_callback = muxer_stream_source_closure_callback,
    1726                 :             :   NULL,
    1727                 :             : };
    1728                 :             : 
    1729                 :             : /**
    1730                 :             :  * valent_bluez_muxer_create_source:
    1731                 :             :  * @muxer: a `ValentBluezMuxer`
    1732                 :             :  * @uuid: a channel UUID
    1733                 :             :  * @condition: a `GIOCondition`
    1734                 :             :  *
    1735                 :             :  * Create a [type@GLib.Source].
    1736                 :             :  *
    1737                 :             :  * Returns: (transfer full) (nullable): a new `GSource`
    1738                 :             :  */
    1739                 :             : GSource *
    1740                 :          11 : valent_bluez_muxer_create_source (ValentBluezMuxer *muxer,
    1741                 :             :                                   const char       *uuid,
    1742                 :             :                                   GIOCondition      condition)
    1743                 :             : {
    1744                 :          11 :   g_autoptr (ChannelState) state = NULL;
    1745                 :          11 :   GSource *source = NULL;
    1746                 :          11 :   ValentMuxerSource *stream_source;
    1747                 :             : 
    1748         [ -  + ]:          11 :   g_assert (VALENT_IS_BLUEZ_MUXER (muxer));
    1749         [ +  - ]:          11 :   g_assert (g_uuid_string_is_valid (uuid));
    1750                 :             : 
    1751                 :          11 :   state = channel_state_lookup (muxer, uuid, NULL);
    1752         [ -  + ]:          11 :   if (state == NULL)
    1753                 :           0 :     return g_source_new (&broken_funcs, sizeof (GSource));
    1754                 :             : 
    1755                 :          11 :   source = g_source_new (&muxer_stream_source_funcs, sizeof (ValentMuxerSource));
    1756                 :          11 :   g_source_set_static_name (source, "ValentMuxerSource");
    1757                 :             : 
    1758                 :          11 :   stream_source = (ValentMuxerSource *) source;
    1759                 :          11 :   stream_source->state = g_atomic_rc_box_acquire (state);
    1760                 :          11 :   stream_source->condition = condition;
    1761                 :          22 :   stream_source->eventfd_tag = g_source_add_unix_fd (source,
    1762                 :          11 :                                                      state->eventfd,
    1763                 :             :                                                      G_IO_IN);
    1764                 :             : 
    1765                 :          11 :   return g_steal_pointer (&source);
    1766                 :             : }
    1767                 :             : 
    1768                 :             : /**
    1769                 :             :  * valent_bluez_muxer_condition_check:
    1770                 :             :  * @muxer: a `ValentBluezMuxer`
    1771                 :             :  * @uuid: a channel UUID
    1772                 :             :  * @condition: a `GIOCondition` mask to check
    1773                 :             :  *
    1774                 :             :  * Checks on the readiness of the channel for @uuid to perform operations. The
    1775                 :             :  * operations specified in @condition are checked for and masked against the
    1776                 :             :  * currently-satisfied conditions.
    1777                 :             :  *
    1778                 :             :  * Returns: the `GIOCondition` mask of the current state
    1779                 :             :  */
    1780                 :             : GIOCondition
    1781                 :           0 : valent_bluez_muxer_condition_check (ValentBluezMuxer *muxer,
    1782                 :             :                                     const char       *uuid,
    1783                 :             :                                     GIOCondition      condition)
    1784                 :             : {
    1785                 :           0 :   g_autoptr (ChannelState) state = NULL;
    1786                 :           0 :   GIOCondition ret = 0;
    1787                 :             : 
    1788         [ #  # ]:           0 :   g_assert (VALENT_IS_BLUEZ_MUXER (muxer));
    1789         [ #  # ]:           0 :   g_assert (g_uuid_string_is_valid (uuid));
    1790                 :             : 
    1791                 :           0 :   state = channel_state_lookup (muxer, uuid, NULL);
    1792         [ #  # ]:           0 :   if (state == NULL)
    1793                 :             :     return G_IO_ERR;
    1794                 :             : 
    1795                 :           0 :   g_mutex_lock (&state->mutex);
    1796                 :           0 :   ret = state->condition & condition;
    1797                 :           0 :   g_mutex_unlock (&state->mutex);
    1798                 :             : 
    1799                 :           0 :   return ret;
    1800                 :             : }
    1801                 :             : 
        

Generated by: LCOV version 2.0-1