aboutsummaryrefslogtreecommitdiffstats
path: root/e-util/e-host-utils.c
diff options
context:
space:
mode:
Diffstat (limited to 'e-util/e-host-utils.c')
-rw-r--r--e-util/e-host-utils.c185
1 files changed, 176 insertions, 9 deletions
diff --git a/e-util/e-host-utils.c b/e-util/e-host-utils.c
index 1649d14ece..1e9fcbb14c 100644
--- a/e-util/e-host-utils.c
+++ b/e-util/e-host-utils.c
@@ -17,17 +17,27 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
- * Author: Chris Toshok
+ * Author: Chris Toshok, Jeffrey Stedfast
*/
+
+#ifdef HAVE_CONFIG_H
#include <config.h>
+#endif
+
#include <glib.h>
-#include "e-host-utils.h"
-#include <string.h>
-#include <stdlib.h>
+
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
#include <errno.h>
+#include "e-host-utils.h"
+
+
#if !defined (HAVE_GETHOSTBYNAME_R) || !defined (HAVE_GETHOSTBYADDR_R)
G_LOCK_DEFINE_STATIC (gethost_mutex);
#endif
@@ -107,6 +117,44 @@ G_LOCK_DEFINE_STATIC (gethost_mutex);
} \
} G_STMT_END
+
+#ifdef ENABLE_IPv6
+/* some helpful utils for IPv6 lookups */
+#define IPv6_BUFLEN_MIN (sizeof (char *) * 3)
+
+static int
+ai_to_herr (int error)
+{
+ switch (error) {
+ case EAI_NONAME:
+ case EAI_FAIL:
+ return HOST_NOT_FOUND;
+ break;
+ case EAI_SERVICE:
+ return NO_DATA;
+ break;
+ case EAI_ADDRFAMILY:
+ return NO_ADDRESS;
+ break;
+ case EAI_NODATA:
+ return NO_DATA;
+ break;
+ case EAI_MEMORY:
+ return ENOMEM;
+ break;
+ case EAI_AGAIN:
+ return TRY_AGAIN;
+ break;
+ case EAI_SYSTEM:
+ return errno;
+ break;
+ default:
+ return NO_RECOVERY;
+ break;
+ }
+}
+#endif /* ENABLE_IPv6 */
+
/**
* e_gethostbyname_r:
* @name: the host to resolve
@@ -125,6 +173,61 @@ int
e_gethostbyname_r (const char *name, struct hostent *host,
char *buf, size_t buflen, int *herr)
{
+#ifdef ENABLE_IPv6
+ struct addrinfo hints, *res;
+ int retval, len;
+ char *addr;
+
+ memset (&hints, 0, sizeof (struct addrinfo));
+ hints.ai_flags = AI_CANONNAME;
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = 0;
+ hints.ai_protocol = 0;
+
+ if ((retval = getaddrinfo (name, NULL, &hints, &res)) != 0) {
+ *herr = ai_to_herr (retval);
+ return -1;
+ }
+
+ len = strlen (res->ai_canonname);
+ if (buflen < IPv6_BUFLEN_MIN + len + 1 + res->ai_addrlen)
+ return ERANGE;
+
+ /* h_name */
+ strcpy (buf, res->ai_canonname);
+ host->h_name = buf;
+ buf += len;
+
+ /* h_aliases */
+ ((char **) buf)[0] = NULL;
+ host->h_aliases = (char **) buf;
+ buf += sizeof (char *);
+
+ /* h_addrtype and h_length */
+ host->h_length = res->ai_addrlen;
+ if (res->ai_family == PF_INET6) {
+ host->h_addrtype = AF_INET6;
+
+ addr = (char *) &((struct sockaddr_in6 *) res->ai_addr)->sin6_addr;
+ } else {
+ host->h_addrtype = AF_INET;
+
+ addr = (char *) &((struct sockaddr_in *) res->ai_addr)->sin_addr;
+ }
+
+ memcpy (buf, addr, host->h_length);
+ addr = buf;
+ buf += host->h_length;
+
+ /* h_addr_list */
+ ((char **) buf)[0] = addr;
+ ((char **) buf)[1] = NULL;
+ host->h_addr_list = (char **) buf;
+
+ freeaddrinfo (res);
+
+ return 0;
+#else /* No support for IPv6 addresses */
#ifdef HAVE_GETHOSTBYNAME_R
#ifdef GETHOSTBYNAME_R_FIVE_ARGS
if (gethostbyname_r (name, host, buf, buflen, herr))
@@ -140,7 +243,7 @@ e_gethostbyname_r (const char *name, struct hostent *host,
*herr = 0;
return retval;
#endif
-#else
+#else /* No support for gethostbyname_r */
struct hostent *h;
G_LOCK (gethost_mutex);
@@ -153,12 +256,13 @@ e_gethostbyname_r (const char *name, struct hostent *host,
return -1;
}
- GETHOST_PROCESS (h, host,buf, buflen, herr);
+ GETHOST_PROCESS (h, host, buf, buflen, herr);
G_UNLOCK (gethost_mutex);
return 0;
-#endif
+#endif /* HAVE_GETHOSTBYNAME_R */
+#endif /* ENABLE_IPv6 */
}
@@ -182,6 +286,68 @@ int
e_gethostbyaddr_r (const char *addr, int len, int type, struct hostent *host,
char *buf, size_t buflen, int *herr)
{
+#ifdef ENABLE_IPv6
+ struct addrinfo hints, *res;
+ const char *name;
+ int retval, len;
+
+ if ((name = inet_ntop (type, addr, buf, buflen)) == NULL) {
+ if (errno == ENOSPC)
+ return ERANGE;
+
+ return -1;
+ }
+
+ memset (&hints, 0, sizeof (struct addrinfo));
+ hints.ai_flags = AI_CANONNAME;
+ hints.ai_family = type == AF_INET6 ? PF_INET6 : PF_INET;
+ hints.ai_socktype = 0;
+ hints.ai_protocol = 0;
+
+ if ((retval = getaddrinfo (name, NULL, &hints, &res)) != 0) {
+ *herr = ai_to_herr (retval);
+ return -1;
+ }
+
+ len = strlen (res->ai_canonname);
+ if (buflen < IPv6_BUFLEN_MIN + len + 1 + res->ai_addrlen)
+ return ERANGE;
+
+ /* h_name */
+ strcpy (buf, res->ai_canonname);
+ host->h_name = buf;
+ buf += len;
+
+ /* h_aliases */
+ ((char **) buf)[0] = NULL;
+ host->h_aliases = (char **) buf;
+ buf += sizeof (char *);
+
+ /* h_addrtype and h_length */
+ host->h_length = res->ai_addrlen;
+ if (res->ai_family == PF_INET6) {
+ host->h_addrtype = AF_INET6;
+
+ addr = (char *) &((struct sockaddr_in6 *) res->ai_addr)->sin6_addr;
+ } else {
+ host->h_addrtype = AF_INET;
+
+ addr = (char *) &((struct sockaddr_in *) res->ai_addr)->sin_addr;
+ }
+
+ memcpy (buf, addr, host->h_length);
+ addr = buf;
+ buf += host->h_length;
+
+ /* h_addr_list */
+ ((char **) buf)[0] = addr;
+ ((char **) buf)[1] = NULL;
+ host->h_addr_list = (char **) buf;
+
+ freeaddrinfo (res);
+
+ return 0;
+#else /* No support for IPv6 addresses */
#ifdef HAVE_GETHOSTBYADDR_R
#ifdef GETHOSTBYADDR_R_SEVEN_ARGS
if (gethostbyaddr_r (addr, len, type, host, buf, buflen, herr))
@@ -197,7 +363,7 @@ e_gethostbyaddr_r (const char *addr, int len, int type, struct hostent *host,
*herr = 0;
return retval;
#endif
-#else
+#else /* No support for gethostbyaddr_r */
struct hostent *h;
G_LOCK (gethost_mutex);
@@ -215,5 +381,6 @@ e_gethostbyaddr_r (const char *addr, int len, int type, struct hostent *host,
G_UNLOCK (gethost_mutex);
return 0;
-#endif
+#endif /* HAVE_GETHOSTBYADDR_R */
+#endif /* ENABLE_IPv6 */
}