[Patch] gethostbyname2

Pierre A. Humblet pierre@phumblet.no-ip.org
Thu Feb 26 04:03:00 GMT 2009


I tried to compile Exim with IPv6 enabled and Cygwin 1.7, but it 
needs gethostbyname2.
Here is an implementation of that function.
In attachment I am including the same patch as well as a short test function.

Pierre



2009-02-25  Pierre Humblet <Pierre.Humblet@ieee.org>

	* net.cc: Include windns.h.
	(gethostbyname2): New function.
	* cygwin.din: Export gethostbyname2.


Index: cygwin.din
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/cygwin.din,v
retrieving revision 1.202
diff -u -p -r1.202 cygwin.din
--- cygwin.din	19 Feb 2009 09:22:51 -0000	1.202
+++ cygwin.din	26 Feb 2009 03:54:30 -0000
@@ -635,6 +635,7 @@ _getgroups = getgroups SIGFE
  _getgroups32 = getgroups32 SIGFE
  gethostbyaddr = cygwin_gethostbyaddr SIGFE
  gethostbyname = cygwin_gethostbyname SIGFE
+gethostbyname2 SIGFE
  gethostid SIGFE
  gethostname = cygwin_gethostname SIGFE
  _gethostname = cygwin_gethostname SIGFE
Index: net.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/net.cc,v
retrieving revision 1.248
diff -u -p -r1.248 net.cc
--- net.cc	16 Sep 2008 02:04:27 -0000	1.248
+++ net.cc	26 Feb 2009 03:54:31 -0000
@@ -25,6 +25,7 @@ details. */
  #include <netdb.h>
  #define USE_SYS_TYPES_FD_SET
  #include <winsock2.h>
+#include <windns.h>
  #include <iphlpapi.h>
  #include <assert.h>
  #include "cygerrno.h"
@@ -888,6 +889,157 @@ cygwin_gethostbyaddr (const char *addr,
    return res;
  }

+/* gethostbyname2: standards? */
+extern "C" struct hostent *
+gethostbyname2 (const char *name, int af)
+{
+  sig_dispatch_pending ();
+  myfault efault;
+  if (efault.faulted (EFAULT))
+    return NULL;
+
+  DWORD type;
+  hostent tmp, *h = NULL;
+  tmp.h_name = NULL;
+  tmp.h_aliases = NULL;
+  tmp.h_addrtype = af;
+  switch (af)
+    {
+    case AF_INET:
+      tmp.h_length = sizeof (IP4_ADDRESS);
+      type = DNS_TYPE_A;
+      break;
+    case AF_INET6:
+      tmp.h_length = sizeof (IP6_ADDRESS);
+      type = DNS_TYPE_AAAA;
+      break;
+    default:
+      set_errno (EAFNOSUPPORT);
+      h_errno = NETDB_INTERNAL;
+      return NULL;
+    }
+
+  PDNS_RECORD pQueryResultsSet, rr;
+  /* Normal query, including search */
+  DNS_STATUS res = DnsQuery_A (name, type, DNS_QUERY_STANDARD,
+			       NULL, &pQueryResultsSet, NULL);
+
+  debug_printf ("DnsQuery: %s type = %d res = %lu\n", name, type, res);
+
+  // NETDB_INTERNAL -1 /* see errno */
+  // HOST_NOT_FOUND  1 /* Authoritative Answer Host not found */
+  // TRY_AGAIN       2 /* Non-Authoritive Host not found, or SERVERFAIL */
+  // NO_RECOVERY     3 /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */
+  // NO_DATA         4 /* Valid name, no data record of requested type */
+
+  switch (res)
+    {
+    case ERROR_SUCCESS:
+      break;
+    case ERROR_INVALID_NAME:
+      set_errno (EINVAL);
+      h_errno = NETDB_INTERNAL;;
+      return NULL;
+    case ERROR_TIMEOUT:
+    case DNS_ERROR_RCODE_SERVER_FAILURE:
+      h_errno = TRY_AGAIN;
+      return NULL;
+    case DNS_ERROR_RCODE_NAME_ERROR:
+      h_errno = HOST_NOT_FOUND;
+      return NULL;
+    case DNS_ERROR_NO_DNS_SERVERS:
+    case DNS_ERROR_RCODE_FORMAT_ERROR:
+    case DNS_ERROR_RCODE_NOT_IMPLEMENTED:
+    case DNS_ERROR_RCODE_REFUSED:
+      h_errno = NO_RECOVERY;
+      return NULL;
+    case DNS_INFO_NO_RECORDS:  /* May be returned when the host 
doesn't exist */
+      h_errno = NO_DATA;
+      return NULL;
+    default:
+      debug_printf ("Unknown code\n");
+      h_errno = NO_RECOVERY;
+      return NULL;
+    }
+
+  const int RECORD_INC = 16;
+  int record_size = 0;
+  int alias_count = 0;
+  int address_count = 0;
+  for (rr = pQueryResultsSet; rr; rr = rr->pNext)
+    {
+      debug_printf ("%s Section %d Type %u Size %d\n",
+		    rr->pName, rr->Flags.S.Section, rr->wType, rr->wDataLength);
+      /* Normally DnsQuery does not provide Question section records and we
+	 should only consider Answer section records.
+	 However DnsQuery seems to return only Question records (with data)
+	 for local names and numeric addresses */
+      if (!((rr->Flags.S.Section == DnsSectionAnswer)
+	    || (rr->Flags.S.Section == DnsSectionQuestion)))
+	continue;
+
+      /* Alloc space, including two null entries */
+      if ((alias_count + address_count + 2) >= record_size)
+	{
+	  void * ptr = realloc (tmp.h_aliases,
+				sizeof (char *)*(record_size += RECORD_INC));
+	  if (!ptr)
+	    {
+	      h_errno = NETDB_INTERNAL;
+	      address_count = -1; /* Flag error */
+	      break;
+	    }
+	  tmp.h_aliases = (char **) ptr;
+	}
+
+      switch (rr->wType)
+	{
+	case DNS_TYPE_CNAME:
+	  /* The CNAME records are supposed to form a chain.
+	     We trust the resolver.
+	     Move the addresses. This should never be needed. */
+	  for (int i = address_count; i > 0; i--)
+	    tmp.h_aliases[alias_count + 1 + i] = tmp.h_aliases[alias_count + i];
+	  tmp.h_aliases[alias_count++] = rr->pName;
+	  break;
+	case DNS_TYPE_A:
+	  /* The address records should all have as pName the last canonical name.
+	     We trust the resolver */
+	  if ((af == AF_INET)
+	      && (rr->wDataLength == sizeof (IP4_ADDRESS)))
+	    {
+	      tmp.h_aliases[alias_count + ++address_count] = (char *) & 
rr->Data.A.IpAddress;
+	      tmp.h_name = rr->pName;
+	    }
+	  break;
+	case DNS_TYPE_AAAA:
+	  if ((af == AF_INET6)
+	      && (rr->wDataLength == sizeof (IP6_ADDRESS)))
+	    {
+	      tmp.h_aliases[alias_count + ++address_count] = (char *) & 
rr->Data.AAAA.Ip6Address;
+	      tmp.h_name = rr->pName;
+	    }
+	  break;
+	default:
+	  continue;
+	}
+      }
+
+  if (address_count == 0)
+    h_errno = NO_DATA;
+  else if (address_count > 0)
+    {
+      tmp.h_aliases[alias_count] = NULL;
+      tmp.h_addr_list = & tmp.h_aliases[alias_count + 1];
+      tmp.h_addr_list[address_count] = NULL;
+      if (!(h = dup_ent (&tmp)))
+	h_errno = NETDB_INTERNAL;
+    }
+  DnsRecordListFree (pQueryResultsSet, DnsFreeRecordList);
+  free (tmp.h_aliases);
+  return h;
+}
+
  /* exported as accept: standards? */
  extern "C" int
  cygwin_accept (int fd, struct sockaddr *peer, socklen_t *len)
-------------- next part --------------
A non-text attachment was scrubbed...
Name: try_gethostbyname.c
Type: application/octet-stream
Size: 1008 bytes
Desc: not available
URL: <http://cygwin.com/pipermail/cygwin-patches/attachments/20090226/5ad49eb3/attachment.obj>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: net.cc
Type: application/octet-stream
Size: 113672 bytes
Desc: not available
URL: <http://cygwin.com/pipermail/cygwin-patches/attachments/20090226/5ad49eb3/attachment-0001.obj>


More information about the Cygwin-patches mailing list