LCOV - code coverage report
Current view: top level - libmogwai-schedule - connection-monitor-nm.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 0 344 0.0 %
Date: 2022-06-30 20:59:16 Functions: 0 43 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 182 0.0 %

           Branch data     Line data    Source code
       1                 :            : /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
       2                 :            :  *
       3                 :            :  * Copyright © 2018 Endless Mobile, Inc.
       4                 :            :  *
       5                 :            :  * This library is free software; you can redistribute it and/or
       6                 :            :  * modify it under the terms of the GNU Lesser General Public
       7                 :            :  * License as published by the Free Software Foundation; either
       8                 :            :  * version 2.1 of the License, or (at your option) any later version.
       9                 :            :  *
      10                 :            :  * This library is distributed in the hope that it will be useful,
      11                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      12                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13                 :            :  * Lesser General Public License for more details.
      14                 :            :  *
      15                 :            :  * You should have received a copy of the GNU Lesser General Public
      16                 :            :  * License along with this library; if not, write to the Free Software
      17                 :            :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
      18                 :            :  *
      19                 :            :  * Authors:
      20                 :            :  *  - Philip Withnall <withnall@endlessm.com>
      21                 :            :  */
      22                 :            : 
      23                 :            : #include "config.h"
      24                 :            : 
      25                 :            : #include <glib.h>
      26                 :            : #include <glib-object.h>
      27                 :            : #include <glib/gi18n-lib.h>
      28                 :            : #include <gio/gio.h>
      29                 :            : #include <libmogwai-schedule/connection-monitor.h>
      30                 :            : #include <libmogwai-schedule/connection-monitor-nm.h>
      31                 :            : #include <libmogwai-tariff/tariff-loader.h>
      32                 :            : #include <libmogwai-tariff/tariff.h>
      33                 :            : #include <NetworkManager.h>
      34                 :            : 
      35                 :            : 
      36                 :            : static void mws_connection_monitor_nm_connection_monitor_init (MwsConnectionMonitorInterface *iface);
      37                 :            : static void mws_connection_monitor_nm_initable_init           (GInitableIface                *iface);
      38                 :            : static void mws_connection_monitor_nm_async_initable_init     (GAsyncInitableIface           *iface);
      39                 :            : static void mws_connection_monitor_nm_dispose                 (GObject                       *object);
      40                 :            : 
      41                 :            : static void mws_connection_monitor_nm_get_property (GObject      *object,
      42                 :            :                                                     guint         property_id,
      43                 :            :                                                     GValue        *value,
      44                 :            :                                                     GParamSpec   *pspec);
      45                 :            : static void mws_connection_monitor_nm_set_property (GObject      *object,
      46                 :            :                                                     guint         property_id,
      47                 :            :                                                     const GValue *value,
      48                 :            :                                                     GParamSpec   *pspec);
      49                 :            : 
      50                 :            : static void active_connection_added_cb           (NMClient           *client,
      51                 :            :                                                   NMActiveConnection *active_connection,
      52                 :            :                                                   gpointer            user_data);
      53                 :            : static void active_connection_removed_cb         (NMClient           *client,
      54                 :            :                                                   NMActiveConnection *active_connection,
      55                 :            :                                                   gpointer            user_data);
      56                 :            : static void active_connection_notify_cb          (GObject            *obj,
      57                 :            :                                                   GParamSpec         *pspec,
      58                 :            :                                                   gpointer            user_data);
      59                 :            : static void active_connection_state_changed_cb   (NMActiveConnection *active_connection,
      60                 :            :                                                   guint               new_state,
      61                 :            :                                                   guint               reason,
      62                 :            :                                                   gpointer            user_data);
      63                 :            : static void device_added_cb                      (NMClient           *client,
      64                 :            :                                                   NMDevice           *device,
      65                 :            :                                                   gpointer            user_data);
      66                 :            : static void device_removed_cb                    (NMClient           *client,
      67                 :            :                                                   NMDevice           *device,
      68                 :            :                                                   gpointer            user_data);
      69                 :            : static void device_state_changed_cb              (NMDevice           *device,
      70                 :            :                                                   guint               new_state,
      71                 :            :                                                   guint               old_state,
      72                 :            :                                                   guint               reason,
      73                 :            :                                                   gpointer            user_data);
      74                 :            : static void device_notify_cb                     (GObject            *obj,
      75                 :            :                                                   GParamSpec         *pspec,
      76                 :            :                                                   gpointer            user_data);
      77                 :            : static void connection_changed_cb                (NMConnection       *connection,
      78                 :            :                                                   gpointer            user_data);
      79                 :            : 
      80                 :            : static gboolean mws_connection_monitor_nm_init_failable (GInitable            *initable,
      81                 :            :                                                          GCancellable         *cancellable,
      82                 :            :                                                          GError              **error);
      83                 :            : static void     mws_connection_monitor_nm_init_async    (GAsyncInitable       *initable,
      84                 :            :                                                          int                   io_priority,
      85                 :            :                                                          GCancellable         *cancellable,
      86                 :            :                                                          GAsyncReadyCallback   callback,
      87                 :            :                                                          gpointer              user_data);
      88                 :            : static gboolean mws_connection_monitor_nm_init_finish   (GAsyncInitable       *initable,
      89                 :            :                                                          GAsyncResult         *result,
      90                 :            :                                                          GError              **error);
      91                 :            : 
      92                 :            : static const gchar * const *mws_connection_monitor_nm_get_connection_ids     (MwsConnectionMonitor *monitor);
      93                 :            : static gboolean             mws_connection_monitor_nm_get_connection_details (MwsConnectionMonitor *monitor,
      94                 :            :                                                                               const gchar          *id,
      95                 :            :                                                                               MwsConnectionDetails *out_details);
      96                 :            : 
      97                 :            : /**
      98                 :            :  * MwsConnectionMonitorNm:
      99                 :            :  *
     100                 :            :  * An implementation of the #MwsConnectionMonitor interface which draws its data
     101                 :            :  * from the NetworkManager D-Bus interface. This implementation is
     102                 :            :  * #GAsyncInitable, and must be initialised asynchronously to connect to D-Bus
     103                 :            :  * without blocking.
     104                 :            :  *
     105                 :            :  * The metered status of each connection (#MwsConnectionDetails.metered) is
     106                 :            :  * calculated as the pessimisic combination of the metered status of each
     107                 :            :  * #NMDevice and #NMSettingConnection associated with that active connection.
     108                 :            :  *
     109                 :            :  * Several settings from #NMSettingUser are read for each active connection:
     110                 :            :  *
     111                 :            :  *  * `connection.allow-downloads` (boolean): If `1`, big downloads are allowed
     112                 :            :  *    on this connection. If `0`, they are not, and Mogwai will never schedule
     113                 :            :  *    downloads on this connection. (Default: `1`.)
     114                 :            :  *  * `connection.allow-downloads-when-metered` (boolean): If `1`, big downloads
     115                 :            :  *    may be scheduled on this connection, iff it is not metered. If the
     116                 :            :  *    connection is metered, or if this setting is `0`, Mogwai will not schedule
     117                 :            :  *    downloads on this connection. (Default: `0`.)
     118                 :            :  *  * `connection.tariff-enabled` (boolean): If `1`, the tariff string in
     119                 :            :  *    `connection.tariff` is parsed and used (and must be present). If `0`, it
     120                 :            :  *    is not. (Default: `0`.)
     121                 :            :  *  * `connection.tariff` (string): A serialised tariff (see
     122                 :            :  *    mwt_tariff_builder_get_tariff_as_variant()) which specifies how the
     123                 :            :  *    connection’s properties change over time (for example, bandwidth limits
     124                 :            :  *    at certain times of day, or capacity limits). (Default: unset.)
     125                 :            :  *
     126                 :            :  * Since: 0.1.0
     127                 :            :  */
     128                 :            : struct _MwsConnectionMonitorNm
     129                 :            : {
     130                 :            :   GObject parent;
     131                 :            : 
     132                 :            :   NMClient *client;  /* (owned); NULL during initialisation */
     133                 :            : 
     134                 :            :   /* Exactly one of these will be set after initialisation completes (or fails). */
     135                 :            :   GError *init_error;  /* (nullable) (owned) */
     136                 :            :   gboolean init_success;
     137                 :            :   gboolean initialising;
     138                 :            : 
     139                 :            :   /* Allow cancelling any pending operations during dispose. */
     140                 :            :   GCancellable *cancellable;  /* (owned) */
     141                 :            : 
     142                 :            :   /* This cache should be invalidated whenever
     143                 :            :    * nm_client_get_active_connections() is changed. */
     144                 :            :   gchar **cached_connection_ids;  /* (owned) (array zero-terminated=1) */
     145                 :            : };
     146                 :            : 
     147                 :            : typedef enum
     148                 :            : {
     149                 :            :   PROP_CLIENT = 1,
     150                 :            : } MwsConnectionMonitorNmProperty;
     151                 :            : 
     152   [ #  #  #  #  :          0 : G_DEFINE_TYPE_WITH_CODE (MwsConnectionMonitorNm, mws_connection_monitor_nm, G_TYPE_OBJECT,
                   #  # ]
     153                 :            :                          G_IMPLEMENT_INTERFACE (MWS_TYPE_CONNECTION_MONITOR,
     154                 :            :                                                 mws_connection_monitor_nm_connection_monitor_init)
     155                 :            :                          G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
     156                 :            :                                                 mws_connection_monitor_nm_initable_init)
     157                 :            :                          G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE,
     158                 :            :                                                 mws_connection_monitor_nm_async_initable_init))
     159                 :            : static void
     160                 :          0 : mws_connection_monitor_nm_class_init (MwsConnectionMonitorNmClass *klass)
     161                 :            : {
     162                 :          0 :   GObjectClass *object_class = (GObjectClass *) klass;
     163                 :          0 :   GParamSpec *props[PROP_CLIENT + 1] = { NULL, };
     164                 :            : 
     165                 :          0 :   object_class->dispose = mws_connection_monitor_nm_dispose;
     166                 :          0 :   object_class->get_property = mws_connection_monitor_nm_get_property;
     167                 :          0 :   object_class->set_property = mws_connection_monitor_nm_set_property;
     168                 :            : 
     169                 :            :   /**
     170                 :            :    * MwsConnectionMonitorNm:client:
     171                 :            :    *
     172                 :            :    * Proxy to the NetworkManager client interface on D-Bus. This must be
     173                 :            :    * provided at construction time, or a new proxy will be built and connected
     174                 :            :    * as part of the asynchronous initialization of this class (using
     175                 :            :    * #GAsyncInitable).
     176                 :            :    *
     177                 :            :    * Since: 0.1.0
     178                 :            :    */
     179                 :          0 :   props[PROP_CLIENT] =
     180                 :          0 :       g_param_spec_object ("client", "Client",
     181                 :            :                            "Proxy to the NetworkManager client interface on D-Bus.",
     182                 :            :                            NM_TYPE_CLIENT,
     183                 :            :                            G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
     184                 :            : 
     185                 :          0 :   g_object_class_install_properties (object_class, G_N_ELEMENTS (props), props);
     186                 :          0 : }
     187                 :            : 
     188                 :            : static void
     189                 :          0 : mws_connection_monitor_nm_connection_monitor_init (MwsConnectionMonitorInterface *iface)
     190                 :            : {
     191                 :          0 :   iface->get_connection_ids = mws_connection_monitor_nm_get_connection_ids;
     192                 :          0 :   iface->get_connection_details = mws_connection_monitor_nm_get_connection_details;
     193                 :          0 : }
     194                 :            : 
     195                 :            : static void
     196                 :          0 : mws_connection_monitor_nm_initable_init (GInitableIface *iface)
     197                 :            : {
     198                 :          0 :   iface->init = mws_connection_monitor_nm_init_failable;
     199                 :          0 : }
     200                 :            : 
     201                 :            : static void
     202                 :          0 : mws_connection_monitor_nm_async_initable_init (GAsyncInitableIface *iface)
     203                 :            : {
     204                 :          0 :   iface->init_async = mws_connection_monitor_nm_init_async;
     205                 :          0 :   iface->init_finish = mws_connection_monitor_nm_init_finish;
     206                 :          0 : }
     207                 :            : 
     208                 :            : static void
     209                 :          0 : mws_connection_monitor_nm_init (MwsConnectionMonitorNm *self)
     210                 :            : {
     211                 :          0 :   self->cancellable = g_cancellable_new ();
     212                 :          0 :   self->cached_connection_ids = NULL;
     213                 :          0 : }
     214                 :            : 
     215                 :            : /* Utilities for connection and disconnecting signals on various objects. */
     216                 :            : static void connection_connect    (MwsConnectionMonitorNm *self,
     217                 :            :                                    NMConnection           *connection,
     218                 :            :                                    NMActiveConnection     *active_connection);
     219                 :            : static void connection_disconnect (NMConnection           *connection);
     220                 :            : 
     221                 :            : static void
     222                 :          0 : active_connection_connect (MwsConnectionMonitorNm *self,
     223                 :            :                            NMActiveConnection     *active_connection)
     224                 :            : {
     225                 :          0 :   NMConnection *connection = NM_CONNECTION (nm_active_connection_get_connection (active_connection));
     226                 :            : 
     227                 :          0 :   g_signal_connect (active_connection, "state-changed",
     228                 :            :                     (GCallback) active_connection_state_changed_cb, self);
     229                 :          0 :   g_signal_connect (active_connection, "notify", (GCallback) active_connection_notify_cb, self);
     230                 :            : 
     231                 :            :   /* @connection may be %NULL if the @active_connection is in state
     232                 :            :    * #NM_ACTIVE_CONNECTION_STATE_ACTIVATING */
     233         [ #  # ]:          0 :   if (connection != NULL)
     234                 :          0 :     connection_connect (self, connection, active_connection);
     235                 :          0 : }
     236                 :            : 
     237                 :            : static void
     238                 :          0 : active_connection_disconnect (MwsConnectionMonitorNm *self,
     239                 :            :                               NMActiveConnection     *active_connection)
     240                 :            : {
     241                 :          0 :   NMConnection *connection = NM_CONNECTION (nm_active_connection_get_connection (active_connection));
     242                 :            : 
     243         [ #  # ]:          0 :   if (connection != NULL)
     244                 :          0 :     connection_disconnect (connection);
     245                 :            : 
     246                 :          0 :   g_signal_handlers_disconnect_by_func (active_connection, active_connection_state_changed_cb, self);
     247                 :          0 :   g_signal_handlers_disconnect_by_func (active_connection, active_connection_notify_cb, self);
     248                 :          0 : }
     249                 :            : 
     250                 :            : static void
     251                 :          0 : device_connect (MwsConnectionMonitorNm *self,
     252                 :            :                 NMDevice               *device)
     253                 :            : {
     254                 :          0 :   g_signal_connect (device, "state-changed",
     255                 :            :                     (GCallback) device_state_changed_cb, self);
     256                 :          0 :   g_signal_connect (device, "notify", (GCallback) device_notify_cb, self);
     257                 :          0 : }
     258                 :            : 
     259                 :            : static void
     260                 :          0 : device_disconnect (MwsConnectionMonitorNm *self,
     261                 :            :                    NMDevice               *device)
     262                 :            : {
     263                 :          0 :   g_signal_handlers_disconnect_by_func (device, device_state_changed_cb, self);
     264                 :          0 :   g_signal_handlers_disconnect_by_func (device, device_notify_cb, self);
     265                 :          0 : }
     266                 :            : 
     267                 :            : /* Closure for the #NMSettingConnection::notify signal callback. */
     268                 :            : typedef struct
     269                 :            : {
     270                 :            :   MwsConnectionMonitorNm *connection_monitor;  /* (unowned) (not nullable) */
     271                 :            :   NMActiveConnection *active_connection;  /* (owned) (not nullable) */
     272                 :            : } ConnectionChangedData;
     273                 :            : 
     274                 :            : static void connection_changed_data_free (ConnectionChangedData *data);
     275         [ #  # ]:          0 : G_DEFINE_AUTOPTR_CLEANUP_FUNC (ConnectionChangedData, connection_changed_data_free)
     276                 :            : 
     277                 :            : static ConnectionChangedData *
     278                 :          0 : setting_notify_data_new (MwsConnectionMonitorNm *connection_monitor,
     279                 :            :                          NMActiveConnection     *active_connection)
     280                 :            : {
     281                 :          0 :   g_autoptr(ConnectionChangedData) data = g_new0 (ConnectionChangedData, 1);
     282                 :          0 :   data->connection_monitor = connection_monitor;
     283                 :          0 :   data->active_connection = g_object_ref (active_connection);
     284                 :          0 :   return g_steal_pointer (&data);
     285                 :            : }
     286                 :            : 
     287                 :            : static void
     288                 :          0 : connection_changed_data_free (ConnectionChangedData *data)
     289                 :            : {
     290         [ #  # ]:          0 :   g_clear_object (&data->active_connection);
     291                 :          0 :   g_free (data);
     292                 :          0 : }
     293                 :            : 
     294                 :            : static void
     295                 :          0 : connection_changed_data_closure_notify (gpointer  data,
     296                 :            :                                         GClosure *closure)
     297                 :            : {
     298                 :          0 :   connection_changed_data_free (data);
     299                 :          0 : }
     300                 :            : 
     301                 :            : static void
     302                 :          0 : connection_connect (MwsConnectionMonitorNm *self,
     303                 :            :                     NMConnection           *connection,
     304                 :            :                     NMActiveConnection     *active_connection)
     305                 :            : {
     306                 :          0 :   g_signal_connect_data (connection, "changed",
     307                 :            :                          (GCallback) connection_changed_cb,
     308                 :          0 :                          setting_notify_data_new (self, active_connection),
     309                 :            :                          connection_changed_data_closure_notify,
     310                 :            :                          0  /* flags */);
     311                 :          0 : }
     312                 :            : 
     313                 :            : static void
     314                 :          0 : connection_disconnect (NMConnection *connection)
     315                 :            : {
     316                 :          0 :   g_signal_handlers_disconnect_matched (connection,
     317                 :            :                                         G_SIGNAL_MATCH_FUNC,
     318                 :            :                                         0  /* signal ID */, 0  /* detail */,
     319                 :            :                                         NULL  /* closure */,
     320                 :            :                                         connection_changed_cb,
     321                 :            :                                         NULL  /* data */);
     322                 :          0 : }
     323                 :            : 
     324                 :            : static void
     325                 :          0 : mws_connection_monitor_nm_dispose (GObject *object)
     326                 :            : {
     327                 :          0 :   MwsConnectionMonitorNm *self = MWS_CONNECTION_MONITOR_NM (object);
     328                 :            : 
     329                 :          0 :   g_cancellable_cancel (self->cancellable);
     330         [ #  # ]:          0 :   g_clear_object (&self->cancellable);
     331                 :            : 
     332         [ #  # ]:          0 :   if (self->client != NULL)
     333                 :            :     {
     334                 :          0 :       g_signal_handlers_disconnect_by_func (self->client, active_connection_added_cb, self);
     335                 :          0 :       g_signal_handlers_disconnect_by_func (self->client, active_connection_removed_cb, self);
     336                 :          0 :       g_signal_handlers_disconnect_by_func (self->client, device_added_cb, self);
     337                 :          0 :       g_signal_handlers_disconnect_by_func (self->client, device_removed_cb, self);
     338                 :            :     }
     339                 :            : 
     340                 :            :   /* Disconnect from all remaining devices. */
     341                 :          0 :   const GPtrArray *devices = nm_client_get_devices (self->client);
     342         [ #  # ]:          0 :   for (gsize i = 0; i < devices->len; i++)
     343                 :            :     {
     344                 :          0 :       NMDevice *device = g_ptr_array_index (devices, i);
     345                 :          0 :       device_removed_cb (self->client, device, self);
     346                 :            :     }
     347                 :            : 
     348                 :            :   /* Disconnect from all remaining active connections. */
     349                 :          0 :   const GPtrArray *active_connections = nm_client_get_active_connections (self->client);
     350         [ #  # ]:          0 :   for (gsize i = 0; i < active_connections->len; i++)
     351                 :            :     {
     352                 :          0 :       NMActiveConnection *active_connection = g_ptr_array_index (active_connections, i);
     353                 :          0 :       active_connection_removed_cb (self->client, active_connection, self);
     354                 :            :     }
     355                 :            : 
     356         [ #  # ]:          0 :   g_clear_object (&self->client);
     357                 :          0 :   g_clear_error (&self->init_error);
     358                 :            : 
     359         [ #  # ]:          0 :   g_clear_pointer (&self->cached_connection_ids, g_strfreev);
     360                 :            : 
     361                 :            :   /* Chain up to the parent class */
     362                 :          0 :   G_OBJECT_CLASS (mws_connection_monitor_nm_parent_class)->dispose (object);
     363                 :          0 : }
     364                 :            : 
     365                 :            : static void
     366                 :          0 : mws_connection_monitor_nm_get_property (GObject    *object,
     367                 :            :                                         guint       property_id,
     368                 :            :                                         GValue     *value,
     369                 :            :                                         GParamSpec *pspec)
     370                 :            : {
     371                 :          0 :   MwsConnectionMonitorNm *self = MWS_CONNECTION_MONITOR_NM (object);
     372                 :            : 
     373         [ #  # ]:          0 :   switch ((MwsConnectionMonitorNmProperty) property_id)
     374                 :            :     {
     375                 :          0 :     case PROP_CLIENT:
     376                 :          0 :       g_value_set_object (value, self->client);
     377                 :          0 :       break;
     378                 :          0 :     default:
     379                 :          0 :       g_assert_not_reached ();
     380                 :            :     }
     381                 :          0 : }
     382                 :            : 
     383                 :            : static void
     384                 :          0 : mws_connection_monitor_nm_set_property (GObject      *object,
     385                 :            :                                         guint         property_id,
     386                 :            :                                         const GValue *value,
     387                 :            :                                         GParamSpec   *pspec)
     388                 :            : {
     389                 :          0 :   MwsConnectionMonitorNm *self = MWS_CONNECTION_MONITOR_NM (object);
     390                 :            : 
     391         [ #  # ]:          0 :   switch ((MwsConnectionMonitorNmProperty) property_id)
     392                 :            :     {
     393                 :          0 :     case PROP_CLIENT:
     394                 :            :       /* Construct only. */
     395         [ #  # ]:          0 :       g_assert (self->client == NULL);
     396                 :          0 :       self->client = g_value_dup_object (value);
     397                 :          0 :       break;
     398                 :          0 :     default:
     399                 :          0 :       g_assert_not_reached ();
     400                 :            :     }
     401                 :          0 : }
     402                 :            : 
     403                 :            : static gboolean
     404                 :          0 : set_up_client (MwsConnectionMonitorNm  *self,
     405                 :            :                GError                 **error)
     406                 :            : {
     407         [ #  # ]:          0 :   g_assert (self->client != NULL);
     408                 :            : 
     409                 :            :   /* Subscribe to signals. */
     410                 :          0 :   g_signal_connect (self->client, "active-connection-added",
     411                 :            :                     (GCallback) active_connection_added_cb, self);
     412                 :          0 :   g_signal_connect (self->client, "active-connection-removed",
     413                 :            :                     (GCallback) active_connection_removed_cb, self);
     414                 :          0 :   g_signal_connect (self->client, "device-added",
     415                 :            :                     (GCallback) device_added_cb, self);
     416                 :          0 :   g_signal_connect (self->client, "device-removed",
     417                 :            :                     (GCallback) device_removed_cb, self);
     418                 :            : 
     419                 :            :   /* Query for initial connections. */
     420                 :          0 :   const GPtrArray *active_connections = nm_client_get_active_connections (self->client);
     421         [ #  # ]:          0 :   for (gsize i = 0; i < active_connections->len; i++)
     422                 :            :     {
     423                 :          0 :       NMActiveConnection *connection = g_ptr_array_index (active_connections, i);
     424                 :          0 :       active_connection_added_cb (self->client, connection, self);
     425                 :            :     }
     426                 :            : 
     427                 :            :   /* …and devices. */
     428                 :          0 :   const GPtrArray *devices = nm_client_get_devices (self->client);
     429         [ #  # ]:          0 :   for (gsize i = 0; i < devices->len; i++)
     430                 :            :     {
     431                 :          0 :       NMDevice *device = g_ptr_array_index (devices, i);
     432                 :          0 :       device_added_cb (self->client, device, self);
     433                 :            :     }
     434                 :            : 
     435                 :          0 :   self->init_success = TRUE;
     436                 :          0 :   return self->init_success;
     437                 :            : }
     438                 :            : 
     439                 :            : static gboolean
     440                 :          0 : mws_connection_monitor_nm_init_failable (GInitable     *initable,
     441                 :            :                                          GCancellable  *cancellable,
     442                 :            :                                          GError       **error)
     443                 :            : {
     444                 :          0 :   MwsConnectionMonitorNm *self = MWS_CONNECTION_MONITOR_NM (initable);
     445                 :            : 
     446                 :            :   /* For the moment, this only supports the case where we’ve been constructed
     447                 :            :    * with a suitable client already. */
     448         [ #  # ]:          0 :   if (self->init_error != NULL)
     449                 :            :     {
     450                 :          0 :       g_propagate_error (error, g_error_copy (self->init_error));
     451                 :          0 :       return FALSE;
     452                 :            :     }
     453         [ #  # ]:          0 :   else if (self->init_success)
     454                 :            :     {
     455                 :          0 :       return TRUE;
     456                 :            :     }
     457                 :            :   else
     458                 :            :     {
     459                 :          0 :       return set_up_client (self, error);
     460                 :            :     }
     461                 :            : }
     462                 :            : 
     463                 :            : static void client_new_cb (GObject      *obj,
     464                 :            :                            GAsyncResult *result,
     465                 :            :                            gpointer      user_data);
     466                 :            : 
     467                 :            : static void
     468                 :          0 : mws_connection_monitor_nm_init_async (GAsyncInitable      *initable,
     469                 :            :                                       int                  io_priority,
     470                 :            :                                       GCancellable        *cancellable,
     471                 :            :                                       GAsyncReadyCallback  callback,
     472                 :            :                                       gpointer             user_data)
     473                 :            : {
     474                 :          0 :   MwsConnectionMonitorNm *self = MWS_CONNECTION_MONITOR_NM (initable);
     475                 :            : 
     476                 :            :   /* We don’t support parallel initialisation. */
     477         [ #  # ]:          0 :   g_assert (!self->initialising);
     478                 :            : 
     479                 :          0 :   g_autoptr(GTask) task = g_task_new (initable, cancellable, callback, user_data);
     480         [ #  # ]:          0 :   g_task_set_source_tag (task, mws_connection_monitor_nm_init_async);
     481                 :            : 
     482         [ #  # ]:          0 :   if (self->init_error != NULL)
     483                 :          0 :     g_task_return_error (task, g_error_copy (self->init_error));
     484         [ #  # ]:          0 :   else if (self->init_success)
     485                 :          0 :     g_task_return_boolean (task, TRUE);
     486                 :            :   else
     487                 :            :     {
     488                 :          0 :       self->initialising = TRUE;
     489                 :          0 :       nm_client_new_async (cancellable, client_new_cb, g_steal_pointer (&task));
     490                 :            :     }
     491                 :          0 : }
     492                 :            : 
     493                 :            : static void
     494                 :          0 : client_new_cb (GObject      *obj,
     495                 :            :                GAsyncResult *result,
     496                 :            :                gpointer      user_data)
     497                 :            : {
     498         [ #  # ]:          0 :   g_autoptr(GTask) task = G_TASK (user_data);
     499                 :          0 :   MwsConnectionMonitorNm *self = g_task_get_source_object (task);
     500         [ #  # ]:          0 :   g_autoptr(GError) error = NULL;
     501                 :            : 
     502                 :            :   /* Get the client. */
     503         [ #  # ]:          0 :   g_assert (self->client == NULL);
     504                 :          0 :   self->client = nm_client_new_finish (result, &error);
     505                 :            : 
     506         [ #  # ]:          0 :   g_assert (self->initialising);
     507                 :          0 :   self->initialising = FALSE;
     508                 :            : 
     509         [ #  # ]:          0 :   if (error != NULL)
     510                 :            :     {
     511                 :          0 :       self->init_success = FALSE;
     512                 :          0 :       g_task_return_error (task, g_steal_pointer (&error));
     513                 :          0 :       return;
     514                 :            :     }
     515                 :            : 
     516         [ #  # ]:          0 :   if (set_up_client (self, &error))
     517                 :          0 :     g_task_return_boolean (task, TRUE);
     518                 :            :   else
     519                 :          0 :     g_task_return_error (task, g_steal_pointer (&error));
     520                 :            : }
     521                 :            : 
     522                 :            : static gboolean
     523                 :          0 : mws_connection_monitor_nm_init_finish (GAsyncInitable  *initable,
     524                 :            :                                        GAsyncResult    *result,
     525                 :            :                                        GError         **error)
     526                 :            : {
     527                 :          0 :   return g_task_propagate_boolean (G_TASK (result), error);
     528                 :            : }
     529                 :            : 
     530                 :            : static const gchar * const *
     531                 :          0 : mws_connection_monitor_nm_get_connection_ids (MwsConnectionMonitor *monitor)
     532                 :            : {
     533                 :          0 :   MwsConnectionMonitorNm *self = MWS_CONNECTION_MONITOR_NM (monitor);
     534                 :            : 
     535                 :          0 :   const GPtrArray *active_connections = nm_client_get_active_connections (self->client);
     536                 :            : 
     537         [ #  # ]:          0 :   if (self->cached_connection_ids == NULL)
     538                 :            :     {
     539                 :          0 :       g_autoptr(GPtrArray) connection_ids = g_ptr_array_new_full (active_connections->len, g_free);
     540         [ #  # ]:          0 :       for (gsize i = 0; i < active_connections->len; i++)
     541                 :            :         {
     542                 :          0 :           NMActiveConnection *active_connection = NM_ACTIVE_CONNECTION (g_ptr_array_index (active_connections, i));
     543                 :          0 :           g_ptr_array_add (connection_ids, g_strdup (nm_active_connection_get_id (active_connection)));
     544                 :            :         }
     545                 :          0 :       g_ptr_array_add (connection_ids, NULL);  /* NULL terminator */
     546                 :          0 :       self->cached_connection_ids = (gchar **) g_ptr_array_free (g_steal_pointer (&connection_ids), FALSE);
     547                 :            :     }
     548                 :            : 
     549                 :            :   /* Sanity check. */
     550         [ #  # ]:          0 :   g_warn_if_fail (g_strv_length ((gchar **) self->cached_connection_ids) == active_connections->len);
     551                 :            : 
     552                 :          0 :   return (const gchar * const *) self->cached_connection_ids;
     553                 :            : }
     554                 :            : 
     555                 :            : /* Convert a #NMMetered to a #MwsMetered. */
     556                 :            : static MwsMetered
     557                 :          0 : mws_metered_from_nm_metered (NMMetered m)
     558                 :            : {
     559   [ #  #  #  #  :          0 :   switch (m)
                   #  # ]
     560                 :            :     {
     561                 :          0 :     case NM_METERED_UNKNOWN:
     562                 :          0 :       return MWS_METERED_UNKNOWN;
     563                 :          0 :     case NM_METERED_YES:
     564                 :          0 :       return MWS_METERED_YES;
     565                 :          0 :     case NM_METERED_NO:
     566                 :          0 :       return MWS_METERED_NO;
     567                 :          0 :     case NM_METERED_GUESS_YES:
     568                 :          0 :       return MWS_METERED_GUESS_YES;
     569                 :          0 :     case NM_METERED_GUESS_NO:
     570                 :          0 :       return MWS_METERED_GUESS_NO;
     571                 :          0 :     default:
     572                 :          0 :       g_assert_not_reached ();
     573                 :            :     }
     574                 :            : }
     575                 :            : 
     576                 :            : /* Get a boolean configuration value from an #NMSettingUser. Valid values are
     577                 :            :  * `0` or `1`. Returns the value; if it wasn’t set in the @setting_user, the
     578                 :            :  * @default_value is returned. There is no way to distinguish an unset value
     579                 :            :  * from a set value equal to the @default_value. */
     580                 :            : static gboolean
     581                 :          0 : setting_user_get_boolean (NMSettingUser *setting_user,
     582                 :            :                           const gchar   *key,
     583                 :            :                           gboolean       default_value)
     584                 :            : {
     585                 :          0 :   const gchar *str = nm_setting_user_get_data (setting_user, key);
     586         [ #  # ]:          0 :   if (str == NULL)
     587                 :          0 :     return default_value;
     588         [ #  # ]:          0 :   else if (g_str_equal (str, "0"))
     589                 :          0 :     return FALSE;
     590         [ #  # ]:          0 :   else if (g_str_equal (str, "1"))
     591                 :          0 :     return TRUE;
     592                 :            :   else
     593                 :          0 :     g_warning ("Invalid value ‘%s’ for user setting ‘%s’; expecting ‘0’ or ‘1’",
     594                 :            :                str, key);
     595                 :            : 
     596                 :          0 :   return default_value;
     597                 :            : }
     598                 :            : 
     599                 :            : static gboolean
     600                 :          0 : mws_connection_monitor_nm_get_connection_details (MwsConnectionMonitor *monitor,
     601                 :            :                                                   const gchar          *id,
     602                 :            :                                                   MwsConnectionDetails *out_details)
     603                 :            : {
     604                 :          0 :   MwsConnectionMonitorNm *self = MWS_CONNECTION_MONITOR_NM (monitor);
     605                 :            : 
     606                 :            :   /* Does the connection with @id exist? */
     607                 :          0 :   const GPtrArray *active_connections = nm_client_get_active_connections (self->client);
     608                 :          0 :   NMActiveConnection *active_connection = NULL;
     609         [ #  # ]:          0 :   for (gsize i = 0; i < active_connections->len; i++)
     610                 :            :     {
     611                 :          0 :       NMActiveConnection *c = NM_ACTIVE_CONNECTION (g_ptr_array_index (active_connections, i));
     612         [ #  # ]:          0 :       if (g_str_equal (nm_active_connection_get_id (c), id))
     613                 :            :         {
     614                 :          0 :           active_connection = c;
     615                 :          0 :           break;
     616                 :            :         }
     617                 :            :     }
     618                 :            : 
     619         [ #  # ]:          0 :   if (active_connection == NULL)
     620                 :          0 :     return FALSE;
     621                 :            : 
     622                 :            :   /* Early return if the connection was found, but the caller doesn’t want the details. */
     623         [ #  # ]:          0 :   if (out_details == NULL)
     624                 :          0 :     return TRUE;
     625                 :            : 
     626                 :            :   /* To work out whether the active connection is metered, combine the metered
     627                 :            :    * status of all the #NMDevices which form it, plus the metered settings of
     628                 :            :    * the active connection’s #NMSettingConnection (if it exists).
     629                 :            :    * We are being conservative here, on the assumption
     630                 :            :    * that a client could download using any active network connection, not just
     631                 :            :    * the primary one. In most cases, the distinction is immaterial as we’d
     632                 :            :    * expect only a single active network connection on most machines. */
     633                 :          0 :   MwsMetered connection_metered = MWS_METERED_GUESS_NO;
     634                 :          0 :   MwsMetered devices_metered = MWS_METERED_UNKNOWN;
     635                 :            : 
     636                 :          0 :   NMConnection *connection = NM_CONNECTION (nm_active_connection_get_connection (active_connection));
     637         [ #  # ]:          0 :   NMSettingConnection *setting = (connection != NULL) ? nm_connection_get_setting_connection (connection) : NULL;
     638                 :            : 
     639         [ #  # ]:          0 :   if (setting != NULL)
     640                 :            :     connection_metered =
     641                 :          0 :         mws_metered_from_nm_metered (nm_setting_connection_get_metered (setting));
     642                 :            : 
     643                 :          0 :   const GPtrArray *devices = nm_active_connection_get_devices (active_connection);
     644                 :            : 
     645         [ #  # ]:          0 :   for (gsize i = 0; i < devices->len; i++)
     646                 :            :     {
     647                 :          0 :       NMDevice *device = g_ptr_array_index (devices, i);
     648                 :            : 
     649                 :            :       /* Sort out metered status. */
     650                 :          0 :       devices_metered = mws_metered_combine_pessimistic (mws_metered_from_nm_metered (nm_device_get_metered (device)),
     651                 :            :                                                          devices_metered);
     652                 :            :     }
     653                 :            : 
     654                 :            :   /* Get the connection’s tariff information (if set). These keys/values are
     655                 :            :    * set on the #NMSettingUser for the primary connection by
     656                 :            :    * gnome-control-center, and may be absent. */
     657                 :          0 :   NMSettingUser *setting_user =
     658         [ #  # ]:          0 :       (connection != NULL) ? NM_SETTING_USER (nm_connection_get_setting (connection, NM_TYPE_SETTING_USER)) : NULL;
     659                 :            : 
     660                 :            :   /* TODO: If we want to load a default value from eos-autoupdater.conf (see
     661                 :            :    * https://phabricator.endlessm.com/T20818#542708), we should plumb it in here
     662                 :            :    * (but do the async loading of the file somewhere else, earlier). */
     663                 :          0 :   const gboolean allow_downloads_when_metered_default = FALSE;
     664                 :          0 :   const gboolean allow_downloads_default = TRUE;
     665                 :            : 
     666                 :          0 :   gboolean allow_downloads_when_metered = allow_downloads_when_metered_default;
     667                 :          0 :   gboolean allow_downloads = allow_downloads_default;
     668                 :          0 :   g_autoptr(MwtTariff) tariff = NULL;
     669                 :            : 
     670         [ #  # ]:          0 :   if (setting_user != NULL)
     671                 :            :     {
     672                 :          0 :       allow_downloads_when_metered = setting_user_get_boolean (setting_user,
     673                 :            :                                                                "connection.allow-downloads-when-metered",
     674                 :            :                                                                allow_downloads_when_metered_default);
     675                 :          0 :       allow_downloads = setting_user_get_boolean (setting_user,
     676                 :            :                                                   "connection.allow-downloads",
     677                 :            :                                                   allow_downloads_default);
     678                 :            : 
     679                 :          0 :       gboolean tariff_enabled = setting_user_get_boolean (setting_user,
     680                 :            :                                                           "connection.tariff-enabled",
     681                 :            :                                                           FALSE);
     682                 :            :       const gchar *tariff_variant_str;
     683                 :          0 :       tariff_variant_str = nm_setting_user_get_data (setting_user,
     684                 :            :                                                      "connection.tariff");
     685                 :            : 
     686   [ #  #  #  #  :          0 :       g_debug ("%s: Connection ‘%s’ has:\n"
                   #  # ]
     687                 :            :                " • connection.allow-downloads-when-metered: %s\n"
     688                 :            :                " • connection.allow-downloads: %s\n"
     689                 :            :                " • connection.tariff-enabled: %s\n"
     690                 :            :                " • connection.tariff: %s",
     691                 :            :                G_STRFUNC, id, allow_downloads_when_metered ? "yes" : "no",
     692                 :            :                allow_downloads ? "yes" : "no", tariff_enabled ? "yes" : "no",
     693                 :            :                tariff_variant_str);
     694                 :            : 
     695   [ #  #  #  # ]:          0 :       if (tariff_enabled && tariff_variant_str != NULL)
     696                 :          0 :         {
     697                 :          0 :           g_autoptr(GError) local_error = NULL;
     698                 :          0 :           g_autoptr(GVariant) tariff_variant = NULL;
     699                 :          0 :           tariff_variant = g_variant_parse (NULL, tariff_variant_str,
     700                 :            :                                             NULL, NULL, &local_error);
     701                 :          0 :           g_autoptr(MwtTariffLoader) loader = mwt_tariff_loader_new ();
     702                 :            : 
     703   [ #  #  #  # ]:          0 :           if (tariff_variant != NULL &&
     704                 :          0 :               mwt_tariff_loader_load_from_variant (loader, tariff_variant,
     705                 :            :                                                    &local_error))
     706                 :          0 :             tariff = g_object_ref (mwt_tariff_loader_get_tariff (loader));
     707                 :            : 
     708         [ #  # ]:          0 :           if (local_error != NULL)
     709                 :            :             {
     710         [ #  # ]:          0 :               g_assert (tariff == NULL);
     711                 :          0 :               g_warning ("connection.tariff contained an invalid tariff ‘%s’: %s",
     712                 :            :                          tariff_variant_str, local_error->message);
     713                 :          0 :               g_clear_error (&local_error);
     714                 :            :             }
     715                 :            :         }
     716   [ #  #  #  # ]:          0 :       else if (tariff_enabled && tariff_variant_str == NULL)
     717                 :            :         {
     718                 :          0 :           g_warning ("connection.tariff is not set even though "
     719                 :            :                      "connection.tariff-enabled is 1");
     720                 :            :         }
     721                 :            :     }
     722                 :            : 
     723                 :          0 :   out_details->metered = mws_metered_combine_pessimistic (devices_metered,
     724                 :            :                                                           connection_metered);
     725                 :          0 :   out_details->allow_downloads_when_metered = allow_downloads_when_metered;
     726                 :          0 :   out_details->allow_downloads = allow_downloads;
     727                 :          0 :   out_details->tariff = g_steal_pointer (&tariff);
     728                 :            : 
     729                 :          0 :   return TRUE;
     730                 :            : }
     731                 :            : 
     732                 :            : static void
     733                 :          0 : active_connection_added_cb (NMClient           *client,
     734                 :            :                             NMActiveConnection *active_connection,
     735                 :            :                             gpointer            user_data)
     736                 :            : {
     737                 :          0 :   MwsConnectionMonitorNm *self = MWS_CONNECTION_MONITOR_NM (user_data);
     738                 :            : 
     739                 :            :   /* Add to the connection IDs list and emit a signal. */
     740                 :          0 :   const gchar *id = nm_active_connection_get_id (active_connection);
     741                 :            : 
     742                 :          0 :   g_debug ("%s: Adding active connection ‘%s’.", G_STRFUNC, id);
     743                 :            : 
     744         [ #  # ]:          0 :   g_clear_pointer (&self->cached_connection_ids, g_strfreev);
     745                 :          0 :   active_connection_connect (self, active_connection);
     746                 :            : 
     747                 :            :   /* FIXME: In the future, we may want to handle the primary connection
     748                 :            :    * (nm_client_get_primary_connection()) differently from other
     749                 :            :    * connections. Probably best to tie that in with the rest of the
     750                 :            :    * multi-path stuff. */
     751                 :          0 :   g_autoptr(GPtrArray) added = g_ptr_array_new_with_free_func (NULL);
     752                 :          0 :   g_ptr_array_add (added, (gpointer) id);
     753                 :          0 :   g_signal_emit_by_name (self, "connections-changed", added, NULL);
     754                 :          0 : }
     755                 :            : 
     756                 :            : static void
     757                 :          0 : active_connection_removed_cb (NMClient           *client,
     758                 :            :                               NMActiveConnection *active_connection,
     759                 :            :                               gpointer            user_data)
     760                 :            : {
     761                 :          0 :   MwsConnectionMonitorNm *self = MWS_CONNECTION_MONITOR_NM (user_data);
     762                 :            : 
     763                 :            :   /* Remove from the connection IDs list and emit a signal. */
     764                 :          0 :   const gchar *id = nm_active_connection_get_id (active_connection);
     765                 :            : 
     766                 :          0 :   g_debug ("%s: Removing active connection ‘%s’.", G_STRFUNC, id);
     767                 :            : 
     768         [ #  # ]:          0 :   g_clear_pointer (&self->cached_connection_ids, g_strfreev);
     769                 :          0 :   active_connection_disconnect (self, active_connection);
     770                 :            : 
     771                 :          0 :   g_autoptr(GPtrArray) removed = g_ptr_array_new_with_free_func (NULL);
     772                 :          0 :   g_ptr_array_add (removed, (gpointer) id);
     773                 :          0 :   g_signal_emit_by_name (self, "connections-changed", NULL, removed);
     774                 :          0 : }
     775                 :            : 
     776                 :            : static void
     777                 :          0 : active_connection_notify_cb (GObject    *obj,
     778                 :            :                              GParamSpec *pspec,
     779                 :            :                              gpointer    user_data)
     780                 :            : {
     781                 :          0 :   MwsConnectionMonitorNm *self = MWS_CONNECTION_MONITOR_NM (user_data);
     782                 :          0 :   NMActiveConnection *active_connection = NM_ACTIVE_CONNECTION (obj);
     783                 :          0 :   NMConnection *connection = NM_CONNECTION (nm_active_connection_get_connection (active_connection));
     784                 :            : 
     785                 :          0 :   const gchar *active_connection_id = NULL;
     786                 :          0 :   active_connection_id = nm_active_connection_get_id (active_connection);
     787                 :            : 
     788         [ #  # ]:          0 :   g_debug ("%s: Active connection ‘%s’ notifying property ‘%s’.",
     789                 :            :            G_STRFUNC, active_connection_id,
     790                 :            :            (pspec != NULL) ? g_param_spec_get_name (pspec) : "(all)");
     791                 :            : 
     792         [ #  # ]:          0 :   if (connection != NULL)
     793                 :          0 :     connection_connect (self, connection, active_connection);
     794                 :            : 
     795         [ #  # ]:          0 :   if (g_cancellable_is_cancelled (self->cancellable))
     796                 :          0 :     return;
     797                 :            : 
     798                 :            :   /* Don’t bother working out what changed; just assume that it will probably
     799                 :            :    * change our scheduling. */
     800                 :          0 :   g_signal_emit_by_name (self, "connection-details-changed", active_connection_id);
     801                 :            : }
     802                 :            : 
     803                 :            : static void
     804                 :          0 : active_connection_state_changed_cb (NMActiveConnection *active_connection,
     805                 :            :                                     guint               new_state,
     806                 :            :                                     guint               reason,
     807                 :            :                                     gpointer            user_data)
     808                 :            : {
     809                 :          0 :   MwsConnectionMonitorNm *self = MWS_CONNECTION_MONITOR_NM (user_data);
     810                 :          0 :   NMConnection *connection = NM_CONNECTION (nm_active_connection_get_connection (active_connection));
     811                 :            : 
     812                 :          0 :   const gchar *active_connection_id = NULL;
     813                 :          0 :   active_connection_id = nm_active_connection_get_id (active_connection);
     814                 :            : 
     815                 :          0 :   g_debug ("%s: Active connection ‘%s’ state changed to %u (reason: %u).",
     816                 :            :            G_STRFUNC, active_connection_id, new_state, reason);
     817                 :            : 
     818         [ #  # ]:          0 :   if (connection != NULL)
     819                 :          0 :     connection_connect (self, connection, active_connection);
     820                 :            : 
     821         [ #  # ]:          0 :   if (g_cancellable_is_cancelled (self->cancellable))
     822                 :          0 :     return;
     823                 :            : 
     824                 :          0 :   g_signal_emit_by_name (self, "connection-details-changed", active_connection_id);
     825                 :            : }
     826                 :            : 
     827                 :            : static void
     828                 :          0 : device_added_cb (NMClient *client,
     829                 :            :                  NMDevice *device,
     830                 :            :                  gpointer  user_data)
     831                 :            : {
     832                 :          0 :   MwsConnectionMonitorNm *self = MWS_CONNECTION_MONITOR_NM (user_data);
     833                 :            : 
     834                 :          0 :   g_debug ("%s: Adding device ‘%s’.", G_STRFUNC, nm_device_get_iface (device));
     835                 :          0 :   device_connect (self, device);
     836                 :          0 : }
     837                 :            : 
     838                 :            : static void
     839                 :          0 : device_removed_cb (NMClient *client,
     840                 :            :                    NMDevice *device,
     841                 :            :                    gpointer  user_data)
     842                 :            : {
     843                 :          0 :   MwsConnectionMonitorNm *self = MWS_CONNECTION_MONITOR_NM (user_data);
     844                 :            : 
     845                 :          0 :   g_debug ("%s: Removing device ‘%s’.", G_STRFUNC, nm_device_get_iface (device));
     846                 :          0 :   device_disconnect (self, device);
     847                 :          0 : }
     848                 :            : 
     849                 :            : static void
     850                 :          0 : device_notify_cb (GObject    *obj,
     851                 :            :                   GParamSpec *pspec,
     852                 :            :                   gpointer    user_data)
     853                 :            : {
     854                 :          0 :   MwsConnectionMonitorNm *self = MWS_CONNECTION_MONITOR_NM (user_data);
     855                 :          0 :   NMDevice *device = NM_DEVICE (obj);
     856                 :            : 
     857                 :          0 :   NMActiveConnection *active_connection = nm_device_get_active_connection (device);
     858                 :          0 :   const gchar *active_connection_id = NULL;
     859         [ #  # ]:          0 :   active_connection_id = (active_connection != NULL) ? nm_active_connection_get_id (active_connection) : "(none)";
     860                 :            : 
     861         [ #  # ]:          0 :   g_debug ("%s: Device ‘%s’ (active connection ‘%s’) notifying property ‘%s’.",
     862                 :            :            G_STRFUNC, nm_device_get_iface (device), active_connection_id,
     863                 :            :            (pspec != NULL) ? g_param_spec_get_name (pspec) : "(all)");
     864                 :            : 
     865         [ #  # ]:          0 :   if (g_cancellable_is_cancelled (self->cancellable))
     866                 :          0 :     return;
     867                 :            : 
     868                 :            :   /* Don’t bother working out what changed; just assume that it will probably
     869                 :            :    * change our scheduling. */
     870         [ #  # ]:          0 :   if (active_connection != NULL)
     871                 :          0 :     g_signal_emit_by_name (self, "connection-details-changed", active_connection_id);
     872                 :            : }
     873                 :            : 
     874                 :            : static void
     875                 :          0 : device_state_changed_cb (NMDevice *device,
     876                 :            :                          guint     new_state,
     877                 :            :                          guint     old_state,
     878                 :            :                          guint     reason,
     879                 :            :                          gpointer  user_data)
     880                 :            : {
     881                 :          0 :   MwsConnectionMonitorNm *self = MWS_CONNECTION_MONITOR_NM (user_data);
     882                 :            : 
     883                 :          0 :   NMActiveConnection *active_connection = nm_device_get_active_connection (device);
     884                 :          0 :   const gchar *active_connection_id = NULL;
     885         [ #  # ]:          0 :   active_connection_id = (active_connection != NULL) ? nm_active_connection_get_id (active_connection) : "(none)";
     886                 :            : 
     887                 :          0 :   g_debug ("%s: Device ‘%s’ (active connection ‘%s’) state changed from %u to "
     888                 :            :            "%u (reason: %u).",
     889                 :            :            G_STRFUNC, nm_device_get_iface (device), active_connection_id,
     890                 :            :            old_state, new_state, reason);
     891                 :            : 
     892         [ #  # ]:          0 :   if (g_cancellable_is_cancelled (self->cancellable))
     893                 :          0 :     return;
     894                 :            : 
     895         [ #  # ]:          0 :   if (active_connection != NULL)
     896                 :          0 :     g_signal_emit_by_name (self, "connection-details-changed", active_connection_id);
     897                 :            : }
     898                 :            : 
     899                 :            : static void
     900                 :          0 : connection_changed_cb (NMConnection *connection,
     901                 :            :                        gpointer      user_data)
     902                 :            : {
     903                 :          0 :   ConnectionChangedData *data = user_data;
     904                 :            : 
     905                 :            :   /* Don’t bother working out what changed; just assume that it will probably
     906                 :            :    * change our scheduling. */
     907                 :          0 :   g_signal_emit_by_name (data->connection_monitor, "connection-details-changed",
     908                 :            :                          nm_active_connection_get_id (data->active_connection));
     909                 :          0 : }
     910                 :            : 
     911                 :            : /**
     912                 :            :  * mws_connection_monitor_nm_new_from_client:
     913                 :            :  * @client: an #NMClient
     914                 :            :  * @error: return location for a #GError, or %NULL
     915                 :            :  *
     916                 :            :  * Create a #MwsConnectionMonitorNm object to wrap the given existing @client.
     917                 :            :  *
     918                 :            :  * Returns: (transfer full): a new #MwsConnectionMonitorNm wrapping @client
     919                 :            :  * Since: 0.1.0
     920                 :            :  */
     921                 :            : MwsConnectionMonitorNm *
     922                 :          0 : mws_connection_monitor_nm_new_from_client (NMClient  *client,
     923                 :            :                                            GError   **error)
     924                 :            : {
     925   [ #  #  #  #  :          0 :   g_return_val_if_fail (NM_IS_CLIENT (client), NULL);
             #  #  #  # ]
     926   [ #  #  #  # ]:          0 :   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
     927                 :            : 
     928                 :          0 :   return g_initable_new (MWS_TYPE_CONNECTION_MONITOR_NM, NULL, error,
     929                 :            :                          "client", client,
     930                 :            :                          NULL);
     931                 :            : }
     932                 :            : 
     933                 :            : /**
     934                 :            :  * mws_connection_monitor_nm_new_async:
     935                 :            :  * @cancellable: (nullable): a #GCancellable, or %NULL
     936                 :            :  * @callback: callback to invoke on completion
     937                 :            :  * @user_data: user data to pass to @callback
     938                 :            :  *
     939                 :            :  * Create a new #MwsConnectionMonitorNm and set it up. This is an asynchronous
     940                 :            :  * process which might fail; object instantiation must be finished (or the error
     941                 :            :  * returned) by calling mws_connection_monitor_nm_new_finish().
     942                 :            :  *
     943                 :            :  * Since: 0.1.0
     944                 :            :  */
     945                 :            : void
     946                 :          0 : mws_connection_monitor_nm_new_async (GCancellable        *cancellable,
     947                 :            :                                      GAsyncReadyCallback  callback,
     948                 :            :                                      gpointer             user_data)
     949                 :            : {
     950   [ #  #  #  #  :          0 :   g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
          #  #  #  #  #  
                      # ]
     951                 :            : 
     952                 :          0 :   g_async_initable_new_async (MWS_TYPE_CONNECTION_MONITOR_NM, G_PRIORITY_DEFAULT,
     953                 :            :                               cancellable, callback, user_data,
     954                 :            :                               "client", NULL,
     955                 :            :                               NULL);
     956                 :            : }
     957                 :            : 
     958                 :            : /**
     959                 :            :  * mws_connection_monitor_nm_new_finish:
     960                 :            :  * @result: asynchronous operation result
     961                 :            :  * @error: return location for a #GError
     962                 :            :  *
     963                 :            :  * Finish initialising a #MwsConnectionMonitorNm. See
     964                 :            :  * mws_connection_monitor_nm_new_async().
     965                 :            :  *
     966                 :            :  * Returns: (transfer full): initialised #MwsConnectionMonitorNm, or %NULL on error
     967                 :            :  * Since: 0.1.0
     968                 :            :  */
     969                 :            : MwsConnectionMonitorNm *
     970                 :          0 : mws_connection_monitor_nm_new_finish (GAsyncResult  *result,
     971                 :            :                                       GError       **error)
     972                 :            : {
     973   [ #  #  #  #  :          0 :   g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
             #  #  #  # ]
     974   [ #  #  #  # ]:          0 :   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
     975                 :            : 
     976                 :          0 :   g_autoptr(GObject) source_object = g_async_result_get_source_object (result);
     977                 :          0 :   return MWS_CONNECTION_MONITOR_NM (g_async_initable_new_finish (G_ASYNC_INITABLE (source_object),
     978                 :            :                                                                  result, error));
     979                 :            : }

Generated by: LCOV version 1.16