diff --git a/configure.ac b/configure.ac
index 5a6a72a..94c2947 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2436,6 +2436,12 @@ if test "${HAVE_GETADDRINFO_A}" = "yes"; then
AC_SUBST(GETADDRINFO_A_LIBS)
fi
+AC_CHECK_HEADER(CFNetwork/CFHost.h,
+ dnl XXX: Do we need to test for existence here?
+ LIBS="$LIBS -framework CFNetwork"
+ AC_DEFINE(HAVE_CFHOSTCREATEWITHNAME, 1,
+[Define to 1 if you have CFHostCreateWithName for asynchronous DNS resolution.]))
+
HAVE_GTK=no
GTK_OBJ=
gtk_term_header=$term_header
diff --git a/src/process.c b/src/process.c
index 2b674e5..de27c31 100644
--- a/src/process.c
+++ b/src/process.c
@@ -87,6 +87,10 @@ along with GNU Emacs. If not, see . */
#include
#include
+#ifdef HAVE_CFHOSTCREATEWITHNAME
+#include
+#endif
+
#endif /* subprocesses */
#include "systime.h"
@@ -125,6 +129,10 @@ along with GNU Emacs. If not, see . */
#define ASYNC_RETRY_NSEC 100000000
#endif
+#ifdef HAVE_CFHOSTCREATEWITHNAME
+static void host_client_callback (CFHostRef, CFHostInfoType, const CFStreamError *, void *);
+#endif
+
#ifdef WINDOWSNT
extern int sys_select (int, fd_set *, fd_set *, fd_set *,
struct timespec *, void *);
@@ -733,15 +741,24 @@ remove_process (register Lisp_Object proc)
deactivate_process (proc);
}
-#ifdef HAVE_GETADDRINFO_A
+#if defined HAVE_GETADDRINFO_A || defined HAVE_CFHOSTCREATEWITHNAME
static void
free_dns_request (Lisp_Object proc)
{
struct Lisp_Process *p = XPROCESS (proc);
+#ifdef HAVE_GETADDRINFO_A
if (p->dns_request->ar_result)
freeaddrinfo (p->dns_request->ar_result);
xfree (p->dns_request);
+#elif defined HAVE_CFHOSTCREATEWITHNAME
+ CFRunLoopRef run_loop = CFRunLoopGetCurrent ();
+ CFHostUnscheduleFromRunLoop (p->dns_request, run_loop, kCFRunLoopDefaultMode);
+ CFHostCancelInfoResolution (p->dns_request, kCFHostAddresses);
+ CFRelease (p->dns_request);
+ xfree (p->dns_error);
+ p->dns_error = NULL;
+#endif
p->dns_request = NULL;
}
#endif
@@ -853,6 +870,10 @@ nil, indicating the current buffer's process. */)
if (canceled)
free_dns_request (process);
}
+#elif defined HAVE_CFHOSTCREATEWITHNAME
+ if (p->dns_request)
+ /* free_dns_request will cancel the request for us. */
+ free_dns_request (process);
#endif
p->raw_status_new = 0;
@@ -3611,6 +3632,9 @@ usage: (make-network-process &rest ARGS) */)
int ai_protocol = 0;
#ifdef HAVE_GETADDRINFO_A
struct gaicb *dns_request = NULL;
+#elif defined HAVE_CFHOSTCREATEWITHNAME
+ CFHostRef dns_request = NULL;
+ CFStreamError *dns_error = NULL;
#endif
ptrdiff_t count = SPECPDL_INDEX ();
@@ -3791,7 +3815,41 @@ usage: (make-network-process &rest ARGS) */)
goto open_socket;
}
-#endif /* HAVE_GETADDRINFO_A */
+#elif defined(HAVE_CFHOSTCREATEWITHNAME)
+ if (!NILP (host) && !NILP (Fplist_get (contact, QCnowait)))
+ {
+ CFStringRef stringref;
+
+ stringref = CFStringCreateWithCString (NULL, SSDATA (host),
+ kCFStringEncodingASCII);
+ if (! stringref)
+ error ("%s CFStringCreateWithCString error", SSDATA (host));
+ /* XXX: when should I deallocate stringref? */
+ dns_request = CFHostCreateWithName (NULL, stringref);
+ if (! dns_request)
+ error ("%s CFHostCreateWithName error", SSDATA (host));
+
+ dns_error = xmalloc (sizeof *dns_error);
+ memset (dns_error, 0, sizeof *dns_error);
+ CFHostClientContext client_context;
+ memset (&client_context, 0, sizeof client_context);
+ client_context.version = 0;
+ client_context.info = (void*)dns_error;
+ if (! CFHostSetClient (dns_request, host_client_callback, &client_context))
+ error ("%s CFHostSetClient error", SSDATA (host));
+
+ CFRunLoopRef run_loop = CFRunLoopGetCurrent ();
+ CFHostScheduleWithRunLoop (dns_request, run_loop, kCFRunLoopDefaultMode);
+
+ /* TODO: need error information? */
+ if (! CFHostStartInfoResolution (dns_request, kCFHostAddresses, NULL))
+ error ("%s CFHostStartInfoResolution error", SSDATA (host));
+
+ /* Unlike getaddrinfo_a, this doesn't resolve the service name
+ for us. */
+ goto resolve_service;
+ }
+#endif /* HAVE_GETADDRINFO_A | HAVE_CFHOSTCREATEWITHNAME */
/* If we have a host, use getaddrinfo to resolve both host and service.
Otherwise, use getservbyname to lookup the service. */
@@ -3842,6 +3900,8 @@ usage: (make-network-process &rest ARGS) */)
/* No hostname has been specified (e.g., a local server process). */
+ resolve_service:
+
if (EQ (service, Qt))
port = 0;
else if (INTEGERP (service))
@@ -3903,6 +3963,9 @@ usage: (make-network-process &rest ARGS) */)
p->ai_protocol = ai_protocol;
#ifdef HAVE_GETADDRINFO_A
p->dns_request = NULL;
+#elif defined HAVE_CFHOSTCREATEWITHNAME
+ p->dns_request = NULL;
+ p->dns_error = NULL;
#endif
#ifdef HAVE_GNUTLS
tem = Fplist_get (contact, QCtls_parameters);
@@ -3930,12 +3993,15 @@ usage: (make-network-process &rest ARGS) */)
&& !NILP (Fplist_get (contact, QCnowait)))
p->is_non_blocking_client = true;
-#ifdef HAVE_GETADDRINFO_A
+#if defined HAVE_GETADDRINFO_A || defined HAVE_CFHOSTCREATEWITHNAME
/* With async address resolution, the list of addresses is empty, so
postpone connecting to the server. */
if (!p->is_server && NILP (ip_addresses))
{
p->dns_request = dns_request;
+#ifdef HAVE_CFHOSTCREATEWITHNAME
+ p->dns_error = dns_error;
+#endif
p->status = Qconnect;
return proc;
}
@@ -4644,7 +4710,21 @@ server_accept_connection (Lisp_Object server, int channel)
exec_sentinel (proc, concat3 (open_from, host_string, nl));
}
-#ifdef HAVE_GETADDRINFO_A
+#ifdef HAVE_CFHOSTCREATEWITHNAME
+static void
+host_client_callback (CFHostRef theHost, CFHostInfoType typeInfo, const CFStreamError *error, void *info)
+{
+ if (error)
+ {
+ CFStreamError *dns_error = (CFStreamError *)info;
+ /* XXX: how can I know that the process hasn't been deallocated? */
+ dns_error->domain = error->domain;
+ dns_error->error = error->error;
+ }
+}
+#endif
+
+#if defined HAVE_GETADDRINFO_A || defined HAVE_CFHOSTCREATEWITHNAME
static Lisp_Object
check_for_dns (Lisp_Object proc)
{
@@ -4655,6 +4735,7 @@ check_for_dns (Lisp_Object proc)
if (! p->dns_request)
return Qnil;
+#ifdef HAVE_GETADDRINFO_A
int ret = gai_error (p->dns_request);
if (ret == EAI_INPROGRESS)
return Qt;
@@ -4683,6 +4764,55 @@ check_for_dns (Lisp_Object proc)
build_string (p->dns_request->ar_name),
build_string (" failed")))));
}
+#elif defined HAVE_CFHOSTCREATEWITHNAME
+
+ Boolean has_been_resolved;
+ CFArrayRef res;
+
+ res = CFHostGetAddressing (p->dns_request, &has_been_resolved);
+
+ /* XXX: if has_been_resolved is false, does that mean there was an error? */
+ if (has_been_resolved && res)
+ {
+ CFIndex n;
+ n = CFArrayGetCount (res);
+ for (CFIndex i = 0; i < n; i++)
+ {
+ CFDataRef entry = CFArrayGetValueAtIndex (res, i);
+ const struct sockaddr *addr = (const struct sockaddr *) CFDataGetBytePtr (entry);
+ CFIndex len = CFDataGetLength (entry);
+ /* Need to insert the port number. */
+ struct sockaddr *addr_with_port = xmalloc (len);
+ memcpy (addr_with_port, addr, len);
+ /* XXX: this should work for IPv4 and IPv6, I think */
+ ((struct sockaddr_in*)addr_with_port)->sin_port = htons (p->port);
+ ip_addresses = Fcons (conv_sockaddr_to_lisp
+ (addr_with_port, len),
+ ip_addresses);
+ xfree (addr_with_port);
+
+ ip_addresses = Fnreverse (ip_addresses);
+ }
+ }
+ else if (p->dns_error->domain)
+ {
+ add_to_log ("async DNS resulution error"); /* XXX */
+ deactivate_process (proc);
+ pset_status (p, (list2
+ (Qfailed,
+ concat2 (
+ concat2 (build_string ("Name lookup failed; error domain "),
+ Fnumber_to_string (make_number (p->dns_error->domain))),
+ concat2 (build_string (", error number "),
+ Fnumber_to_string (make_number (p->dns_error->error)))))));
+ }
+ else
+ {
+ /* Still in progress ??? */
+ add_to_log ("Name resolution still in progress"); /* XXX */
+ return Qt;
+ }
+#endif
free_dns_request (proc);
@@ -4693,7 +4823,7 @@ check_for_dns (Lisp_Object proc)
return ip_addresses;
}
-#endif /* HAVE_GETADDRINFO_A */
+#endif /* HAVE_GETADDRINFO_A || HAVE_CFHOSTCREATEWITHNAME */
static void
wait_for_socket_fds (Lisp_Object process, char const *name)
@@ -4805,9 +4935,10 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
Lisp_Object proc;
struct timespec timeout, end_time, timer_delay;
struct timespec got_output_end_time = invalid_timespec ();
+#undef INFINITY
enum { MINIMUM = -1, TIMEOUT, INFINITY } wait;
int got_some_output = -1;
-#if defined HAVE_GETADDRINFO_A || defined HAVE_GNUTLS
+#if defined HAVE_GETADDRINFO_A || defined HAVE_CFHOSTCREATEWITHNAME || defined HAVE_GNUTLS
bool retry_for_async;
#endif
ptrdiff_t count = SPECPDL_INDEX ();
@@ -4857,7 +4988,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
if (! NILP (wait_for_cell) && ! NILP (XCAR (wait_for_cell)))
break;
-#if defined HAVE_GETADDRINFO_A || defined HAVE_GNUTLS
+#if defined HAVE_GETADDRINFO_A || defined HAVE_CFHOSTCREATEWITHNAME || defined HAVE_GNUTLS
{
Lisp_Object process_list_head, aproc;
struct Lisp_Process *p;
@@ -4869,7 +5000,7 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd,
if (! wait_proc || p == wait_proc)
{
-#ifdef HAVE_GETADDRINFO_A
+#if defined HAVE_GETADDRINFO_A || defined HAVE_CFHOSTCREATEWITHNAME
/* Check for pending DNS requests. */
if (p->dns_request)
{
diff --git a/src/process.h b/src/process.h
index bf1eadc..e47a53e 100644
--- a/src/process.h
+++ b/src/process.h
@@ -25,6 +25,10 @@ along with GNU Emacs. If not, see . */
#include
+#ifdef HAVE_CFHOSTCREATEWITHNAME
+#include
+#endif
+
#ifdef HAVE_GNUTLS
#include "gnutls.h"
#endif
@@ -180,6 +184,9 @@ struct Lisp_Process
/* Whether the socket is waiting for response from an asynchronous
DNS call. */
struct gaicb *dns_request;
+#elif defined (HAVE_CFHOSTCREATEWITHNAME)
+ CFHostRef dns_request;
+ CFStreamError *dns_error;
#endif
#ifdef HAVE_GNUTLS