Blame gio/tests/resolver.c

Packit ae235b
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
Packit ae235b
Packit ae235b
/* GIO - GLib Input, Output and Streaming Library
Packit ae235b
 * 
Packit ae235b
 * Copyright (C) 2008 Red Hat, Inc.
Packit ae235b
 *
Packit ae235b
 * This library is free software; you can redistribute it and/or
Packit ae235b
 * modify it under the terms of the GNU Lesser General Public
Packit ae235b
 * License as published by the Free Software Foundation; either
Packit ae235b
 * version 2.1 of the License, or (at your option) any later version.
Packit ae235b
 *
Packit ae235b
 * This library is distributed in the hope that it will be useful,
Packit ae235b
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit ae235b
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit ae235b
 * Lesser General Public License for more details.
Packit ae235b
 *
Packit ae235b
 * You should have received a copy of the GNU Lesser General
Packit ae235b
 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
Packit ae235b
 */
Packit ae235b
Packit ae235b
#include "config.h"
Packit ae235b
#include <glib.h>
Packit ae235b
#include "glibintl.h"
Packit ae235b
Packit ae235b
#include <signal.h>
Packit ae235b
#include <stdio.h>
Packit ae235b
#include <stdlib.h>
Packit ae235b
#include <string.h>
Packit ae235b
#ifdef G_OS_UNIX
Packit ae235b
#include <unistd.h>
Packit ae235b
#endif
Packit ae235b
Packit ae235b
#include <gio/gio.h>
Packit ae235b
Packit ae235b
static GResolver *resolver;
Packit ae235b
static GCancellable *cancellable;
Packit ae235b
static GMainLoop *loop;
Packit ae235b
static int nlookups = 0;
Packit ae235b
static gboolean synchronous = FALSE;
Packit ae235b
static guint connectable_count = 0;
Packit ae235b
static GResolverRecordType record_type = 0;
Packit ae235b
Packit ae235b
static void G_GNUC_NORETURN
Packit ae235b
usage (void)
Packit ae235b
{
Packit ae235b
	fprintf (stderr, "Usage: resolver [-s] [hostname | IP | service/protocol/domain ] ...\n");
Packit ae235b
	fprintf (stderr, "Usage: resolver [-s] [-t MX|TXT|NS|SOA] rrname ...\n");
Packit ae235b
	fprintf (stderr, "       resolver [-s] -c NUMBER [hostname | IP | service/protocol/domain ]\n");
Packit ae235b
	fprintf (stderr, "       Use -s to do synchronous lookups.\n");
Packit ae235b
	fprintf (stderr, "       Use -c NUMBER (and only a single resolvable argument) to test GSocketConnectable.\n");
Packit ae235b
	fprintf (stderr, "       The given NUMBER determines how many times the connectable will be enumerated.\n");
Packit ae235b
	fprintf (stderr, "       Use -t with MX, TXT, NS or SOA to lookup DNS records of those types.\n");
Packit ae235b
	exit (1);
Packit ae235b
}
Packit ae235b
Packit ae235b
G_LOCK_DEFINE_STATIC (response);
Packit ae235b
Packit ae235b
static void
Packit ae235b
done_lookup (void)
Packit ae235b
{
Packit ae235b
  nlookups--;
Packit ae235b
  if (nlookups == 0)
Packit ae235b
    {
Packit ae235b
      /* In the sync case we need to make sure we don't call
Packit ae235b
       * g_main_loop_quit before the loop is actually running...
Packit ae235b
       */
Packit ae235b
      g_idle_add ((GSourceFunc)g_main_loop_quit, loop);
Packit ae235b
    }
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
print_resolved_name (const char *phys,
Packit ae235b
                     char       *name,
Packit ae235b
                     GError     *error)
Packit ae235b
{
Packit ae235b
  G_LOCK (response);
Packit ae235b
  printf ("Address: %s\n", phys);
Packit ae235b
  if (error)
Packit ae235b
    {
Packit ae235b
      printf ("Error:   %s\n", error->message);
Packit ae235b
      g_error_free (error);
Packit ae235b
    }
Packit ae235b
  else
Packit ae235b
    {
Packit ae235b
      printf ("Name:    %s\n", name);
Packit ae235b
      g_free (name);
Packit ae235b
    }
Packit ae235b
  printf ("\n");
Packit ae235b
Packit ae235b
  done_lookup ();
Packit ae235b
  G_UNLOCK (response);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
print_resolved_addresses (const char *name,
Packit ae235b
                          GList      *addresses,
Packit ae235b
			  GError     *error)
Packit ae235b
{
Packit ae235b
  char *phys;
Packit ae235b
  GList *a;
Packit ae235b
Packit ae235b
  G_LOCK (response);
Packit ae235b
  printf ("Name:    %s\n", name);
Packit ae235b
  if (error)
Packit ae235b
    {
Packit ae235b
      printf ("Error:   %s\n", error->message);
Packit ae235b
      g_error_free (error);
Packit ae235b
    }
Packit ae235b
  else
Packit ae235b
    {
Packit ae235b
      for (a = addresses; a; a = a->next)
Packit ae235b
	{
Packit ae235b
	  phys = g_inet_address_to_string (a->data);
Packit ae235b
	  printf ("Address: %s\n", phys);
Packit ae235b
	  g_free (phys);
Packit ae235b
          g_object_unref (a->data);
Packit ae235b
	}
Packit ae235b
      g_list_free (addresses);
Packit ae235b
    }
Packit ae235b
  printf ("\n");
Packit ae235b
Packit ae235b
  done_lookup ();
Packit ae235b
  G_UNLOCK (response);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
print_resolved_service (const char *service,
Packit ae235b
                        GList      *targets,
Packit ae235b
			GError     *error)
Packit ae235b
{
Packit ae235b
  GList *t;  
Packit ae235b
Packit ae235b
  G_LOCK (response);
Packit ae235b
  printf ("Service: %s\n", service);
Packit ae235b
  if (error)
Packit ae235b
    {
Packit ae235b
      printf ("Error: %s\n", error->message);
Packit ae235b
      g_error_free (error);
Packit ae235b
    }
Packit ae235b
  else
Packit ae235b
    {
Packit ae235b
      for (t = targets; t; t = t->next)
Packit ae235b
	{
Packit ae235b
	  printf ("%s:%u (pri %u, weight %u)\n",
Packit ae235b
		  g_srv_target_get_hostname (t->data),
Packit ae235b
		  (guint)g_srv_target_get_port (t->data),
Packit ae235b
		  (guint)g_srv_target_get_priority (t->data),
Packit ae235b
		  (guint)g_srv_target_get_weight (t->data));
Packit ae235b
          g_srv_target_free (t->data);
Packit ae235b
	}
Packit ae235b
      g_list_free (targets);
Packit ae235b
    }
Packit ae235b
  printf ("\n");
Packit ae235b
Packit ae235b
  done_lookup ();
Packit ae235b
  G_UNLOCK (response);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
print_resolved_mx (const char *rrname,
Packit ae235b
                   GList      *records,
Packit ae235b
                   GError     *error)
Packit ae235b
{
Packit ae235b
  const gchar *hostname;
Packit ae235b
  guint16 priority;
Packit ae235b
  GList *t;
Packit ae235b
Packit ae235b
  G_LOCK (response);
Packit ae235b
  printf ("Domain: %s\n", rrname);
Packit ae235b
  if (error)
Packit ae235b
    {
Packit ae235b
      printf ("Error: %s\n", error->message);
Packit ae235b
      g_error_free (error);
Packit ae235b
    }
Packit ae235b
  else if (!records)
Packit ae235b
    {
Packit ae235b
      printf ("no MX records\n");
Packit ae235b
    }
Packit ae235b
  else
Packit ae235b
    {
Packit ae235b
      for (t = records; t; t = t->next)
Packit ae235b
        {
Packit ae235b
          g_variant_get (t->data, "(q&s)", &priority, &hostname);
Packit ae235b
          printf ("%s (pri %u)\n", hostname, (guint)priority);
Packit ae235b
          g_variant_unref (t->data);
Packit ae235b
        }
Packit ae235b
      g_list_free (records);
Packit ae235b
    }
Packit ae235b
  printf ("\n");
Packit ae235b
Packit ae235b
  done_lookup ();
Packit ae235b
  G_UNLOCK (response);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
print_resolved_txt (const char *rrname,
Packit ae235b
                    GList      *records,
Packit ae235b
                    GError     *error)
Packit ae235b
{
Packit ae235b
  const gchar **contents;
Packit ae235b
  GList *t;
Packit ae235b
  gint i;
Packit ae235b
Packit ae235b
  G_LOCK (response);
Packit ae235b
  printf ("Domain: %s\n", rrname);
Packit ae235b
  if (error)
Packit ae235b
    {
Packit ae235b
      printf ("Error: %s\n", error->message);
Packit ae235b
      g_error_free (error);
Packit ae235b
    }
Packit ae235b
  else if (!records)
Packit ae235b
    {
Packit ae235b
      printf ("no TXT records\n");
Packit ae235b
    }
Packit ae235b
  else
Packit ae235b
    {
Packit ae235b
      for (t = records; t; t = t->next)
Packit ae235b
        {
Packit ae235b
          if (t != records)
Packit ae235b
            printf ("\n");
Packit ae235b
          g_variant_get (t->data, "(^a&s)", &contents);
Packit ae235b
          for (i = 0; contents[i] != NULL; i++)
Packit ae235b
            printf ("%s\n", contents[i]);
Packit ae235b
          g_variant_unref (t->data);
Packit ae235b
        }
Packit ae235b
      g_list_free (records);
Packit ae235b
    }
Packit ae235b
  printf ("\n");
Packit ae235b
Packit ae235b
  done_lookup ();
Packit ae235b
  G_UNLOCK (response);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
print_resolved_soa (const char *rrname,
Packit ae235b
                    GList      *records,
Packit ae235b
                    GError     *error)
Packit ae235b
{
Packit ae235b
  GList *t;
Packit ae235b
  const gchar *primary_ns;
Packit ae235b
  const gchar *administrator;
Packit ae235b
  guint32 serial, refresh, retry, expire, ttl;
Packit ae235b
Packit ae235b
  G_LOCK (response);
Packit ae235b
  printf ("Zone: %s\n", rrname);
Packit ae235b
  if (error)
Packit ae235b
    {
Packit ae235b
      printf ("Error: %s\n", error->message);
Packit ae235b
      g_error_free (error);
Packit ae235b
    }
Packit ae235b
  else if (!records)
Packit ae235b
    {
Packit ae235b
      printf ("no SOA records\n");
Packit ae235b
    }
Packit ae235b
  else
Packit ae235b
    {
Packit ae235b
      for (t = records; t; t = t->next)
Packit ae235b
        {
Packit ae235b
          g_variant_get (t->data, "(&s&suuuuu)", &primary_ns, &administrator,
Packit ae235b
                         &serial, &refresh, &retry, &expire, &ttl);
Packit ae235b
          printf ("%s %s (serial %u, refresh %u, retry %u, expire %u, ttl %u)\n",
Packit ae235b
                  primary_ns, administrator, (guint)serial, (guint)refresh,
Packit ae235b
                  (guint)retry, (guint)expire, (guint)ttl);
Packit ae235b
          g_variant_unref (t->data);
Packit ae235b
        }
Packit ae235b
      g_list_free (records);
Packit ae235b
    }
Packit ae235b
  printf ("\n");
Packit ae235b
Packit ae235b
  done_lookup ();
Packit ae235b
  G_UNLOCK (response);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
print_resolved_ns (const char *rrname,
Packit ae235b
                    GList      *records,
Packit ae235b
                    GError     *error)
Packit ae235b
{
Packit ae235b
  GList *t;
Packit ae235b
  const gchar *hostname;
Packit ae235b
Packit ae235b
  G_LOCK (response);
Packit ae235b
  printf ("Zone: %s\n", rrname);
Packit ae235b
  if (error)
Packit ae235b
    {
Packit ae235b
      printf ("Error: %s\n", error->message);
Packit ae235b
      g_error_free (error);
Packit ae235b
    }
Packit ae235b
  else if (!records)
Packit ae235b
    {
Packit ae235b
      printf ("no NS records\n");
Packit ae235b
    }
Packit ae235b
  else
Packit ae235b
    {
Packit ae235b
      for (t = records; t; t = t->next)
Packit ae235b
        {
Packit ae235b
          g_variant_get (t->data, "(&s)", &hostname);
Packit ae235b
          printf ("%s\n", hostname);
Packit ae235b
          g_variant_unref (t->data);
Packit ae235b
        }
Packit ae235b
      g_list_free (records);
Packit ae235b
    }
Packit ae235b
  printf ("\n");
Packit ae235b
Packit ae235b
  done_lookup ();
Packit ae235b
  G_UNLOCK (response);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
lookup_one_sync (const char *arg)
Packit ae235b
{
Packit ae235b
  GError *error = NULL;
Packit ae235b
Packit ae235b
  if (record_type != 0)
Packit ae235b
    {
Packit ae235b
      GList *records;
Packit ae235b
Packit ae235b
      records = g_resolver_lookup_records (resolver, arg, record_type, cancellable, &error);
Packit ae235b
      switch (record_type)
Packit ae235b
      {
Packit ae235b
        case G_RESOLVER_RECORD_MX:
Packit ae235b
          print_resolved_mx (arg, records, error);
Packit ae235b
          break;
Packit ae235b
        case G_RESOLVER_RECORD_SOA:
Packit ae235b
          print_resolved_soa (arg, records, error);
Packit ae235b
          break;
Packit ae235b
        case G_RESOLVER_RECORD_NS:
Packit ae235b
          print_resolved_ns (arg, records, error);
Packit ae235b
          break;
Packit ae235b
        case G_RESOLVER_RECORD_TXT:
Packit ae235b
          print_resolved_txt (arg, records, error);
Packit ae235b
          break;
Packit ae235b
        default:
Packit ae235b
          g_warn_if_reached ();
Packit ae235b
          break;
Packit ae235b
      }
Packit ae235b
    }
Packit ae235b
  else if (strchr (arg, '/'))
Packit ae235b
    {
Packit ae235b
      GList *targets;
Packit ae235b
      /* service/protocol/domain */
Packit ae235b
      char **parts = g_strsplit (arg, "/", 3);
Packit ae235b
Packit ae235b
      if (!parts || !parts[2])
Packit ae235b
	usage ();
Packit ae235b
Packit ae235b
      targets = g_resolver_lookup_service (resolver,
Packit ae235b
                                           parts[0], parts[1], parts[2],
Packit ae235b
                                           cancellable, &error);
Packit ae235b
      print_resolved_service (arg, targets, error);
Packit ae235b
    }
Packit ae235b
  else if (g_hostname_is_ip_address (arg))
Packit ae235b
    {
Packit ae235b
      GInetAddress *addr = g_inet_address_new_from_string (arg);
Packit ae235b
      char *name;
Packit ae235b
Packit ae235b
      name = g_resolver_lookup_by_address (resolver, addr, cancellable, &error);
Packit ae235b
      print_resolved_name (arg, name, error);
Packit ae235b
      g_object_unref (addr);
Packit ae235b
    }
Packit ae235b
  else
Packit ae235b
    {
Packit ae235b
      GList *addresses;
Packit ae235b
Packit ae235b
      addresses = g_resolver_lookup_by_name (resolver, arg, cancellable, &error);
Packit ae235b
      print_resolved_addresses (arg, addresses, error);
Packit ae235b
    }
Packit ae235b
}
Packit ae235b
Packit ae235b
static gpointer
Packit ae235b
lookup_thread (gpointer arg)
Packit ae235b
{
Packit ae235b
  lookup_one_sync (arg);
Packit ae235b
  return NULL;
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
start_sync_lookups (char **argv, int argc)
Packit ae235b
{
Packit ae235b
  int i;
Packit ae235b
Packit ae235b
  for (i = 0; i < argc; i++)
Packit ae235b
    {
Packit ae235b
      GThread *thread;
Packit ae235b
      thread = g_thread_new ("lookup", lookup_thread, argv[i]);
Packit ae235b
      g_thread_unref (thread);
Packit ae235b
    }
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
lookup_by_addr_callback (GObject *source, GAsyncResult *result,
Packit ae235b
                         gpointer user_data)
Packit ae235b
{
Packit ae235b
  const char *phys = user_data;
Packit ae235b
  GError *error = NULL;
Packit ae235b
  char *name;
Packit ae235b
Packit ae235b
  name = g_resolver_lookup_by_address_finish (resolver, result, &error);
Packit ae235b
  print_resolved_name (phys, name, error);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
lookup_by_name_callback (GObject *source, GAsyncResult *result,
Packit ae235b
                         gpointer user_data)
Packit ae235b
{
Packit ae235b
  const char *name = user_data;
Packit ae235b
  GError *error = NULL;
Packit ae235b
  GList *addresses;
Packit ae235b
Packit ae235b
  addresses = g_resolver_lookup_by_name_finish (resolver, result, &error);
Packit ae235b
  print_resolved_addresses (name, addresses, error);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
lookup_service_callback (GObject *source, GAsyncResult *result,
Packit ae235b
			 gpointer user_data)
Packit ae235b
{
Packit ae235b
  const char *service = user_data;
Packit ae235b
  GError *error = NULL;
Packit ae235b
  GList *targets;
Packit ae235b
Packit ae235b
  targets = g_resolver_lookup_service_finish (resolver, result, &error);
Packit ae235b
  print_resolved_service (service, targets, error);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
lookup_records_callback (GObject      *source,
Packit ae235b
                         GAsyncResult *result,
Packit ae235b
                         gpointer      user_data)
Packit ae235b
{
Packit ae235b
  const char *arg = user_data;
Packit ae235b
  GError *error = NULL;
Packit ae235b
  GList *records;
Packit ae235b
Packit ae235b
  records = g_resolver_lookup_records_finish (resolver, result, &error);
Packit ae235b
Packit ae235b
  switch (record_type)
Packit ae235b
  {
Packit ae235b
    case G_RESOLVER_RECORD_MX:
Packit ae235b
      print_resolved_mx (arg, records, error);
Packit ae235b
      break;
Packit ae235b
    case G_RESOLVER_RECORD_SOA:
Packit ae235b
      print_resolved_soa (arg, records, error);
Packit ae235b
      break;
Packit ae235b
    case G_RESOLVER_RECORD_NS:
Packit ae235b
      print_resolved_ns (arg, records, error);
Packit ae235b
      break;
Packit ae235b
    case G_RESOLVER_RECORD_TXT:
Packit ae235b
      print_resolved_txt (arg, records, error);
Packit ae235b
      break;
Packit ae235b
    default:
Packit ae235b
      g_warn_if_reached ();
Packit ae235b
      break;
Packit ae235b
  }
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
start_async_lookups (char **argv, int argc)
Packit ae235b
{
Packit ae235b
  int i;
Packit ae235b
Packit ae235b
  for (i = 0; i < argc; i++)
Packit ae235b
    {
Packit ae235b
      if (record_type != 0)
Packit ae235b
	{
Packit ae235b
	  g_resolver_lookup_records_async (resolver, argv[i], record_type,
Packit ae235b
	                                   cancellable, lookup_records_callback, argv[i]);
Packit ae235b
	}
Packit ae235b
      else if (strchr (argv[i], '/'))
Packit ae235b
	{
Packit ae235b
	  /* service/protocol/domain */
Packit ae235b
	  char **parts = g_strsplit (argv[i], "/", 3);
Packit ae235b
Packit ae235b
	  if (!parts || !parts[2])
Packit ae235b
	    usage ();
Packit ae235b
Packit ae235b
	  g_resolver_lookup_service_async (resolver,
Packit ae235b
					   parts[0], parts[1], parts[2],
Packit ae235b
					   cancellable,
Packit ae235b
					   lookup_service_callback, argv[i]);
Packit ae235b
	}
Packit ae235b
      else if (g_hostname_is_ip_address (argv[i]))
Packit ae235b
	{
Packit ae235b
          GInetAddress *addr = g_inet_address_new_from_string (argv[i]);
Packit ae235b
Packit ae235b
	  g_resolver_lookup_by_address_async (resolver, addr, cancellable,
Packit ae235b
                                              lookup_by_addr_callback, argv[i]);
Packit ae235b
	  g_object_unref (addr);
Packit ae235b
	}
Packit ae235b
      else
Packit ae235b
	{
Packit ae235b
	  g_resolver_lookup_by_name_async (resolver, argv[i], cancellable,
Packit ae235b
                                           lookup_by_name_callback,
Packit ae235b
                                           argv[i]);
Packit ae235b
	}
Packit ae235b
Packit ae235b
      /* Stress-test the reloading code */
Packit ae235b
      g_signal_emit_by_name (resolver, "reload");
Packit ae235b
    }
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
print_connectable_sockaddr (GSocketAddress *sockaddr,
Packit ae235b
                            GError         *error)
Packit ae235b
{
Packit ae235b
  char *phys;
Packit ae235b
Packit ae235b
  if (error)
Packit ae235b
    {
Packit ae235b
      printf ("Error:   %s\n", error->message);
Packit ae235b
      g_error_free (error);
Packit ae235b
    }
Packit ae235b
  else if (!G_IS_INET_SOCKET_ADDRESS (sockaddr))
Packit ae235b
    {
Packit ae235b
      printf ("Error:   Unexpected sockaddr type '%s'\n", g_type_name_from_instance ((GTypeInstance *)sockaddr));
Packit ae235b
      g_object_unref (sockaddr);
Packit ae235b
    }
Packit ae235b
  else
Packit ae235b
    {
Packit ae235b
      GInetSocketAddress *isa = G_INET_SOCKET_ADDRESS (sockaddr);
Packit ae235b
      phys = g_inet_address_to_string (g_inet_socket_address_get_address (isa));
Packit ae235b
      printf ("Address: %s%s%s:%d\n",
Packit ae235b
              strchr (phys, ':') ? "[" : "", phys, strchr (phys, ':') ? "]" : "",
Packit ae235b
              g_inet_socket_address_get_port (isa));
Packit ae235b
      g_free (phys);
Packit ae235b
      g_object_unref (sockaddr);
Packit ae235b
    }
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
do_sync_connectable (GSocketAddressEnumerator *enumerator)
Packit ae235b
{
Packit ae235b
  GSocketAddress *sockaddr;
Packit ae235b
  GError *error = NULL;
Packit ae235b
Packit ae235b
  while ((sockaddr = g_socket_address_enumerator_next (enumerator, cancellable, &error)))
Packit ae235b
    print_connectable_sockaddr (sockaddr, error);
Packit ae235b
Packit ae235b
  g_object_unref (enumerator);
Packit ae235b
  done_lookup ();
Packit ae235b
}
Packit ae235b
Packit ae235b
static void do_async_connectable (GSocketAddressEnumerator *enumerator);
Packit ae235b
Packit ae235b
static void
Packit ae235b
got_next_async (GObject *source, GAsyncResult *result, gpointer user_data)
Packit ae235b
{
Packit ae235b
  GSocketAddressEnumerator *enumerator = G_SOCKET_ADDRESS_ENUMERATOR (source);
Packit ae235b
  GSocketAddress *sockaddr;
Packit ae235b
  GError *error = NULL;
Packit ae235b
Packit ae235b
  sockaddr = g_socket_address_enumerator_next_finish (enumerator, result, &error);
Packit ae235b
  if (sockaddr || error)
Packit ae235b
    print_connectable_sockaddr (sockaddr, error);
Packit ae235b
  if (sockaddr)
Packit ae235b
    do_async_connectable (enumerator);
Packit ae235b
  else
Packit ae235b
    {
Packit ae235b
      g_object_unref (enumerator);
Packit ae235b
      done_lookup ();
Packit ae235b
    }
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
do_async_connectable (GSocketAddressEnumerator *enumerator)
Packit ae235b
{
Packit ae235b
  g_socket_address_enumerator_next_async (enumerator, cancellable,
Packit ae235b
                                          got_next_async, NULL);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
do_connectable (const char *arg, gboolean synchronous, guint count)
Packit ae235b
{
Packit ae235b
  char **parts;
Packit ae235b
  GSocketConnectable *connectable;
Packit ae235b
  GSocketAddressEnumerator *enumerator;
Packit ae235b
Packit ae235b
  if (strchr (arg, '/'))
Packit ae235b
    {
Packit ae235b
      /* service/protocol/domain */
Packit ae235b
      parts = g_strsplit (arg, "/", 3);
Packit ae235b
      if (!parts || !parts[2])
Packit ae235b
	usage ();
Packit ae235b
Packit ae235b
      connectable = g_network_service_new (parts[0], parts[1], parts[2]);
Packit ae235b
    }
Packit ae235b
  else
Packit ae235b
    {
Packit ae235b
      guint16 port;
Packit ae235b
Packit ae235b
      parts = g_strsplit (arg, ":", 2);
Packit ae235b
      if (parts && parts[1])
Packit ae235b
	{
Packit ae235b
	  arg = parts[0];
Packit ae235b
	  port = strtoul (parts[1], NULL, 10);
Packit ae235b
	}
Packit ae235b
      else
Packit ae235b
	port = 0;
Packit ae235b
Packit ae235b
      if (g_hostname_is_ip_address (arg))
Packit ae235b
	{
Packit ae235b
	  GInetAddress *addr = g_inet_address_new_from_string (arg);
Packit ae235b
	  GSocketAddress *sockaddr = g_inet_socket_address_new (addr, port);
Packit ae235b
Packit ae235b
	  g_object_unref (addr);
Packit ae235b
	  connectable = G_SOCKET_CONNECTABLE (sockaddr);
Packit ae235b
	}
Packit ae235b
      else
Packit ae235b
        connectable = g_network_address_new (arg, port);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  while (count--)
Packit ae235b
    {
Packit ae235b
      enumerator = g_socket_connectable_enumerate (connectable);
Packit ae235b
Packit ae235b
      if (synchronous)
Packit ae235b
        do_sync_connectable (enumerator);
Packit ae235b
      else
Packit ae235b
        do_async_connectable (enumerator);
Packit ae235b
    }
Packit ae235b
  
Packit ae235b
  g_object_unref (connectable);
Packit ae235b
}
Packit ae235b
Packit ae235b
#ifdef G_OS_UNIX
Packit ae235b
static int cancel_fds[2];
Packit ae235b
Packit ae235b
static void
Packit ae235b
interrupted (int sig)
Packit ae235b
{
Packit ae235b
  gssize c;
Packit ae235b
Packit ae235b
  signal (SIGINT, SIG_DFL);
Packit ae235b
  c = write (cancel_fds[1], "x", 1);
Packit ae235b
  g_assert_cmpint(c, ==, 1);
Packit ae235b
}
Packit ae235b
Packit ae235b
static gboolean
Packit ae235b
async_cancel (GIOChannel *source, GIOCondition cond, gpointer cancel)
Packit ae235b
{
Packit ae235b
  g_cancellable_cancel (cancel);
Packit ae235b
  return FALSE;
Packit ae235b
}
Packit ae235b
#endif
Packit ae235b
Packit ae235b
Packit ae235b
static gboolean
Packit ae235b
record_type_arg (const gchar *option_name,
Packit ae235b
                 const gchar *value,
Packit ae235b
                 gpointer data,
Packit ae235b
                 GError **error)
Packit ae235b
{
Packit ae235b
  if (g_ascii_strcasecmp (value, "MX") == 0) {
Packit ae235b
    record_type = G_RESOLVER_RECORD_MX;
Packit ae235b
  } else if (g_ascii_strcasecmp (value, "TXT") == 0) {
Packit ae235b
    record_type = G_RESOLVER_RECORD_TXT;
Packit ae235b
  } else if (g_ascii_strcasecmp (value, "SOA") == 0) {
Packit ae235b
    record_type = G_RESOLVER_RECORD_SOA;
Packit ae235b
  } else if (g_ascii_strcasecmp (value, "NS") == 0) {
Packit ae235b
    record_type = G_RESOLVER_RECORD_NS;
Packit ae235b
  } else {
Packit ae235b
      g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
Packit ae235b
                   "Specify MX, TXT, NS or SOA for the special record lookup types");
Packit ae235b
      return FALSE;
Packit ae235b
  }
Packit ae235b
Packit ae235b
  return TRUE;
Packit ae235b
}
Packit ae235b
Packit ae235b
static const GOptionEntry option_entries[] = {
Packit ae235b
  { "synchronous", 's', 0, G_OPTION_ARG_NONE, &synchronous, "Synchronous connections", NULL },
Packit ae235b
  { "connectable", 'c', 0, G_OPTION_ARG_INT, &connectable_count, "Connectable count", "C" },
Packit ae235b
  { "special-type", 't', 0, G_OPTION_ARG_CALLBACK, record_type_arg, "Record type like MX, TXT, NS or SOA", "RR" },
Packit ae235b
  { NULL },
Packit ae235b
};
Packit ae235b
Packit ae235b
int
Packit ae235b
main (int argc, char **argv)
Packit ae235b
{
Packit ae235b
  GOptionContext *context;
Packit ae235b
  GError *error = NULL;
Packit ae235b
#ifdef G_OS_UNIX
Packit ae235b
  GIOChannel *chan;
Packit ae235b
  guint watch;
Packit ae235b
#endif
Packit ae235b
Packit ae235b
  context = g_option_context_new ("lookups ...");
Packit ae235b
  g_option_context_add_main_entries (context, option_entries, NULL);
Packit ae235b
  if (!g_option_context_parse (context, &argc, &argv, &error))
Packit ae235b
    {
Packit ae235b
      g_printerr ("%s\n", error->message);
Packit ae235b
      g_error_free (error);
Packit ae235b
      usage();
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (argc < 2 || (argc > 2 && connectable_count))
Packit ae235b
    usage ();
Packit ae235b
Packit ae235b
  resolver = g_resolver_get_default ();
Packit ae235b
Packit ae235b
  cancellable = g_cancellable_new ();
Packit ae235b
Packit ae235b
#ifdef G_OS_UNIX
Packit ae235b
  /* Set up cancellation; we want to cancel if the user ^C's the
Packit ae235b
   * program, but we can't cancel directly from an interrupt.
Packit ae235b
   */
Packit ae235b
  signal (SIGINT, interrupted);
Packit ae235b
Packit ae235b
  if (pipe (cancel_fds) == -1)
Packit ae235b
    {
Packit ae235b
      perror ("pipe");
Packit ae235b
      exit (1);
Packit ae235b
    }
Packit ae235b
  chan = g_io_channel_unix_new (cancel_fds[0]);
Packit ae235b
  watch = g_io_add_watch (chan, G_IO_IN, async_cancel, cancellable);
Packit ae235b
  g_io_channel_unref (chan);
Packit ae235b
#endif
Packit ae235b
Packit ae235b
  nlookups = argc - 1;
Packit ae235b
  loop = g_main_loop_new (NULL, TRUE);
Packit ae235b
Packit ae235b
  if (connectable_count)
Packit ae235b
    {
Packit ae235b
      nlookups = connectable_count;
Packit ae235b
      do_connectable (argv[1], synchronous, connectable_count);
Packit ae235b
    }
Packit ae235b
  else
Packit ae235b
    {
Packit ae235b
      if (synchronous)
Packit ae235b
        start_sync_lookups (argv + 1, argc - 1);
Packit ae235b
      else
Packit ae235b
        start_async_lookups (argv + 1, argc - 1);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  g_main_loop_run (loop);
Packit ae235b
  g_main_loop_unref (loop);
Packit ae235b
Packit ae235b
#ifdef G_OS_UNIX
Packit ae235b
  g_source_remove (watch);
Packit ae235b
#endif
Packit ae235b
  g_object_unref (cancellable);
Packit ae235b
Packit ae235b
  return 0;
Packit ae235b
}