<commit_before>/* GIO - GLib Input, Output and Streaming Library
 *
 * Copyright 2011 Red Hat, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General
 * Public License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#include "config.h"

#include "gnetworkmonitorbase.h"
#include "ginetaddress.h"
#include "ginetaddressmask.h"
#include "ginetsocketaddress.h"
#include "ginitable.h"
#include "gioerror.h"
#include "giomodule-priv.h"
#include "gnetworkmonitor.h"
#include "gsocketaddressenumerator.h"
#include "gsocketconnectable.h"
#include "glibintl.h"

static void g_network_monitor_base_iface_init (GNetworkMonitorInterface *iface);
static void g_network_monitor_base_initable_iface_init (GInitableIface *iface);

G_DEFINE_TYPE_WITH_CODE (GNetworkMonitorBase, g_network_monitor_base, G_TYPE_OBJECT,
                         G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
                                                g_network_monitor_base_initable_iface_init)
                         G_IMPLEMENT_INTERFACE (G_TYPE_NETWORK_MONITOR,
                                                g_network_monitor_base_iface_init)
                         _g_io_modules_ensure_extension_points_registered ();
                         g_io_extension_point_implement (G_NETWORK_MONITOR_EXTENSION_POINT_NAME,
                                                         g_define_type_id,
                                                         "base",
                                                         0))

enum
{
  PROP_0,

  PROP_NETWORK_AVAILABLE
};

struct _GNetworkMonitorBasePrivate
{
  GPtrArray    *networks;
  gboolean      have_ipv4_default_route;
  gboolean      have_ipv6_default_route;
  gboolean      is_available;

  GMainContext *context;
  GSource      *network_changed_source;
  gboolean      initializing;
};

static guint network_changed_signal = 0;

static void queue_network_changed (GNetworkMonitorBase *monitor);

static void
g_network_monitor_base_init (GNetworkMonitorBase *monitor)
{
  monitor->priv = G_TYPE_INSTANCE_GET_PRIVATE (monitor,
                                               G_TYPE_NETWORK_MONITOR_BASE,
                                               GNetworkMonitorBasePrivate);

  monitor->priv->networks = g_ptr_array_new_with_free_func (g_object_unref);
  monitor->priv->context = g_main_context_get_thread_default ();
  if (monitor->priv->context)
    g_main_context_ref (monitor->priv->context);

  monitor->priv->initializing = TRUE;
  queue_network_changed (monitor);
}

static void
g_network_monitor_base_constructed (GObject *object)
{
  GNetworkMonitorBase *monitor = G_NETWORK_MONITOR_BASE (object);

  if (G_OBJECT_TYPE (monitor) == G_TYPE_NETWORK_MONITOR_BASE)
    {
      GInetAddressMask *mask;

      /* We're the dumb base class, not a smarter subclass. So just
       * assume that the network is available.
       */
      mask = g_inet_address_mask_new_from_string ("0.0.0.0/0", NULL);
      g_network_monitor_base_add_network (monitor, mask);
      g_object_unref (mask);

      mask = g_inet_address_mask_new_from_string ("::/0", NULL);
      g_network_monitor_base_add_network (monitor, mask);
      g_object_unref (mask);
    }
}

static void
g_network_monitor_base_get_property (GObject    *object,
                                     guint       prop_id,
                                     GValue     *value,
                                     GParamSpec *pspec)
{
  GNetworkMonitorBase *monitor = G_NETWORK_MONITOR_BASE (object);

  switch (prop_id)
    {
      case PROP_NETWORK_AVAILABLE:
        g_value_set_boolean (value, monitor->priv->is_available);
        break;

      default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
    }

}

static void
g_network_monitor_base_finalize (GObject *object)
{
  GNetworkMonitorBase *monitor = G_NETWORK_MONITOR_BASE (object);

  g_ptr_array_free (monitor->priv->networks, TRUE);
  if (monitor->priv->network_changed_source)
    {
      g_source_destroy (monitor->priv->network_changed_source);
      g_source_unref (monitor->priv->network_changed_source);
    }
  if (monitor->priv->context)
    g_main_context_unref (monitor->priv->context);

  G_OBJECT_CLASS (g_network_monitor_base_parent_class)->finalize (object);
}

static void
g_network_monitor_base_class_init (GNetworkMonitorBaseClass *monitor_class)
{
  GObjectClass *gobject_class = G_OBJECT_CLASS (monitor_class);

  g_type_class_add_private (monitor_class, sizeof (GNetworkMonitorBasePrivate));

  gobject_class->constructed  = g_network_monitor_base_constructed;
  gobject_class->get_property = g_network_monitor_base_get_property;
  gobject_class->finalize     = g_network_monitor_base_finalize;

  g_object_class_override_property (gobject_class, PROP_NETWORK_AVAILABLE, "network-available");
}

static gboolean
g_network_monitor_base_can_reach (GNetworkMonitor      *monitor,
                                  GSocketConnectable   *connectable,
                                  GCancellable         *cancellable,
                                  GError              **error)
{
  GNetworkMonitorBasePrivate *priv = G_NETWORK_MONITOR_BASE (monitor)->priv;
  GSocketAddressEnumerator *enumerator;
  GSocketAddress *addr;

  if (priv->have_ipv4_default_route &&
      priv->have_ipv6_default_route)
    return TRUE;

  if (priv->networks->len == 0)
    {
      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NETWORK_UNREACHABLE,
                           _("Network unreachable"));
      return FALSE;
    }

  enumerator = g_socket_connectable_proxy_enumerate (connectable);
  addr = g_socket_address_enumerator_next (enumerator, cancellable, error);
  if (!addr)
    {
      /* Either the user cancelled, or DNS resolution failed */
      g_object_unref (enumerator);
      return FALSE;
    }

  while (addr)
    {
      if (G_IS_INET_SOCKET_ADDRESS (addr))
        {
          GInetAddress *iaddr;
          int i;

          iaddr = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (addr));
          for (i = 0; i < priv->networks->len; i++)
            {
              if (g_inet_address_mask_matches (priv->networks->pdata[i], iaddr))
                {
                  g_object_unref (addr);
                  g_object_unref (enumerator);
                  return TRUE;
                }
            }
        }

      g_object_unref (addr);
      addr = g_socket_address_enumerator_next (enumerator, cancellable, error);
    }
  g_object_unref (enumerator);

  if (error && !*error)<commit_msg>g_network_monitor_base_can_reach: Check for default route after enumerating.<commit_after>/* GIO - GLib Input, Output and Streaming Library
 *
 * Copyright 2011 Red Hat, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General
 * Public License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#include "config.h"

#include "gnetworkmonitorbase.h"
#include "ginetaddress.h"
#include "ginetaddressmask.h"
#include "ginetsocketaddress.h"
#include "ginitable.h"
#include "gioerror.h"
#include "giomodule-priv.h"
#include "gnetworkmonitor.h"
#include "gsocketaddressenumerator.h"
#include "gsocketconnectable.h"
#include "glibintl.h"

static void g_network_monitor_base_iface_init (GNetworkMonitorInterface *iface);
static void g_network_monitor_base_initable_iface_init (GInitableIface *iface);

G_DEFINE_TYPE_WITH_CODE (GNetworkMonitorBase, g_network_monitor_base, G_TYPE_OBJECT,
                         G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
                                                g_network_monitor_base_initable_iface_init)
                         G_IMPLEMENT_INTERFACE (G_TYPE_NETWORK_MONITOR,
                                                g_network_monitor_base_iface_init)
                         _g_io_modules_ensure_extension_points_registered ();
                         g_io_extension_point_implement (G_NETWORK_MONITOR_EXTENSION_POINT_NAME,
                                                         g_define_type_id,
                                                         "base",
                                                         0))

enum
{
  PROP_0,

  PROP_NETWORK_AVAILABLE
};

struct _GNetworkMonitorBasePrivate
{
  GPtrArray    *networks;
  gboolean      have_ipv4_default_route;
  gboolean      have_ipv6_default_route;
  gboolean      is_available;

  GMainContext *context;
  GSource      *network_changed_source;
  gboolean      initializing;
};

static guint network_changed_signal = 0;

static void queue_network_changed (GNetworkMonitorBase *monitor);

static void
g_network_monitor_base_init (GNetworkMonitorBase *monitor)
{
  monitor->priv = G_TYPE_INSTANCE_GET_PRIVATE (monitor,
                                               G_TYPE_NETWORK_MONITOR_BASE,
                                               GNetworkMonitorBasePrivate);

  monitor->priv->networks = g_ptr_array_new_with_free_func (g_object_unref);
  monitor->priv->context = g_main_context_get_thread_default ();
  if (monitor->priv->context)
    g_main_context_ref (monitor->priv->context);

  monitor->priv->initializing = TRUE;
  queue_network_changed (monitor);
}

static void
g_network_monitor_base_constructed (GObject *object)
{
  GNetworkMonitorBase *monitor = G_NETWORK_MONITOR_BASE (object);

  if (G_OBJECT_TYPE (monitor) == G_TYPE_NETWORK_MONITOR_BASE)
    {
      GInetAddressMask *mask;

      /* We're the dumb base class, not a smarter subclass. So just
       * assume that the network is available.
       */
      mask = g_inet_address_mask_new_from_string ("0.0.0.0/0", NULL);
      g_network_monitor_base_add_network (monitor, mask);
      g_object_unref (mask);

      mask = g_inet_address_mask_new_from_string ("::/0", NULL);
      g_network_monitor_base_add_network (monitor, mask);
      g_object_unref (mask);
    }
}

static void
g_network_monitor_base_get_property (GObject    *object,
                                     guint       prop_id,
                                     GValue     *value,
                                     GParamSpec *pspec)
{
  GNetworkMonitorBase *monitor = G_NETWORK_MONITOR_BASE (object);

  switch (prop_id)
    {
      case PROP_NETWORK_AVAILABLE:
        g_value_set_boolean (value, monitor->priv->is_available);
        break;

      default:
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
    }

}

static void
g_network_monitor_base_finalize (GObject *object)
{
  GNetworkMonitorBase *monitor = G_NETWORK_MONITOR_BASE (object);

  g_ptr_array_free (monitor->priv->networks, TRUE);
  if (monitor->priv->network_changed_source)
    {
      g_source_destroy (monitor->priv->network_changed_source);
      g_source_unref (monitor->priv->network_changed_source);
    }
  if (monitor->priv->context)
    g_main_context_unref (monitor->priv->context);

  G_OBJECT_CLASS (g_network_monitor_base_parent_class)->finalize (object);
}

static void
g_network_monitor_base_class_init (GNetworkMonitorBaseClass *monitor_class)
{
  GObjectClass *gobject_class = G_OBJECT_CLASS (monitor_class);

  g_type_class_add_private (monitor_class, sizeof (GNetworkMonitorBasePrivate));

  gobject_class->constructed  = g_network_monitor_base_constructed;
  gobject_class->get_property = g_network_monitor_base_get_property;
  gobject_class->finalize     = g_network_monitor_base_finalize;

  g_object_class_override_property (gobject_class, PROP_NETWORK_AVAILABLE, "network-available");
}

static gboolean
g_network_monitor_base_can_reach (GNetworkMonitor      *monitor,
                                  GSocketConnectable   *connectable,
                                  GCancellable         *cancellable,
                                  GError              **error)
{
  GNetworkMonitorBasePrivate *priv = G_NETWORK_MONITOR_BASE (monitor)->priv;
  GSocketAddressEnumerator *enumerator;
  GSocketAddress *addr;

  if (priv->networks->len == 0)
    {
      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NETWORK_UNREACHABLE,
                           _("Network unreachable"));
      return FALSE;
    }

  enumerator = g_socket_connectable_proxy_enumerate (connectable);
  addr = g_socket_address_enumerator_next (enumerator, cancellable, error);
  if (!addr)
    {
      /* Either the user cancelled, or DNS resolution failed */
      g_object_unref (enumerator);
      return FALSE;
    }

  if (priv->have_ipv4_default_route &&
      priv->have_ipv6_default_route)
    {
      g_object_unref (enumerator);
      g_object_unref (addr);
      return TRUE;
    }

  while (addr)
    {
      if (G_IS_INET_SOCKET_ADDRESS (addr))
        {
          GInetAddress *iaddr;
          int i;

          iaddr = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (addr));
          for (i = 0; i < priv->networks->len; i++)
            {
              if (g_inet_address_mask_matches (priv->networks->pdata[i], iaddr))
                {
                  g_object_unref (addr);
                  g_object_unref (enumerator);
                  return TRUE;
                }
            }
        }

      g_object_unref (addr);
      addr = g_socket_address_enumerator_next (enumerator, cancellable, error);
    }
  g_object_unref (enumerator);

  if (error && !*error)
{'fraction_non_alphanumeric': 0.07618122528273087, 'fraction_numerical': 0.00471796295011448, 'mean_word_length': 2.7053984575835477, 'pattern_counts': {'":': 2, '<': 5, '<?xml version=': 0, '>': 79, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 2, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 40, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2851415', 'n_tokens_mistral': 4383, 'n_tokens_neox': 4285, 'n_words': 917}