From 89b5ec7066232b37e7d98600597e263f1de201af Mon Sep 17 00:00:00 2001 From: Christian Kellner Date: Sat, 19 Jan 2008 13:15:04 +0100 Subject: [PATCH] Add files that were not added during the last commit --- gnio/gnio.h | 37 +++++ gnio/gnioerror.h | 40 +++++ gnio/gresolver.c | 379 +++++++++++++++++++++++++++++++++++++++++++++++ gnio/gresolver.h | 66 +++++++++ 4 files changed, 522 insertions(+) create mode 100644 gnio/gnio.h create mode 100644 gnio/gnioerror.h create mode 100644 gnio/gresolver.c create mode 100644 gnio/gresolver.h diff --git a/gnio/gnio.h b/gnio/gnio.h new file mode 100644 index 0000000..de14013 --- /dev/null +++ b/gnio/gnio.h @@ -0,0 +1,37 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright (C) 2006-2007 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. + * + * Author: Alexander Larsson + */ + +#ifndef __GNIO_H__ +#define __GNIO_H__ + +#define __GNIO_GNIO_H_INSIDE__ + +#include +#include +#include +#include +#include +#include + +#undef __GNIO_GNIO_H_INSIDE__ + +#endif /* __GNIO_H__ */ diff --git a/gnio/gnioerror.h b/gnio/gnioerror.h new file mode 100644 index 0000000..d188fdb --- /dev/null +++ b/gnio/gnioerror.h @@ -0,0 +1,40 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright (C) 2006-2007 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. + * + * Author: Alexander Larsson + */ + +#ifndef __GNIO_ERROR_H__ +#define __GNIO_ERROR_H__ + +#include + +G_BEGIN_DECLS + +/** + * This would ideally be in gioerror.h's GIOErrorEnum, some extra error codes are needed. + * Just use defines for now. + **/ + +#define G_IO_ERROR_RESOLVER_NOT_FOUND 31 +#define G_IO_ERROR_RESOLVER_NO_DATA 32 + +G_END_DECLS + +#endif /* __G_IO_ERROR_H__ */ diff --git a/gnio/gresolver.c b/gnio/gresolver.c new file mode 100644 index 0000000..af46ae9 --- /dev/null +++ b/gnio/gresolver.c @@ -0,0 +1,379 @@ +/* GNIO - GLib Network Layer of GIO + * + * Copyright (C) 2008 Christian Kellner + * + * 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. + * + * Author: Christian Kellner + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "ginetaddress.h" +#include "ginet4address.h" +#include "ginet6address.h" +#include "gresolver.h" +#include "gnioerror.h" + +G_DEFINE_TYPE (GResolver, g_resolver, G_TYPE_OBJECT); + +#if defined(HAVE_GETHOSTBYNAME_R_GLIB_MUTEX) || defined(HAVE_GETADDRINFO_GLIB_MUTEX) +# ifndef G_THREADS_ENABLED +# error Using GLib Mutex but thread are not enabled. +# endif +G_LOCK_DEFINE (dnslock); +#endif + +#if !defined(HAVE_GETADDRINFO) +static GList * +hostent2list (const struct hostent *he) +{ + GList *list = NULL; + int i; + + g_return_val_if_fail (he != NULL, NULL); + + for (i = 0; he->h_addr_list[i]; i++) + { + GInetAddress *address = NULL; + + if (he->h_addrtype == AF_INET) + address = G_INET_ADDRESS (g_inet4_address_from_bytes ((guint8 *) he->h_addr_list[i])); + else if (he->h_addrtype == AF_INET6) + address = G_INET_ADDRESS (g_inet6_address_from_bytes ((guint8 *) he->h_addr_list[i])); + + list = g_list_prepend (list, address); + } + + return list; +} +#endif + +#if defined(HAVE_GETADDRINFO) +static void +g_io_error_from_addrinfo (GError** error, int err) +{ + GIOErrorEnum code = G_IO_ERROR_FAILED; + const gchar *message = NULL; + + if (error == NULL) + return; + + switch (err) + { + case EAI_NONAME: + code = G_IO_ERROR_RESOLVER_NOT_FOUND; + break; + case EAI_NODATA: + code = G_IO_ERROR_RESOLVER_NO_DATA; + break; + default: + g_warning ("unknown getaddrinfo() error code encountered"); + } + + if (message == NULL) + { + /* FIXME: is gai_strerror() thread-safe? */ + message = gai_strerror (err); + } + + *error = g_error_new_literal (G_IO_ERROR, code, message); +} +#endif + +static GList * +g_resolver_get_host_by_name (GResolver *resolver, const gchar *hostname, GError **error) +{ + GList *list = NULL; + +#if defined(HAVE_GETADDRINFO) + { + struct addrinfo hints; + struct addrinfo *res = NULL, *i; + int rv; + + memset (&hints, 0, sizeof (hints)); + hints.ai_socktype = SOCK_STREAM; + +#ifdef HAVE_GETADDRINFO_GLIB_MUTEX + G_LOCK (dnslock); +#endif + + if ((rv = getaddrinfo (hostname, NULL, &hints, &res))) + g_io_error_from_addrinfo (error, rv); + else + for (i = res; i != NULL; i = i->ai_next) + { + if (i->ai_family == PF_INET) + list = g_list_prepend (list, g_inet4_address_from_bytes ((guint8 *) &(((struct sockaddr_in *) i->ai_addr)->sin_addr.s_addr))); + else if (i->ai_family == PF_INET6) + list = g_list_prepend (list, g_inet6_address_from_bytes ((guint8 *) &(((struct sockaddr_in *) i->ai_addr)->sin_addr.s_addr))); + } + + if (res) + freeaddrinfo (res); + +#ifdef HAVE_GETADDRINFO_GLIB_MUTEX + G_UNLOCK (dnslock); +#endif + } +#elif defined(HAVE_GETHOSTBYNAME_THREADSAFE) + { + struct hostent *he = gethostbyname (hostname); + + if (!he) + g_io_error_from_errno (error); + else + list = hostent2list (he); + } +#elif defined(HAVE_GETHOSTBYNAME_R_GLIBC) + { + struct hostent result, *he; + gsize len = 1024; + gchar *buf = g_new (gchar, len); + gint rv, herr; + + while ((rv = gethostbyname_r (hostname, &result, buf, len, &he, &herr)) == ERANGE) + { + len *= 2; + buf = g_renew (gchar, buf, len); + } + + if (!rv) + list = hostent2list (he); + + g_free (buf); + } +#elif defined(HAVE_GETHOSTBYNAME_R_SOLARIS) + { + struct hostent result, *he; + gsize len = 8192; + char *buf = NULL; + + do + { + buf = g_renew (gchar, buf, len); + errno = 0; + he = gethostbyname_r (hostname, &result, buf, len, &h_errno); + len += 1024; + } + while (errno == ERANGE); + + if (he) + list = hostent2list (&result); + + g_free (buf); + } +#elif defined(HAVE_GETHOSTBYNAME_R_HPUX) + { + struct hostent he; + struct hostent_data buf; + int rv; + + rv = gethostbyname_r (hostname, &he, &buf); + + if (!rv) + list = hostent2list (&he); + } +#else + { + struct hostent *he; + +#ifdef HAVE_GETHOSTBYNAME_R_GLIB_MUTEX + G_LOCK (dnslock); +#endif + + he = gethostbyname (hostname); + list = hostent2list (he); + +#ifdef HAVE_GETHOSTBYNAME_R_GLIB_MUTEX + G_UNLOCK (dnslock); +#endif + } +#endif + + if (list) + list = g_list_reverse (list); + + return list; +} + +static void +g_resolver_class_init (GResolverClass *klass) +{ + GObjectClass *gobject_class G_GNUC_UNUSED = G_OBJECT_CLASS (klass); +} + +static void +g_resolver_init (GResolver *address) +{ + +} + +typedef struct { + GList *list; + const gchar *host; +} ResolveListData; + +static void +resolve_list_thread (GSimpleAsyncResult *res, + GObject *object, + GCancellable *cancellable) +{ + ResolveListData *op; + GError *error = NULL; + + op = g_simple_async_result_get_op_res_gpointer (res); + + op->list = g_resolver_resolve_list (G_RESOLVER (object), op->host, cancellable, &error); + + if (op->list == NULL) + { + g_simple_async_result_set_from_error (res, error); + g_error_free (error); + } +} + +GInetAddress * +g_resolver_resolve (GResolver *resolver, + const char *host, + GCancellable *cancellable, + GError **error) +{ + GList *list; + GInetAddress *address; + + list = g_resolver_get_host_by_name (resolver, host, error); + + if (!list) + return NULL; + + address = G_INET_ADDRESS (g_object_ref (g_list_first (list)->data)); + + g_list_foreach (list, (GFunc) g_object_unref, NULL); + + g_list_free (list); + + return address; +} + +void +g_resolver_resolve_async (GResolver *resolver, + const char *host, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *res; + ResolveListData *op; + + op = g_new (ResolveListData, 1); + + res = g_simple_async_result_new (G_OBJECT (resolver), callback, user_data, g_resolver_resolve_list_async); + + g_simple_async_result_set_op_res_gpointer (res, op, g_free); + + op->host = host; + + g_simple_async_result_run_in_thread (res, resolve_list_thread, G_PRIORITY_DEFAULT, cancellable); + + g_object_unref (res); +} + +GInetAddress * +g_resolver_resolve_finish (GResolver *resolver, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (result); + ResolveListData *op; + GInetAddress *address; + + g_warn_if_fail (g_simple_async_result_get_source_tag (res) == g_resolver_resolve_list_async); + + op = g_simple_async_result_get_op_res_gpointer (res); + + g_simple_async_result_propagate_error (res, error); + + if (op->list == NULL) + return NULL; + + address = G_INET_ADDRESS (g_object_ref (g_list_first (op->list)->data)); + + g_list_foreach (op->list, (GFunc) g_object_unref, NULL); + + g_list_free (op->list); + + return address; +} + +GList * +g_resolver_resolve_list (GResolver *resolver, + const char *host, + GCancellable *cancellable, + GError **error) +{ + return g_resolver_get_host_by_name (resolver, host, error); +} + +void +g_resolver_resolve_list_async (GResolver *resolver, + const char *host, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *res; + ResolveListData *op; + + op = g_new (ResolveListData, 1); + + res = g_simple_async_result_new (G_OBJECT (resolver), callback, user_data, g_resolver_resolve_list_async); + + g_simple_async_result_set_op_res_gpointer (res, op, g_free); + + op->host = host; + + g_simple_async_result_run_in_thread (res, resolve_list_thread, G_PRIORITY_DEFAULT, cancellable); + + g_object_unref (res); +} + +GList * +g_resolver_resolve_list_finish (GResolver *resolver, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (result); + ResolveListData *op; + + g_warn_if_fail (g_simple_async_result_get_source_tag (res) == g_resolver_resolve_list_async); + + op = g_simple_async_result_get_op_res_gpointer (res); + + g_simple_async_result_propagate_error (res, error); + + return op->list; +} + diff --git a/gnio/gresolver.h b/gnio/gresolver.h new file mode 100644 index 0000000..33e935e --- /dev/null +++ b/gnio/gresolver.h @@ -0,0 +1,66 @@ +#ifndef G_RESOLVER_H +#define G_RESOLVER_H + +#include +#include + +#include "ginetaddress.h" + +G_BEGIN_DECLS + +#define G_TYPE_RESOLVER (g_resolver_get_type ()) +#define G_RESOLVER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_RESOLVER, GResolver)) +#define G_RESOLVER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_RESOLVER, GResolverClass)) +#define G_IS_RESOLVER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_RESOLVER)) +#define G_IS_RESOLVER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_RESOLVER)) +#define G_RESOLVER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_RESOLVER, GResolver)) + +typedef struct _GResolver GResolver; +typedef struct _GResolverClass GResolverClass; + +struct _GResolver +{ + GObject parent; +}; + +struct _GResolverClass +{ + GObjectClass parent_class; +}; + +GType g_resolver_get_type (void) G_GNUC_CONST; + +GInetAddress * g_resolver_resolve (GResolver *resolver, + const char *host, + GCancellable *cancellable, + GError **error); + +void g_resolver_resolve_async (GResolver *resolver, + const char *host, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +GInetAddress * g_resolver_resolve_finish (GResolver *resolver, + GAsyncResult *result, + GError **error); + +GList * g_resolver_resolve_list (GResolver *resolver, + const char *host, + GCancellable *cancellable, + GError **error); + +void g_resolver_resolve_list_async (GResolver *resolver, + const char *host, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +GList * g_resolver_resolve_list_finish (GResolver *resolver, + GAsyncResult *result, + GError **error); + +G_END_DECLS + +#endif /* G_RESOLVER_H */ + -- 2.20.1