[glibmm] Re-enable network IO stuff (Socket, Resolver, etc)



commit e161c51f14b5b5123dacac447d1697134ee4eadb
Author: Jonathon Jongsma <jonathon quotidian org>
Date:   Sat Oct 24 00:11:18 2009 -0500

    Re-enable network IO stuff (Socket, Resolver, etc)
    
    There is a bit of a problem with some of the async stuff that is exhibited by
    the included resolver example.  For example, when run the example with the
    following arguments:
    
      ./resolver -c domain.com
    
    There are several critical warnings printed to the terminal, and I have not been
    able to debug it to find the cause yet.  I think it must have something to with
    the lifetime of the enumerator object during the next_async() calls and
    sigc::bind, etc. but I can't figure it out yet.

 .gitignore                     |    2 +-
 ChangeLog                      |   15 ++
 examples/Makefile.am           |    5 +-
 examples/network/resolver.cc   |  529 ++++++++++++++++++++++++++++++++++++++++
 examples/network_io/resolve.cc |   51 ----
 gio/giomm.h                    |   11 +
 gio/src/error.hg               |    1 +
 gio/src/inetaddress.ccg        |    5 +
 gio/src/inetaddress.hg         |    2 +-
 gio/src/resolver.ccg           |   32 +++
 gio/src/resolver.hg            |    6 +
 11 files changed, 604 insertions(+), 55 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index 9a0f053..67b7ccd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -63,7 +63,7 @@ giommconfig.h
 /examples/thread/dispatcher2
 /examples/thread/thread
 /examples/thread/threadpool
-/examples/network_io/resolve
+/examples/network/resolver
 
 # gio/
 /gio/giomm-*.pc
diff --git a/ChangeLog b/ChangeLog
index 5208e86..8ad24ec 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+2009-10-23  Jonathon Jongsma  <jonathon jongsma collabora co uk>
+
+	Re-enable Network IO stuff (Socket, Resolver, etc)
+
+	* .gitignore:
+	* examples/Makefile.am:
+	* examples/network/resolver.cc: Ported example from glib
+	* examples/network_io/resolve.cc: Removed.
+	* gio/giomm.h: Add network headers
+	* gio/src/error.hg: Add ResolverError
+	* gio/src/inetaddress.ccg:
+	* gio/src/inetaddress.hg: Fix broken constructor
+	* gio/src/resolver.ccg:
+	* gio/src/resolver.hg: Added a few missing free functions
+
 2009-11-23  Murray Cumming  <murrayc murrayc com>
 
 	Regex: Slight documentation improvement.
diff --git a/examples/Makefile.am b/examples/Makefile.am
index ea48c91..83aa5ab 100644
--- a/examples/Makefile.am
+++ b/examples/Makefile.am
@@ -23,6 +23,7 @@ check_PROGRAMS =			\
 	iochannel_stream/example	\
 	keyfile/example			\
 	markup/parser			\
+	network/resolver		\
 	options/example			\
 	properties/example		\
 	regex/example			\
@@ -67,5 +68,5 @@ thread_thread_LDADD        = $(thread_ldadd)
 thread_threadpool_SOURCES  = thread/threadpool.cc
 thread_threadpool_LDADD    = $(thread_ldadd)
 
-network_io_resolve_SOURCES = network_io/resolve.cc
-network_io_resolve_LDADD   = $(giomm_ldadd)
+network_resolver_SOURCES   = network/resolver.cc
+network_resolver_LDADD     = $(giomm_ldadd) $(GTHREAD_LIBS)
diff --git a/examples/network/resolver.cc b/examples/network/resolver.cc
new file mode 100644
index 0000000..625c859
--- /dev/null
+++ b/examples/network/resolver.cc
@@ -0,0 +1,529 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2008 Red Hat, Inc.
+ * Copyright (C) 2009 Jonathon Jongsma
+ *
+ * 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 <giomm.h>
+#include <iostream>
+
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <gio/gio.h>
+
+static Glib::RefPtr<Gio::Resolver> resolver;
+static Glib::RefPtr<Gio::Cancellable> cancellable;
+static Glib::RefPtr<Glib::MainLoop> loop;
+static int nlookups = 0;
+
+static void G_GNUC_NORETURN
+usage (void)
+{
+    std::cerr
+        << "Usage: resolver [-t] [-s] [hostname | IP | service/protocol/domain ] ...\n"
+        << "       resolver [-t] [-s] -c [hostname | IP | service/protocol/domain ]\n"
+        << "       Use -t to enable threading.\n"
+        << "       Use -s to do synchronous lookups.\n"
+        << "       Both together will result in simultaneous lookups in multiple threads\n"
+        << "       Use -c (and only a single resolvable argument) to test GSocketConnectable.\n";
+    exit (1);
+}
+
+G_LOCK_DEFINE_STATIC (response);
+
+static bool
+idle_quit ()
+{
+    loop->quit ();
+    return false;
+}
+
+static void
+done_lookup (void)
+{
+  nlookups--;
+  if (nlookups == 0)
+    {
+      /* In the sync case we need to make sure we don't call
+       * g_main_loop_quit before the loop is actually running...
+       */
+        Glib::signal_idle ().connect (sigc::ptr_fun (idle_quit));
+    }
+}
+
+static void
+print_resolved_name (const Glib::ustring& phys,
+                     const Glib::ustring& name)
+{
+  G_LOCK (response);
+  std::cout
+      << Glib::ustring::compose ("Address: %1\n", phys)
+      << Glib::ustring::compose ("Name:    %1\n", name)
+      << std::endl;
+
+  done_lookup ();
+  G_UNLOCK (response);
+}
+
+static void
+print_resolved_addresses (const Glib::ustring& name,
+                          const std::list<Glib::RefPtr<Gio::InetAddress> >& addresses)
+{
+    G_LOCK (response);
+    std::cout << Glib::ustring::compose ("Name:    %1\n", name);
+    for (std::list<Glib::RefPtr<Gio::InetAddress> >::const_iterator iter = addresses.begin ();
+         iter != addresses.end (); ++iter)
+    {
+        std::cout << Glib::ustring::compose ("Address: %1\n", (*iter)->to_string ());
+    }
+    std::cout << std::endl;
+
+    done_lookup ();
+    G_UNLOCK (response);
+}
+
+static void
+print_resolved_service (const Glib::ustring& service,
+                        const std::list<Gio::SrvTarget>& targets)
+{
+    G_LOCK (response);
+    std::cout << Glib::ustring::compose ("Service: %1\n", service);
+    for (std::list<Gio::SrvTarget>::const_iterator iter = targets.begin ();
+         iter != targets.end (); ++iter)
+    {
+        std::cout <<
+            Glib::ustring::compose ("%1:%u (pri %u, weight %u)\n",
+                                    iter->get_hostname (),
+                                    iter->get_port (),
+                                    iter->get_priority (),
+                                    iter->get_weight ());
+    }
+    std::cout << std::endl;
+
+    done_lookup ();
+    G_UNLOCK (response);
+}
+
+static void
+lookup_one_sync (const Glib::ustring& arg)
+{
+    if (arg.find ('/') != std::string::npos)
+    {
+        std::list<Gio::SrvTarget> targets;
+        /* service/protocol/domain */
+        std::vector<Glib::ustring> parts;
+        size_t pos = 0;
+        for (int i = 0; i < 3; ++i)
+        {
+            size_t newpos = arg.find ('/', pos);
+            if (pos == std::string::npos)
+                usage ();
+            parts.push_back (arg.substr (pos, newpos - pos));
+            pos = newpos;
+        }
+
+        try
+        {
+            targets = resolver->lookup_service (parts[0], parts[1], parts[2],
+                                                cancellable);
+            print_resolved_service (arg, targets);
+        }
+        catch (const Gio::ResolverError& err)
+        {
+            std::cerr << err.what () << std::endl;
+        }
+    }
+    else if (Gio::hostname_is_ip_address (arg))
+    {
+        Glib::RefPtr<Gio::InetAddress> addr = Gio::InetAddress::create (arg);
+        try
+        {
+            Glib::ustring name = resolver->lookup_by_address (addr, cancellable);
+            print_resolved_name (arg, name);
+        }
+        catch (const Gio::ResolverError& err)
+        {
+            std::cerr << err.what () << std::endl;
+        }
+    }
+    else
+    {
+        std::list<Glib::RefPtr<Gio::InetAddress> > addresses;
+
+        try
+        {
+            addresses = resolver->lookup_by_name (arg, cancellable);
+            print_resolved_addresses (arg, addresses);
+        }
+        catch (const Gio::ResolverError& err)
+        {
+            std::cerr << err.what () << std::endl;
+        }
+    }
+}
+
+static void
+lookup_thread (const Glib::ustring& arg)
+{
+  lookup_one_sync (arg);
+}
+
+static void
+start_threaded_lookups (char **argv, int argc)
+{
+    int i;
+
+    for (i = 0; i < argc; i++)
+        Glib::Thread::create (sigc::bind (sigc::ptr_fun (lookup_thread),
+                                          argv[i]),
+                              false);
+}
+
+static void
+start_sync_lookups (char **argv, int argc)
+{
+    int i;
+
+    for (i = 0; i < argc; i++)
+        lookup_one_sync (argv[i]);
+}
+
+static void
+lookup_by_addr_callback (Glib::RefPtr<Gio::AsyncResult> result,
+                         const Glib::ustring& phys)
+{
+    try
+    {
+        print_resolved_name (phys, resolver->lookup_by_address_finish (result));
+    }
+    catch (const Gio::ResolverError& err)
+    {
+        std::cerr << err.what () << std::endl;
+        done_lookup ();
+    }
+}
+
+static void
+lookup_by_name_callback (Glib::RefPtr<Gio::AsyncResult> result,
+                         const Glib::ustring& name)
+{
+    try
+    {
+        print_resolved_addresses (name, resolver->lookup_by_name_finish (result));
+    }
+    catch (const Gio::ResolverError& err)
+    {
+        std::cerr << err.what () << std::endl;
+    }
+}
+
+static void
+lookup_service_callback (Glib::RefPtr<Gio::AsyncResult> result,
+                         const Glib::ustring& service)
+{
+  try
+  {
+      print_resolved_service (service,
+                              resolver->lookup_service_finish (result));
+  }
+  catch (const Gio::ResolverError& err)
+  {
+      std::cerr << err.what () << std::endl;
+  }
+}
+
+static void
+start_async_lookups (char **argv, int argc)
+{
+    for (int i = 0; i < argc; i++)
+    {
+        Glib::ustring arg (argv[i]);
+        if (arg.find ('/') != std::string::npos)
+        {
+            /* service/protocol/domain */
+            std::vector<Glib::ustring> parts;
+            size_t pos = 0;
+            for (int j = 0; j < 3; ++j)
+            {
+                size_t newpos = arg.find ('/', pos);
+                if (pos == std::string::npos)
+                    usage ();
+                parts.push_back (arg.substr (pos, newpos - pos));
+                pos = newpos;
+            }
+
+            resolver->lookup_service_async (parts[0], parts[1], parts[2],
+                                            sigc::bind (sigc::ptr_fun
+                                                        (lookup_service_callback),
+                                                        Glib::ustring (argv[i])),
+                                            cancellable
+                                            );
+        }
+        else if (Gio::hostname_is_ip_address (argv[i]))
+        {
+            Glib::RefPtr<Gio::InetAddress> addr = Gio::InetAddress::create (argv[i]);
+
+            resolver->lookup_by_address_async (addr,
+                                               sigc::bind (sigc::ptr_fun
+                                                           (lookup_by_addr_callback),
+                                                           argv[i]),
+                                               cancellable);
+        }
+        else
+        {
+            resolver->lookup_by_name_async (argv[i],
+                                            sigc::bind (sigc::ptr_fun
+                                                        (lookup_by_name_callback),
+                                                        argv[i]),
+                                            cancellable);
+        }
+
+        /* Stress-test the reloading code */
+        //g_signal_emit_by_name (resolver, "reload");
+    }
+}
+
+static void
+print_connectable_sockaddr (Glib::RefPtr<Gio::SocketAddress> sockaddr)
+{
+    Glib::ustring phys;
+    Glib::RefPtr<Gio::InetSocketAddress> isa =
+        Glib::RefPtr<Gio::InetSocketAddress>::cast_dynamic (sockaddr);
+
+    if (!isa)
+    {
+        std::cerr <<
+            Glib::ustring::compose ("Error: Unexpected sockaddr type '%1'\n",
+                                    g_type_name_from_instance ((GTypeInstance *)sockaddr->gobj ()));
+    }
+    else
+    {
+        phys = isa->get_address ()->to_string ();
+        std::cout << Glib::ustring::compose ("Address: %1%2%3:%4\n",
+                phys.find (':') != std::string::npos ? "[" : "",
+                phys,
+                phys.find (':') != std::string::npos ? "]" : "",
+                isa->get_port ());
+    }
+}
+
+static void
+do_sync_connectable (Glib::RefPtr<Gio::SocketAddressEnumerator> enumerator)
+{
+    Glib::RefPtr<Gio::SocketAddress> sockaddr;
+
+    while ((sockaddr = enumerator->next (cancellable)))
+        print_connectable_sockaddr (sockaddr);
+
+    done_lookup ();
+}
+
+static void do_async_connectable (Glib::RefPtr<Gio::SocketAddressEnumerator> enumerator);
+
+static void
+got_next_async (Glib::RefPtr<Gio::AsyncResult> result,
+                Glib::RefPtr<Gio::SocketAddressEnumerator> enumerator)
+{
+    g_debug ("%s: enumerator: %p (%d)", G_STRFUNC, enumerator->gobj (), G_OBJECT (enumerator->gobj ())->ref_count);
+    try
+    {
+        Glib::RefPtr<Gio::SocketAddress> sockaddr = enumerator->next_finish (result);
+        if (sockaddr)
+        {
+            print_connectable_sockaddr (sockaddr);
+            do_async_connectable (enumerator);
+        }
+        else
+        {
+            done_lookup ();
+        }
+    }
+    catch (const Gio::ResolverError& err)
+    {
+        std::cerr << err.what () << std::endl;
+    }
+}
+
+Glib::RefPtr<Gio::SocketAddressEnumerator> global_enumerator;
+static void
+do_async_connectable (Glib::RefPtr<Gio::SocketAddressEnumerator> enumerator)
+{
+    g_debug ("%s: enumerator: %p (%d)", G_STRFUNC, enumerator->gobj (), G_OBJECT (enumerator->gobj ())->ref_count);
+    enumerator->next_async (cancellable,
+                            sigc::bind (sigc::ptr_fun (got_next_async),
+                                        enumerator));
+}
+
+Glib::RefPtr<Gio::SocketConnectable> global_connectable;
+
+static void
+do_connectable (const std::string& arg, gboolean synchronous)
+{
+    std::vector<std::string> parts;
+    Glib::RefPtr<Gio::SocketConnectable> connectable;
+    Glib::RefPtr<Gio::SocketAddressEnumerator> enumerator;
+
+    if (arg.find ('/') != std::string::npos)
+    {
+        /* service/protocol/domain */
+        size_t pos = 0;
+        for (int i = 0; i < 3; ++i)
+        {
+            size_t newpos = arg.find ('/', pos);
+            if (pos == std::string::npos)
+                usage ();
+            parts.push_back (arg.substr (pos, newpos - pos));
+            pos = newpos;
+        }
+
+        connectable = Gio::NetworkService::create (parts[0], parts[1], parts[2]);
+    }
+    else
+    {
+        std::string host, port_str;
+        guint16 port;
+
+        size_t pos = arg.find (':');
+        if (pos != std::string::npos)
+        {
+            host = arg.substr (0, pos);
+            port_str = arg.substr(pos);
+            port = strtoul (port_str.c_str (), NULL, 10);
+        }
+        else
+            port = 0;
+
+        if (Gio::hostname_is_ip_address (host))
+        {
+            Glib::RefPtr<Gio::InetAddress> addr = Gio::InetAddress::create (host);
+            connectable = Gio::InetSocketAddress::create (addr, port);
+        }
+        else
+            connectable = Gio::NetworkAddress::create (arg, port);
+    }
+
+    enumerator = connectable->enumerate ();
+    g_debug ("%s: enumerator: %p (%d)", G_STRFUNC, enumerator->gobj (), G_OBJECT (enumerator->gobj ())->ref_count);
+
+    if (synchronous)
+        do_sync_connectable (enumerator);
+    else
+        do_async_connectable (enumerator);
+}
+
+#ifdef G_OS_UNIX
+static int cancel_fds[2];
+
+static void
+interrupted (int sig)
+{
+  signal (SIGINT, SIG_DFL);
+  write (cancel_fds[1], "x", 1);
+}
+
+static bool
+async_cancel (Glib::IOCondition /*cond*/, Glib::RefPtr<Gio::Cancellable> cancellable)
+{
+    cancellable->cancel ();
+    return false;
+}
+#endif
+
+int
+main (int argc, char **argv)
+{
+    bool threaded = false, synchronous = false;
+    bool use_connectable = false;
+#ifdef G_OS_UNIX
+    Glib::RefPtr<Glib::IOChannel> chan;
+    sigc::connection watch_conn;
+#endif
+
+    /* We can't use Glib::OptionContext because we use the arguments to
+     * decide whether or not to call g_thread_init().
+     */
+    while (argc >= 2 && argv[1][0] == '-')
+    {
+        if (!strcmp (argv[1], "-t"))
+        {
+            Glib::thread_init ();
+            threaded = true;
+        }
+        else if (!strcmp (argv[1], "-s"))
+            synchronous = true;
+        else if (!strcmp (argv[1], "-c"))
+            use_connectable = true;
+        else
+            usage ();
+
+        argv++;
+        argc--;
+    }
+    Gio::init ();
+
+    if (argc < 2 || (argc > 2 && use_connectable))
+        usage ();
+
+    resolver = Gio::Resolver::get_default ();
+
+    cancellable = Gio::Cancellable::create ();
+
+#ifdef G_OS_UNIX
+    /* Set up cancellation; we want to cancel if the user ^C's the
+     * program, but we can't cancel directly from an interrupt.
+     */
+    signal (SIGINT, interrupted);
+
+    if (pipe (cancel_fds) == -1)
+    {
+        perror ("pipe");
+        exit (1);
+    }
+    chan = Glib::IOChannel::create_from_fd (cancel_fds[0]);
+    Glib::RefPtr<Glib::IOSource> source = chan->create_watch (Glib::IO_IN);
+    watch_conn = source->connect (sigc::bind (sigc::ptr_fun (async_cancel), cancellable));
+#endif
+
+    nlookups = argc - 1;
+    loop = Glib::MainLoop::create (true);
+
+    if (use_connectable)
+        do_connectable (argv[1], synchronous);
+    else
+    {
+        if (threaded && synchronous)
+            start_threaded_lookups (argv + 1, argc - 1);
+        else if (synchronous)
+            start_sync_lookups (argv + 1, argc - 1);
+        else
+            start_async_lookups (argv + 1, argc - 1);
+    }
+
+    loop->run ();
+
+#ifdef G_OS_UNIX
+    watch_conn.disconnect ();
+#endif
+
+    return 0;
+}
diff --git a/gio/giomm.h b/gio/giomm.h
index 2e393c6..287d6d5 100644
--- a/gio/giomm.h
+++ b/gio/giomm.h
@@ -48,7 +48,10 @@
 #include <giomm/filterinputstream.h>
 #include <giomm/filteroutputstream.h>
 #include <giomm/icon.h>
+#include <giomm/inetaddress.h>
+#include <giomm/inetsocketaddress.h>
 #include <giomm/init.h>
+#include <giomm/initable.h>
 #include <giomm/inputstream.h>
 #include <giomm/iostream.h>
 #include <giomm/loadableicon.h>
@@ -56,8 +59,16 @@
 #include <giomm/memoryoutputstream.h>
 #include <giomm/mount.h>
 #include <giomm/mountoperation.h>
+#include <giomm/networkaddress.h>
+#include <giomm/networkservice.h>
 #include <giomm/outputstream.h>
+#include <giomm/resolver.h>
 #include <giomm/seekable.h>
+#include <giomm/socket.h>
+#include <giomm/socketaddress.h>
+#include <giomm/socketaddressenumerator.h>
+#include <giomm/socketconnectable.h>
+#include <giomm/srvtarget.h>
 #include <giomm/themedicon.h>
 #include <giomm/unixinputstream.h>
 #include <giomm/unixoutputstream.h>
diff --git a/gio/src/error.hg b/gio/src/error.hg
index b7f464f..970b59b 100644
--- a/gio/src/error.hg
+++ b/gio/src/error.hg
@@ -41,6 +41,7 @@ namespace Gio
 /** Exception class for giomm errors.
  */
 _WRAP_GERROR(Error, GIOErrorEnum, G_IO_ERROR, NO_GTYPE)
+_WRAP_GERROR(ResolverError, GResolverError, G_RESOLVER_ERROR, NO_GTYPE)
 
 
 } // namespace Gio
diff --git a/gio/src/inetaddress.ccg b/gio/src/inetaddress.ccg
index c146baa..1ed1a1d 100644
--- a/gio/src/inetaddress.ccg
+++ b/gio/src/inetaddress.ccg
@@ -22,4 +22,9 @@
 namespace Gio
 {
 
+Glib::RefPtr<InetAddress> InetAddress::create(const Glib::ustring& string)
+{
+    return Glib::wrap (g_inet_address_new_from_string (string.c_str ()));
+}
+
 } //namespace Gio
diff --git a/gio/src/inetaddress.hg b/gio/src/inetaddress.hg
index b7ab6b5..ed18433 100644
--- a/gio/src/inetaddress.hg
+++ b/gio/src/inetaddress.hg
@@ -52,7 +52,7 @@ protected:
  // TODO: new_loopback has the same signature as new_any
 
 public:
-  _WRAP_CREATE(const Glib::ustring& string)
+  static Glib::RefPtr<InetAddress> create(const Glib::ustring& string);
   _WRAP_CREATE(const guint8 *bytes, SocketFamily family)
   _WRAP_CREATE(SocketFamily family)
   // TODO: create for new_loopback
diff --git a/gio/src/resolver.ccg b/gio/src/resolver.ccg
index f786bce..1ddc037 100644
--- a/gio/src/resolver.ccg
+++ b/gio/src/resolver.ccg
@@ -182,4 +182,36 @@ Resolver::lookup_service_async(const Glib::ustring& service,
                                    slot_copy);
 }
 
+std::string
+hostname_to_ascii (const Glib::ustring& hostname)
+{
+    Glib::convert_return_gchar_ptr_to_stdstring
+        (g_hostname_to_ascii (hostname.c_str ()));
+}
+
+Glib::ustring
+hostname_to_unicode (const Glib::ustring& hostname)
+{
+    Glib::convert_return_gchar_ptr_to_ustring
+        (g_hostname_to_unicode (hostname.c_str ()));
+}
+
+bool
+hostname_is_non_ascii (const Glib::ustring& hostname)
+{
+    return g_hostname_is_non_ascii (hostname.c_str ());
+}
+
+bool
+hostname_is_ascii_encoded (const Glib::ustring& hostname)
+{
+    return g_hostname_is_ascii_encoded (hostname.c_str ());
+}
+
+bool
+hostname_is_ip_address (const Glib::ustring& hostname)
+{
+    return g_hostname_is_ip_address (hostname.c_str ());
+}
+
 } //namespace Gio
diff --git a/gio/src/resolver.hg b/gio/src/resolver.hg
index dcf5544..d4cf192 100644
--- a/gio/src/resolver.hg
+++ b/gio/src/resolver.hg
@@ -95,4 +95,10 @@ public:
   _WRAP_METHOD(ListHandle_SrvTarget lookup_service_finish(const Glib::RefPtr<AsyncResult>& result), g_resolver_lookup_service_finish, errthrow)
 };
 
+std::string hostname_to_ascii (const Glib::ustring& hostname);
+Glib::ustring hostname_to_unicode (const Glib::ustring& hostname);
+bool hostname_is_non_ascii (const Glib::ustring& hostname);
+bool hostname_is_ascii_encoded (const Glib::ustring& hostname);
+bool hostname_is_ip_address (const Glib::ustring& hostname);
+
 } // namespace Gio



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]