/*
- * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 1999-2007 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
- * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
- * Reserved. This file contains Original Code and/or Modifications of
- * Original Code as defined in and that are subject to the Apple Public
- * Source License Version 1.0 (the 'License'). You may not use this file
- * except in compliance with the License. Please obtain a copy of the
- * License at http://www.apple.com/publicsource and read it before using
- * this file.
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
- * License for the specific language governing rights and limitations
- * under the License."
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
char *qname;
pdns_handle_t **pdns;
uint32_t pdns_count;
- int i, n, m;
+ int i, n;
+ int m, tmin, minstate;
pdns = NULL;
pdns_count = 0;
n = -1;
+ minstate = 0;
+ *min = -1;
+ m = -1;
pdns_count = _pdns_get_handles_for_name(sdns, name, &pdns);
for (i = 0; i < pdns_count; i++)
{
- m = -1;
- n = _pdns_query(sdns, pdns[i], qname, class, type, buf, len, from, fromlen, &m);
- if (min != NULL)
+ tmin = -1;
+ n = _pdns_query(sdns, pdns[i], qname, class, type, buf, len, from, fromlen, &tmin);
+ if (n <= 0)
{
- if (*min == -1) *min = m;
- else if ((m >= 0) && (m < *min)) *min = m;
+ if (tmin < 0)
+ {
+ minstate = -1;
+ }
+ else if (minstate == 0)
+ {
+ if (m == -1) m = tmin;
+ else if (tmin < m) m = tmin;
+ }
}
if (n > 0) break;
}
+ if (minstate == 0) *min = m;
+
free(pdns);
free(qname);
return n;
_sdns_search(sdns_handle_t *sdns, const char *name, uint32_t class, uint32_t type, uint32_t fqdn, uint32_t recurse, char *buf, uint32_t len, struct sockaddr *from, uint32_t *fromlen, int *min)
{
pdns_handle_t *primary, **pdns;
- int i, n, ndots, status, m;
+ int i, n, ndots, status;
+ int m, tmin, minstate;
char *dot, *qname;
uint32_t pdns_count;
if (sdns == NULL) return -1;
if (name == NULL) return -1;
+ /*
+ * A minimum TTL derived from the minimim of all SOA records
+ * that are received with NXDOMAIN or no data is returned to
+ * the caller if every call returns an NXDOMAIN or no data
+ * and a SOA min ttl. If any call times out or returns some
+ * other error, we return "-1" in the "min" out parameter.
+ * The minstate variable is set to -1 if we must return -1.
+ */
+ minstate = 0;
+ *min = -1;
+
+ /* m is the lowest of all minima. -1 is unset */
+ m = -1;
+
/* ndots is the threshold for trying a qualified name "as is" */
ndots = 1;
primary = sdns->pdns_primary;
*/
if ((n >= ndots) || (fqdn == 1) || (type == ns_t_ptr))
{
- status = _sdns_send(sdns, name, class, type, fqdn, buf, len, from, fromlen, min);
+ tmin = -1;
+ status = _sdns_send(sdns, name, class, type, fqdn, buf, len, from, fromlen, &tmin);
if (status > 0) return status;
+
+ if (tmin < 0) minstate = -1;
+ else m = tmin;
}
/* end of the line for FQDNs or PTR queries */
- if (fqdn == 1) return -1;
- if (type == ns_t_ptr) return -1;
-
- if (recurse == 0) return -1;
- if (primary == NULL) return -1;
+ if ((fqdn == 1) || (type == ns_t_ptr) || (recurse == 0) || (primary == NULL))
+ {
+ if (minstate == 0) *min = m;
+ return -1;
+ }
/* Try appending names from the search list */
if (primary->search_count == SEARCH_COUNT_INIT) _pdns_process_res_search_list(primary);
asprintf(&qname, "%s.%s", name, primary->search_list[i]);
if (qname == NULL) return -1;
- m = -1;
- status = _sdns_search(sdns, qname, class, type, fqdn, 0, buf, len, from, fromlen, &m);
+ tmin = -1;
+ status = _sdns_search(sdns, qname, class, type, fqdn, 0, buf, len, from, fromlen, &tmin);
+ if (status <= 0)
{
- if (*min == -1) *min = m;
- else if ((m >= 0) && (m < *min)) *min = m;
+ if (tmin < 0)
+ {
+ minstate = -1;
+ }
+ else if (minstate == 0)
+ {
+ if (m == -1) m = tmin;
+ else if (tmin < m) m = tmin;
+ }
}
-
+
free(qname);
if (status > 0) return status;
}
+ if (minstate == 0) *min = m;
return -1;
}
pdns_count = _pdns_get_default_handles(sdns, &pdns);
status = -1;
- if (pdns_count == 0) return -1;
+ if (pdns_count == 0)
+ {
+ if (minstate == 0) *min = m;
+ return -1;
+ }
for (i = 0; i < pdns_count; i++)
{
qname = NULL;
if (pdns[i]->name == NULL) asprintf(&qname, "%s", name);
else asprintf(&qname, "%s.%s", name, pdns[i]->name);
+
+ /* leave *min at -1 in case of a malloc failure */
if (qname == NULL) return -1;
- m = -1;
- status = _pdns_query(sdns, pdns[i], qname, class, type, buf, len, from, fromlen, min);
+ tmin = -1;
+ status = _pdns_query(sdns, pdns[i], qname, class, type, buf, len, from, fromlen, &tmin);
+ if (status <= 0)
{
- if (*min == -1) *min = m;
- else if ((m >= 0) && (m < *min)) *min = m;
+ if (tmin < 0)
+ {
+ minstate = -1;
+ }
+ else if (minstate == 0)
+ {
+ if (m == -1) m = tmin;
+ else if (tmin < m) m = tmin;
+ }
}
-
+
free(qname);
if (status > 0) break;
}
free(pdns);
+
+ if (minstate == 0) *min = m;
return status;
}
/*
- * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2003-2006 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
- * "Portions Copyright (c) 2003 Apple Computer, Inc. All Rights
- * Reserved. This file contains Original Code and/or Modifications of
- * Original Code as defined in and that are subject to the Apple Public
- * Source License Version 1.0 (the 'License'). You may not use this file
- * except in compliance with the License. Please obtain a copy of the
- * License at http://www.apple.com/publicsource and read it before using
- * this file.
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
- * License for the specific language governing rights and limitations
- * under the License."
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
- * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 1999-2007 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
- * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
- * Reserved. This file contains Original Code and/or Modifications of
- * Original Code as defined in and that are subject to the Apple Public
- * Source License Version 1.0 (the 'License'). You may not use this file
- * except in compliance with the License. Please obtain a copy of the
- * License at http://www.apple.com/publicsource and read it before using
- * this file.
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
- * License for the specific language governing rights and limitations
- * under the License."
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
if (!strcasecmp(t, "PTR")) { *n = ns_t_ptr; return 0; }
if (!strcasecmp(t, "HINFO")) { *n = ns_t_hinfo; return 0; }
if (!strcasecmp(t, "MINFO")) { *n = ns_t_minfo; return 0; }
+ if (!strcasecmp(t, "MX")) { *n = ns_t_mx; return 0; }
if (!strcasecmp(t, "TXT")) { *n = ns_t_txt; return 0; }
if (!strcasecmp(t, "RP")) { *n = ns_t_rp; return 0; }
if (!strcasecmp(t, "AFSDB")) { *n = ns_t_afsdb; return 0; }
/*
- * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2003-2006 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
- * "Portions Copyright (c) 2003 Apple Computer, Inc. All Rights
- * Reserved. This file contains Original Code and/or Modifications of
- * Original Code as defined in and that are subject to the Apple Public
- * Source License Version 1.0 (the 'License'). You may not use this file
- * except in compliance with the License. Please obtain a copy of the
- * License at http://www.apple.com/publicsource and read it before using
- * this file.
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
- * License for the specific language governing rights and limitations
- * under the License."
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
int dns_res_once(struct sockaddr *server, struct timeval *timeout, int options, const char *name, int class, int type, u_char *res, int *reslen);
+/*
+ * Interrupt a thread blocked in select()
+ */
+void res_interrupt_requests_enable(void);
+void res_interrupt_requests_disable(void);
+void res_interrupt_requests(void* token);
+void* res_init_interrupt_token(void);
+void res_delete_interrupt_token(void* token);
+
#endif
return (n);
}
- if (hp->rcode != ns_r_noerror || ntohs(hp->ancount) == 0)
+ if ((hp->rcode == ns_r_nxdomain) || ((hp->rcode == ns_r_noerror) && (ntohs(hp->ancount) == 0)))
{
if (min != NULL)
{
*min = res_soa_minimum(answer, anslen);
- if (statp->options & RES_DEBUG) printf(";; res_nquery: SOA minimum = %d\n", *min);
+ if (statp->options & RES_DEBUG) printf(";; res_nquery: SOA minimum TTL = %d\n", *min);
}
+ }
+ if (hp->rcode != ns_r_noerror || ntohs(hp->ancount) == 0)
+ {
#ifdef DEBUG
if (statp->options & RES_DEBUG) printf(";; rcode = %d, ancount=%d\n", hp->rcode, ntohs(hp->ancount));
#endif
#include "res_debug.h"
#include "res_private.h"
+#include <sys/fcntl.h>
#define EXT(res) ((res)->_u._ext)
#endif
static const int niflags = NI_NUMERICHOST | NI_NUMERICSERV;
+static int interrupt_pipe_enabled = 0;
+static pthread_key_t interrupt_pipe_key;
+
+void
+res_delete_interrupt_token(void *token)
+{
+ int *interrupt_pipe;
+
+ interrupt_pipe = token;
+ if (interrupt_pipe == NULL) return;
+
+ if (interrupt_pipe[0] >= 0)
+ {
+ close(interrupt_pipe[0]);
+ interrupt_pipe[0] = -1;
+ }
+
+ if (interrupt_pipe[1] >= 0)
+ {
+ close(interrupt_pipe[1]);
+ interrupt_pipe[1] = -1;
+ }
+
+ pthread_setspecific(interrupt_pipe_key, NULL);
+ free(interrupt_pipe);
+}
+
+void *
+res_init_interrupt_token(void)
+{
+ int *interrupt_pipe;
+
+ interrupt_pipe = (int *)malloc(2 * sizeof(int));
+ if (interrupt_pipe == NULL) return NULL;
+
+ if (pipe(interrupt_pipe) < 0)
+ {
+ /* this shouldn't happen */
+ interrupt_pipe[0] = -1;
+ interrupt_pipe[1] = -1;
+ }
+ else
+ {
+ fcntl(interrupt_pipe[0], F_SETFD, FD_CLOEXEC | O_NONBLOCK);
+ fcntl(interrupt_pipe[1], F_SETFD, FD_CLOEXEC | O_NONBLOCK);
+ }
+
+ pthread_setspecific(interrupt_pipe_key, interrupt_pipe);
+
+ return interrupt_pipe;
+}
+
+void
+res_interrupt_requests_enable(void)
+{
+ interrupt_pipe_enabled = 1;
+ pthread_key_create(&interrupt_pipe_key, NULL);
+}
+
+void
+res_interrupt_requests_disable(void)
+{
+ interrupt_pipe_enabled = 0;
+ pthread_key_delete(interrupt_pipe_key);
+}
+
+void
+res_interrupt_request(void *token)
+{
+ int oldwrite;
+ int *interrupt_pipe;
+
+ interrupt_pipe = token;
+
+ if ((interrupt_pipe == NULL) || (interrupt_pipe_enabled == 0)) return;
+
+ oldwrite = interrupt_pipe[1];
+ interrupt_pipe[1] = -1;
+
+ if (oldwrite >= 0) close(oldwrite);
+}
#ifdef __APPLE__
static struct iovec
* dynamic update packets.
*/
if ((((const HEADER *)buf1)->opcode == ns_o_update) &&
- (((const HEADER *)buf2)->opcode == ns_o_update))
+ (((const HEADER *)buf2)->opcode == ns_o_update))
return (1);
if (qdcount != ntohs(((const HEADER*)buf2)->qdcount)) return (0);
*/
for (try = 0; try < statp->retry; try++)
{
- for (ns = 0; ns < statp->nscount; ns++)
+ for (ns = 0; ns < statp->nscount; ns++)
{
struct sockaddr *nsap;
int nsaplen;
status = notify_get_state(notify_token, &exit_requested);
if (exit_requested == ThreadStateExitRequested)
{
+ Dprint(statp->options & RES_DEBUG, (stdout, ";; cancelled\n"));
res_nclose(statp);
notify_cancel(notify_token);
return DNS_RES_STATUS_CANCELLED;
status = notify_get_state(notify_token, &exit_requested);
if (exit_requested == ThreadStateExitRequested)
{
+ Dprint(statp->options & RES_DEBUG, (stdout, ";; cancelled\n"));
*terrno = EINTR;
return DNS_RES_STATUS_CANCELLED;
}
status = notify_get_state(notify_token, &exit_requested);
if (exit_requested == ThreadStateExitRequested)
{
+ Dprint(statp->options & RES_DEBUG, (stdout, ";; cancelled\n"));
*terrno = EINTR;
return DNS_RES_STATUS_CANCELLED;
}
}
-
+
cp = ans;
len = NS_INT16SZ;
while ((n = read(statp->_vcsock, (char *)cp, (int)len)) > 0)
const HEADER *hp = (const HEADER *) buf;
HEADER *anhp = (HEADER *) ans;
const struct sockaddr *nsap;
- int nsaplen;
+ int nsaplen, nfds;
struct timespec now, timeout, finish;
fd_set dsmask;
int iface, rif, status;
uint64_t exit_requested;
+ int *interrupt_pipe;
#ifndef __APPLE__
struct sockaddr_storage from;
ISC_SOCKLEN_T fromlen;
int multicast;
#endif
+ interrupt_pipe = NULL;
+
nsap = get_nsaddr(statp, ns);
nsaplen = get_salen(nsap);
if (EXT(statp).nssocks[ns] == -1)
timeout.tv_nsec *= 1000000;
now = evNowTime();
finish = evAddTime(now, timeout);
+
+ if (interrupt_pipe_enabled != 0) interrupt_pipe = pthread_getspecific(interrupt_pipe_key);
#else
seconds = (statp->retrans << ns);
if (ns > 0) seconds /= statp->nscount;
now = evNowTime();
nonow:
-
+
if (notify_token != -1)
{
exit_requested = 0;
status = notify_get_state(notify_token, &exit_requested);
- if (exit_requested == ThreadStateExitRequested) return DNS_RES_STATUS_CANCELLED;
+ if (exit_requested == ThreadStateExitRequested)
+ {
+ Dprint(statp->options & RES_DEBUG, (stdout, ";; cancelled\n"));
+ return DNS_RES_STATUS_CANCELLED;
+ }
}
FD_ZERO(&dsmask);
FD_SET(s, &dsmask);
+
+ nfds = s + 1;
+ if ((interrupt_pipe_enabled != 0) && (interrupt_pipe != NULL))
+ {
+ if (interrupt_pipe[0] >= 0)
+ {
+ FD_SET(interrupt_pipe[0], &dsmask);
+ nfds = MAX(s, interrupt_pipe[0]) + 1;
+ }
+ }
+
if (evCmpTime(finish, now) > 0) timeout = evSubTime(finish, now);
else timeout = evConsTime(0, 0);
- n = pselect(s + 1, &dsmask, NULL, NULL, &timeout, NULL);
+ n = pselect(nfds, &dsmask, NULL, NULL, &timeout, NULL);
if (n == 0)
{
Dprint(statp->options & RES_DEBUG, (stdout, ";; timeout\n"));
return DNS_RES_STATUS_SYSTEM_ERROR;
}
+ /* socket s and/or interrupt pipe got data */
+ if ((interrupt_pipe_enabled != 0) && (interrupt_pipe != NULL) && ((interrupt_pipe[0] < 0) || (FD_ISSET(interrupt_pipe[0], &dsmask))))
+ {
+ Dprint(statp->options & RES_DEBUG, (stdout, ";; cancelled\n"));
+ return DNS_RES_STATUS_CANCELLED;
+ }
+
errno = 0;
iface = 0;
resplen = internal_recvfrom(s, (char *)ans, *anssiz, from, fromlen, &iface);
struct sockaddr_in6 *a6, *b6;
if (a->sa_family != b->sa_family) return 0;
-
+
switch (a->sa_family)
{
case AF_INET: