1/*	$NetBSD: res_send.c,v 1.9 2006/01/24 17:41:25 christos Exp $	*/
2
3/*
4 * Copyright 2008  Android Open Source Project (source port randomization)
5 * Copyright (c) 1985, 1989, 1993
6 *    The Regents of the University of California.  All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 * 	This product includes software developed by the University of
19 * 	California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 *    may be used to endorse or promote products derived from this software
22 *    without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37/*
38 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
39 *
40 * Permission to use, copy, modify, and distribute this software for any
41 * purpose with or without fee is hereby granted, provided that the above
42 * copyright notice and this permission notice appear in all copies, and that
43 * the name of Digital Equipment Corporation not be used in advertising or
44 * publicity pertaining to distribution of the document or software without
45 * specific, written prior permission.
46 *
47 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
48 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
49 * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
50 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
51 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
52 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
53 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
54 * SOFTWARE.
55 */
56
57/*
58 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
59 * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
60 *
61 * Permission to use, copy, modify, and distribute this software for any
62 * purpose with or without fee is hereby granted, provided that the above
63 * copyright notice and this permission notice appear in all copies.
64 *
65 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
66 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
67 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
68 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
69 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
70 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
71 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
72 */
73
74#include <sys/cdefs.h>
75#if defined(LIBC_SCCS) && !defined(lint)
76#ifdef notdef
77static const char sccsid[] = "@(#)res_send.c	8.1 (Berkeley) 6/4/93";
78static const char rcsid[] = "Id: res_send.c,v 1.5.2.2.4.5 2004/08/10 02:19:56 marka Exp";
79#else
80__RCSID("$NetBSD: res_send.c,v 1.9 2006/01/24 17:41:25 christos Exp $");
81#endif
82#endif /* LIBC_SCCS and not lint */
83
84/* set to 1 to use our small/simple/limited DNS cache */
85#define  USE_RESOLV_CACHE  1
86
87/*
88 * Send query to name server and wait for reply.
89 */
90
91#include <sys/types.h>
92#include <sys/param.h>
93#include <sys/time.h>
94#include <sys/socket.h>
95#include <sys/uio.h>
96
97#include <netinet/in.h>
98#include "arpa_nameser.h"
99#include <arpa/inet.h>
100
101#include <errno.h>
102#include <fcntl.h>
103#include <netdb.h>
104#ifdef ANDROID_CHANGES
105#include "resolv_private.h"
106#else
107#include <resolv.h>
108#endif
109#include <signal.h>
110#include <stdio.h>
111#include <stdlib.h>
112#include <string.h>
113#include <time.h>
114#include <unistd.h>
115
116#include <isc/eventlib.h>
117
118#if USE_RESOLV_CACHE
119#  include <resolv_cache.h>
120#endif
121
122#include "libc_logging.h"
123
124#ifndef DE_CONST
125#define DE_CONST(c,v)   v = ((c) ? \
126    strchr((const void *)(c), *(const char *)(const void *)(c)) : NULL)
127#endif
128
129/* Options.  Leave them on. */
130#ifndef DEBUG
131#define DEBUG
132#endif
133#include "res_debug.h"
134#include "res_private.h"
135
136#define EXT(res) ((res)->_u._ext)
137#define DBG 0
138
139static const int highestFD = FD_SETSIZE - 1;
140
141/* Forward. */
142
143static int		get_salen __P((const struct sockaddr *));
144static struct sockaddr * get_nsaddr __P((res_state, size_t));
145static int		send_vc(res_state, const u_char *, int,
146				u_char *, int, int *, int);
147static int		send_dg(res_state, const u_char *, int,
148				u_char *, int, int *, int,
149				int *, int *);
150static void		Aerror(const res_state, FILE *, const char *, int,
151			       const struct sockaddr *, int);
152static void		Perror(const res_state, FILE *, const char *, int);
153static int		sock_eq(struct sockaddr *, struct sockaddr *);
154#ifdef NEED_PSELECT
155static int		pselect(int, void *, void *, void *,
156				struct timespec *,
157				const sigset_t *);
158#endif
159void res_pquery(const res_state, const u_char *, int, FILE *);
160static int connect_with_timeout(int sock, const struct sockaddr *nsap,
161			socklen_t salen, int sec);
162static int retrying_select(const int sock, fd_set *readset, fd_set *writeset,
163			const struct timespec *finish);
164
165/* BIONIC-BEGIN: implement source port randomization */
166typedef union {
167    struct sockaddr      sa;
168    struct sockaddr_in   sin;
169    struct sockaddr_in6  sin6;
170} _sockaddr_union;
171
172static int
173random_bind( int  s, int  family )
174{
175    _sockaddr_union  u;
176    int              j;
177    socklen_t        slen;
178
179    /* clear all, this also sets the IP4/6 address to 'any' */
180    memset( &u, 0, sizeof u );
181
182    switch (family) {
183        case AF_INET:
184            u.sin.sin_family = family;
185            slen             = sizeof u.sin;
186            break;
187        case AF_INET6:
188            u.sin6.sin6_family = family;
189            slen               = sizeof u.sin6;
190            break;
191        default:
192            errno = EPROTO;
193            return -1;
194    }
195
196    /* first try to bind to a random source port a few times */
197    for (j = 0; j < 10; j++) {
198        /* find a random port between 1025 .. 65534 */
199        int  port = 1025 + (res_randomid() % (65535-1025));
200        if (family == AF_INET)
201            u.sin.sin_port = htons(port);
202        else
203            u.sin6.sin6_port = htons(port);
204
205        if ( !bind( s, &u.sa, slen ) )
206            return 0;
207    }
208
209    /* nothing after 10 tries, our network table is probably busy */
210    /* let the system decide which port is best */
211    if (family == AF_INET)
212        u.sin.sin_port = 0;
213    else
214        u.sin6.sin6_port = 0;
215
216    return bind( s, &u.sa, slen );
217}
218/* BIONIC-END */
219
220static const int niflags = NI_NUMERICHOST | NI_NUMERICSERV;
221
222/* Public. */
223
224/* int
225 * res_isourserver(ina)
226 *	looks up "ina" in _res.ns_addr_list[]
227 * returns:
228 *	0  : not found
229 *	>0 : found
230 * author:
231 *	paul vixie, 29may94
232 */
233__LIBC_HIDDEN__ int
234res_ourserver_p(const res_state statp, const struct sockaddr *sa) {
235	const struct sockaddr_in *inp, *srv;
236	const struct sockaddr_in6 *in6p, *srv6;
237	int ns;
238
239	switch (sa->sa_family) {
240	case AF_INET:
241		inp = (const struct sockaddr_in *)(const void *)sa;
242		for (ns = 0;  ns < statp->nscount;  ns++) {
243			srv = (struct sockaddr_in *)(void *)get_nsaddr(statp, (size_t)ns);
244			if (srv->sin_family == inp->sin_family &&
245			    srv->sin_port == inp->sin_port &&
246			    (srv->sin_addr.s_addr == INADDR_ANY ||
247			     srv->sin_addr.s_addr == inp->sin_addr.s_addr))
248				return (1);
249		}
250		break;
251	case AF_INET6:
252		if (EXT(statp).ext == NULL)
253			break;
254		in6p = (const struct sockaddr_in6 *)(const void *)sa;
255		for (ns = 0;  ns < statp->nscount;  ns++) {
256			srv6 = (struct sockaddr_in6 *)(void *)get_nsaddr(statp, (size_t)ns);
257			if (srv6->sin6_family == in6p->sin6_family &&
258			    srv6->sin6_port == in6p->sin6_port &&
259#ifdef HAVE_SIN6_SCOPE_ID
260			    (srv6->sin6_scope_id == 0 ||
261			     srv6->sin6_scope_id == in6p->sin6_scope_id) &&
262#endif
263			    (IN6_IS_ADDR_UNSPECIFIED(&srv6->sin6_addr) ||
264			     IN6_ARE_ADDR_EQUAL(&srv6->sin6_addr, &in6p->sin6_addr)))
265				return (1);
266		}
267		break;
268	default:
269		break;
270	}
271	return (0);
272}
273
274/* int
275 * res_nameinquery(name, type, class, buf, eom)
276 *	look for (name,type,class) in the query section of packet (buf,eom)
277 * requires:
278 *	buf + HFIXEDSZ <= eom
279 * returns:
280 *	-1 : format error
281 *	0  : not found
282 *	>0 : found
283 * author:
284 *	paul vixie, 29may94
285 */
286int
287res_nameinquery(const char *name, int type, int class,
288		const u_char *buf, const u_char *eom)
289{
290	const u_char *cp = buf + HFIXEDSZ;
291	int qdcount = ntohs(((const HEADER*)(const void *)buf)->qdcount);
292
293	while (qdcount-- > 0) {
294		char tname[MAXDNAME+1];
295		int n, ttype, tclass;
296
297		n = dn_expand(buf, eom, cp, tname, sizeof tname);
298		if (n < 0)
299			return (-1);
300		cp += n;
301		if (cp + 2 * INT16SZ > eom)
302			return (-1);
303		ttype = ns_get16(cp); cp += INT16SZ;
304		tclass = ns_get16(cp); cp += INT16SZ;
305		if (ttype == type && tclass == class &&
306		    ns_samename(tname, name) == 1)
307			return (1);
308	}
309	return (0);
310}
311
312/* int
313 * res_queriesmatch(buf1, eom1, buf2, eom2)
314 *	is there a 1:1 mapping of (name,type,class)
315 *	in (buf1,eom1) and (buf2,eom2)?
316 * returns:
317 *	-1 : format error
318 *	0  : not a 1:1 mapping
319 *	>0 : is a 1:1 mapping
320 * author:
321 *	paul vixie, 29may94
322 */
323int
324res_queriesmatch(const u_char *buf1, const u_char *eom1,
325		 const u_char *buf2, const u_char *eom2)
326{
327	const u_char *cp = buf1 + HFIXEDSZ;
328	int qdcount = ntohs(((const HEADER*)(const void *)buf1)->qdcount);
329
330	if (buf1 + HFIXEDSZ > eom1 || buf2 + HFIXEDSZ > eom2)
331		return (-1);
332
333	/*
334	 * Only header section present in replies to
335	 * dynamic update packets.
336	 */
337	if ((((const HEADER *)(const void *)buf1)->opcode == ns_o_update) &&
338	    (((const HEADER *)(const void *)buf2)->opcode == ns_o_update))
339		return (1);
340
341	if (qdcount != ntohs(((const HEADER*)(const void *)buf2)->qdcount))
342		return (0);
343	while (qdcount-- > 0) {
344		char tname[MAXDNAME+1];
345		int n, ttype, tclass;
346
347		n = dn_expand(buf1, eom1, cp, tname, sizeof tname);
348		if (n < 0)
349			return (-1);
350		cp += n;
351		if (cp + 2 * INT16SZ > eom1)
352			return (-1);
353		ttype = ns_get16(cp);	cp += INT16SZ;
354		tclass = ns_get16(cp); cp += INT16SZ;
355		if (!res_nameinquery(tname, ttype, tclass, buf2, eom2))
356			return (0);
357	}
358	return (1);
359}
360
361
362int
363res_nsend(res_state statp,
364	  const u_char *buf, int buflen, u_char *ans, int anssiz)
365{
366	int gotsomewhere, terrno, try, v_circuit, resplen, ns, n;
367	char abuf[NI_MAXHOST];
368#if USE_RESOLV_CACHE
369        struct resolv_cache*  cache;
370        ResolvCacheStatus     cache_status = RESOLV_CACHE_UNSUPPORTED;
371#endif
372
373#if !USE_RESOLV_CACHE
374	if (statp->nscount == 0) {
375		errno = ESRCH;
376		return (-1);
377	}
378#endif
379
380	if (anssiz < HFIXEDSZ) {
381		errno = EINVAL;
382		return (-1);
383	}
384	DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_QUERY),
385		(stdout, ";; res_send()\n"), buf, buflen);
386	v_circuit = (statp->options & RES_USEVC) || buflen > PACKETSZ;
387	gotsomewhere = 0;
388	terrno = ETIMEDOUT;
389
390#if USE_RESOLV_CACHE
391	// get the cache associated with the interface
392	cache = __get_res_cache(statp->iface);
393	if (cache != NULL) {
394		int  anslen = 0;
395		cache_status = _resolv_cache_lookup(
396				cache, buf, buflen,
397				ans, anssiz, &anslen);
398
399		if (cache_status == RESOLV_CACHE_FOUND) {
400			return anslen;
401		} else {
402			// had a cache miss for a known interface, so populate the thread private
403			// data so the normal resolve path can do its thing
404			_resolv_populate_res_for_iface(statp);
405		}
406	}
407
408	if (statp->nscount == 0) {
409		errno = ESRCH;
410		return (-1);
411	}
412#endif
413
414	/*
415	 * If the ns_addr_list in the resolver context has changed, then
416	 * invalidate our cached copy and the associated timing data.
417	 */
418	if (EXT(statp).nscount != 0) {
419		int needclose = 0;
420		struct sockaddr_storage peer;
421		socklen_t peerlen;
422
423		if (EXT(statp).nscount != statp->nscount)
424			needclose++;
425		else
426			for (ns = 0; ns < statp->nscount; ns++) {
427				if (statp->nsaddr_list[ns].sin_family &&
428				    !sock_eq((struct sockaddr *)(void *)&statp->nsaddr_list[ns],
429					     (struct sockaddr *)(void *)&EXT(statp).ext->nsaddrs[ns])) {
430					needclose++;
431					break;
432				}
433
434				if (EXT(statp).nssocks[ns] == -1)
435					continue;
436				peerlen = sizeof(peer);
437				if (getpeername(EXT(statp).nssocks[ns],
438				    (struct sockaddr *)(void *)&peer, &peerlen) < 0) {
439					needclose++;
440					break;
441				}
442				if (!sock_eq((struct sockaddr *)(void *)&peer,
443				    get_nsaddr(statp, (size_t)ns))) {
444					needclose++;
445					break;
446				}
447			}
448		if (needclose) {
449			res_nclose(statp);
450			EXT(statp).nscount = 0;
451		}
452	}
453
454	/*
455	 * Maybe initialize our private copy of the ns_addr_list.
456	 */
457	if (EXT(statp).nscount == 0) {
458		for (ns = 0; ns < statp->nscount; ns++) {
459			EXT(statp).nstimes[ns] = RES_MAXTIME;
460			EXT(statp).nssocks[ns] = -1;
461			if (!statp->nsaddr_list[ns].sin_family)
462				continue;
463			EXT(statp).ext->nsaddrs[ns].sin =
464				 statp->nsaddr_list[ns];
465		}
466		EXT(statp).nscount = statp->nscount;
467	}
468
469	/*
470	 * Some resolvers want to even out the load on their nameservers.
471	 * Note that RES_BLAST overrides RES_ROTATE.
472	 */
473	if ((statp->options & RES_ROTATE) != 0U &&
474	    (statp->options & RES_BLAST) == 0U) {
475		union res_sockaddr_union inu;
476		struct sockaddr_in ina;
477		int lastns = statp->nscount - 1;
478		int fd;
479		u_int16_t nstime;
480
481		if (EXT(statp).ext != NULL)
482			inu = EXT(statp).ext->nsaddrs[0];
483		ina = statp->nsaddr_list[0];
484		fd = EXT(statp).nssocks[0];
485		nstime = EXT(statp).nstimes[0];
486		for (ns = 0; ns < lastns; ns++) {
487			if (EXT(statp).ext != NULL)
488                                EXT(statp).ext->nsaddrs[ns] =
489					EXT(statp).ext->nsaddrs[ns + 1];
490			statp->nsaddr_list[ns] = statp->nsaddr_list[ns + 1];
491			EXT(statp).nssocks[ns] = EXT(statp).nssocks[ns + 1];
492			EXT(statp).nstimes[ns] = EXT(statp).nstimes[ns + 1];
493		}
494		if (EXT(statp).ext != NULL)
495			EXT(statp).ext->nsaddrs[lastns] = inu;
496		statp->nsaddr_list[lastns] = ina;
497		EXT(statp).nssocks[lastns] = fd;
498		EXT(statp).nstimes[lastns] = nstime;
499	}
500
501	/*
502	 * Send request, RETRY times, or until successful.
503	 */
504	for (try = 0; try < statp->retry; try++) {
505	    for (ns = 0; ns < statp->nscount; ns++) {
506		struct sockaddr *nsap;
507		int nsaplen;
508		nsap = get_nsaddr(statp, (size_t)ns);
509		nsaplen = get_salen(nsap);
510		statp->_flags &= ~RES_F_LASTMASK;
511		statp->_flags |= (ns << RES_F_LASTSHIFT);
512 same_ns:
513		if (statp->qhook) {
514			int done = 0, loops = 0;
515
516			do {
517				res_sendhookact act;
518
519				act = (*statp->qhook)(&nsap, &buf, &buflen,
520						      ans, anssiz, &resplen);
521				switch (act) {
522				case res_goahead:
523					done = 1;
524					break;
525				case res_nextns:
526					res_nclose(statp);
527					goto next_ns;
528				case res_done:
529					return (resplen);
530				case res_modified:
531					/* give the hook another try */
532					if (++loops < 42) /*doug adams*/
533						break;
534					/*FALLTHROUGH*/
535				case res_error:
536					/*FALLTHROUGH*/
537				default:
538					goto fail;
539				}
540			} while (!done);
541		}
542
543		Dprint(((statp->options & RES_DEBUG) &&
544			getnameinfo(nsap, (socklen_t)nsaplen, abuf, sizeof(abuf),
545				NULL, 0, niflags) == 0),
546				(stdout, ";; Querying server (# %d) address = %s\n",
547				ns + 1, abuf));
548
549
550		if (v_circuit) {
551			/* Use VC; at most one attempt per server. */
552			try = statp->retry;
553
554			n = send_vc(statp, buf, buflen, ans, anssiz, &terrno,
555				    ns);
556
557			if (DBG) {
558				__libc_format_log(ANDROID_LOG_DEBUG, "libc",
559					"used send_vc %d\n", n);
560			}
561
562			if (n < 0)
563				goto fail;
564			if (n == 0)
565				goto next_ns;
566			resplen = n;
567		} else {
568			/* Use datagrams. */
569			if (DBG) {
570				__libc_format_log(ANDROID_LOG_DEBUG, "libc", "using send_dg\n");
571			}
572
573			n = send_dg(statp, buf, buflen, ans, anssiz, &terrno,
574				    ns, &v_circuit, &gotsomewhere);
575			if (DBG) {
576				__libc_format_log(ANDROID_LOG_DEBUG, "libc", "used send_dg %d\n",n);
577			}
578
579			if (n < 0)
580				goto fail;
581			if (n == 0)
582				goto next_ns;
583			if (DBG) {
584				__libc_format_log(ANDROID_LOG_DEBUG, "libc", "time=%ld\n",
585                                                  time(NULL));
586			}
587			if (v_circuit)
588				goto same_ns;
589			resplen = n;
590		}
591
592		Dprint((statp->options & RES_DEBUG) ||
593		       ((statp->pfcode & RES_PRF_REPLY) &&
594			(statp->pfcode & RES_PRF_HEAD1)),
595		       (stdout, ";; got answer:\n"));
596
597		DprintQ((statp->options & RES_DEBUG) ||
598			(statp->pfcode & RES_PRF_REPLY),
599			(stdout, "%s", ""),
600			ans, (resplen > anssiz) ? anssiz : resplen);
601
602#if USE_RESOLV_CACHE
603                if (cache_status == RESOLV_CACHE_NOTFOUND) {
604                    _resolv_cache_add(cache, buf, buflen,
605                                      ans, resplen);
606                }
607#endif
608		/*
609		 * If we have temporarily opened a virtual circuit,
610		 * or if we haven't been asked to keep a socket open,
611		 * close the socket.
612		 */
613		if ((v_circuit && (statp->options & RES_USEVC) == 0U) ||
614		    (statp->options & RES_STAYOPEN) == 0U) {
615			res_nclose(statp);
616		}
617		if (statp->rhook) {
618			int done = 0, loops = 0;
619
620			do {
621				res_sendhookact act;
622
623				act = (*statp->rhook)(nsap, buf, buflen,
624						      ans, anssiz, &resplen);
625				switch (act) {
626				case res_goahead:
627				case res_done:
628					done = 1;
629					break;
630				case res_nextns:
631					res_nclose(statp);
632					goto next_ns;
633				case res_modified:
634					/* give the hook another try */
635					if (++loops < 42) /*doug adams*/
636						break;
637					/*FALLTHROUGH*/
638				case res_error:
639					/*FALLTHROUGH*/
640				default:
641					goto fail;
642				}
643			} while (!done);
644
645		}
646		return (resplen);
647 next_ns: ;
648	   } /*foreach ns*/
649	} /*foreach retry*/
650	res_nclose(statp);
651	if (!v_circuit) {
652		if (!gotsomewhere)
653			errno = ECONNREFUSED;	/* no nameservers found */
654		else
655			errno = ETIMEDOUT;	/* no answer obtained */
656	} else
657		errno = terrno;
658
659#if USE_RESOLV_CACHE
660        _resolv_cache_query_failed(cache, buf, buflen);
661#endif
662
663	return (-1);
664 fail:
665#if USE_RESOLV_CACHE
666	_resolv_cache_query_failed(cache, buf, buflen);
667#endif
668	res_nclose(statp);
669	return (-1);
670}
671
672/* Private */
673
674static int
675get_salen(sa)
676	const struct sockaddr *sa;
677{
678
679#ifdef HAVE_SA_LEN
680	/* There are people do not set sa_len.  Be forgiving to them. */
681	if (sa->sa_len)
682		return (sa->sa_len);
683#endif
684
685	if (sa->sa_family == AF_INET)
686		return (sizeof(struct sockaddr_in));
687	else if (sa->sa_family == AF_INET6)
688		return (sizeof(struct sockaddr_in6));
689	else
690		return (0);	/* unknown, die on connect */
691}
692
693/*
694 * pick appropriate nsaddr_list for use.  see res_init() for initialization.
695 */
696static struct sockaddr *
697get_nsaddr(statp, n)
698	res_state statp;
699	size_t n;
700{
701
702	if (!statp->nsaddr_list[n].sin_family && EXT(statp).ext) {
703		/*
704		 * - EXT(statp).ext->nsaddrs[n] holds an address that is larger
705		 *   than struct sockaddr, and
706		 * - user code did not update statp->nsaddr_list[n].
707		 */
708		return (struct sockaddr *)(void *)&EXT(statp).ext->nsaddrs[n];
709	} else {
710		/*
711		 * - user code updated statp->nsaddr_list[n], or
712		 * - statp->nsaddr_list[n] has the same content as
713		 *   EXT(statp).ext->nsaddrs[n].
714		 */
715		return (struct sockaddr *)(void *)&statp->nsaddr_list[n];
716	}
717}
718
719static int get_timeout(const res_state statp, const int ns)
720{
721	int timeout = (statp->retrans << ns);
722	if (ns > 0) {
723		timeout /= statp->nscount;
724	}
725	if (timeout <= 0) {
726		timeout = 1;
727	}
728	if (DBG) {
729		__libc_format_log(ANDROID_LOG_DEBUG, "libc", "using timeout of %d sec\n", timeout);
730	}
731
732	return timeout;
733}
734
735static int
736send_vc(res_state statp,
737	const u_char *buf, int buflen, u_char *ans, int anssiz,
738	int *terrno, int ns)
739{
740	const HEADER *hp = (const HEADER *)(const void *)buf;
741	HEADER *anhp = (HEADER *)(void *)ans;
742	struct sockaddr *nsap;
743	int nsaplen;
744	int truncating, connreset, resplen, n;
745	struct iovec iov[2];
746	u_short len;
747	u_char *cp;
748	void *tmp;
749
750	if (DBG) {
751		__libc_format_log(ANDROID_LOG_DEBUG, "libc", "using send_vc\n");
752	}
753
754	nsap = get_nsaddr(statp, (size_t)ns);
755	nsaplen = get_salen(nsap);
756
757	connreset = 0;
758 same_ns:
759	truncating = 0;
760
761	/* Are we still talking to whom we want to talk to? */
762	if (statp->_vcsock >= 0 && (statp->_flags & RES_F_VC) != 0) {
763		struct sockaddr_storage peer;
764		socklen_t size = sizeof peer;
765		int old_mark;
766		int mark_size = sizeof(old_mark);
767		if (getpeername(statp->_vcsock,
768				(struct sockaddr *)(void *)&peer, &size) < 0 ||
769		    !sock_eq((struct sockaddr *)(void *)&peer, nsap) ||
770			getsockopt(statp->_vcsock, SOL_SOCKET, SO_MARK, &old_mark, &mark_size) < 0 ||
771			old_mark != statp->_mark) {
772			res_nclose(statp);
773			statp->_flags &= ~RES_F_VC;
774		}
775	}
776
777	if (statp->_vcsock < 0 || (statp->_flags & RES_F_VC) == 0) {
778		if (statp->_vcsock >= 0)
779			res_nclose(statp);
780
781		statp->_vcsock = socket(nsap->sa_family, SOCK_STREAM, 0);
782		if (statp->_vcsock > highestFD) {
783			res_nclose(statp);
784			errno = ENOTSOCK;
785		}
786		if (statp->_vcsock < 0) {
787			switch (errno) {
788			case EPROTONOSUPPORT:
789#ifdef EPFNOSUPPORT
790			case EPFNOSUPPORT:
791#endif
792			case EAFNOSUPPORT:
793				Perror(statp, stderr, "socket(vc)", errno);
794				return (0);
795			default:
796				*terrno = errno;
797				Perror(statp, stderr, "socket(vc)", errno);
798				return (-1);
799			}
800		}
801		if (statp->_mark != 0) {
802			if (setsockopt(statp->_vcsock, SOL_SOCKET,
803				        SO_MARK, &statp->_mark, sizeof(statp->_mark)) < 0) {
804				*terrno = errno;
805				Perror(statp, stderr, "setsockopt", errno);
806				return -1;
807			}
808		}
809		errno = 0;
810		if (random_bind(statp->_vcsock,nsap->sa_family) < 0) {
811			*terrno = errno;
812			Aerror(statp, stderr, "bind/vc", errno, nsap,
813			    nsaplen);
814			res_nclose(statp);
815			return (0);
816		}
817		if (connect_with_timeout(statp->_vcsock, nsap, (socklen_t)nsaplen,
818				get_timeout(statp, ns)) < 0) {
819			*terrno = errno;
820			Aerror(statp, stderr, "connect/vc", errno, nsap,
821			    nsaplen);
822			res_nclose(statp);
823			return (0);
824		}
825		statp->_flags |= RES_F_VC;
826	}
827
828	/*
829	 * Send length & message
830	 */
831	ns_put16((u_short)buflen, (u_char*)(void *)&len);
832	iov[0] = evConsIovec(&len, INT16SZ);
833	DE_CONST(buf, tmp);
834	iov[1] = evConsIovec(tmp, (size_t)buflen);
835	if (writev(statp->_vcsock, iov, 2) != (INT16SZ + buflen)) {
836		*terrno = errno;
837		Perror(statp, stderr, "write failed", errno);
838		res_nclose(statp);
839		return (0);
840	}
841	/*
842	 * Receive length & response
843	 */
844 read_len:
845	cp = ans;
846	len = INT16SZ;
847	while ((n = read(statp->_vcsock, (char *)cp, (size_t)len)) > 0) {
848		cp += n;
849		if ((len -= n) == 0)
850			break;
851	}
852	if (n <= 0) {
853		*terrno = errno;
854		Perror(statp, stderr, "read failed", errno);
855		res_nclose(statp);
856		/*
857		 * A long running process might get its TCP
858		 * connection reset if the remote server was
859		 * restarted.  Requery the server instead of
860		 * trying a new one.  When there is only one
861		 * server, this means that a query might work
862		 * instead of failing.  We only allow one reset
863		 * per query to prevent looping.
864		 */
865		if (*terrno == ECONNRESET && !connreset) {
866			connreset = 1;
867			res_nclose(statp);
868			goto same_ns;
869		}
870		res_nclose(statp);
871		return (0);
872	}
873	resplen = ns_get16(ans);
874	if (resplen > anssiz) {
875		Dprint(statp->options & RES_DEBUG,
876		       (stdout, ";; response truncated\n")
877		       );
878		truncating = 1;
879		len = anssiz;
880	} else
881		len = resplen;
882	if (len < HFIXEDSZ) {
883		/*
884		 * Undersized message.
885		 */
886		Dprint(statp->options & RES_DEBUG,
887		       (stdout, ";; undersized: %d\n", len));
888		*terrno = EMSGSIZE;
889		res_nclose(statp);
890		return (0);
891	}
892	cp = ans;
893	while (len != 0 && (n = read(statp->_vcsock, (char *)cp, (size_t)len)) > 0){
894		cp += n;
895		len -= n;
896	}
897	if (n <= 0) {
898		*terrno = errno;
899		Perror(statp, stderr, "read(vc)", errno);
900		res_nclose(statp);
901		return (0);
902	}
903	if (truncating) {
904		/*
905		 * Flush rest of answer so connection stays in synch.
906		 */
907		anhp->tc = 1;
908		len = resplen - anssiz;
909		while (len != 0) {
910			char junk[PACKETSZ];
911
912			n = read(statp->_vcsock, junk,
913				 (len > sizeof junk) ? sizeof junk : len);
914			if (n > 0)
915				len -= n;
916			else
917				break;
918		}
919	}
920	/*
921	 * If the calling applicating has bailed out of
922	 * a previous call and failed to arrange to have
923	 * the circuit closed or the server has got
924	 * itself confused, then drop the packet and
925	 * wait for the correct one.
926	 */
927	if (hp->id != anhp->id) {
928		DprintQ((statp->options & RES_DEBUG) ||
929			(statp->pfcode & RES_PRF_REPLY),
930			(stdout, ";; old answer (unexpected):\n"),
931			ans, (resplen > anssiz) ? anssiz: resplen);
932		goto read_len;
933	}
934
935	/*
936	 * All is well, or the error is fatal.  Signal that the
937	 * next nameserver ought not be tried.
938	 */
939	return (resplen);
940}
941
942/* return -1 on error (errno set), 0 on success */
943static int
944connect_with_timeout(int sock, const struct sockaddr *nsap, socklen_t salen, int sec)
945{
946	int res, origflags;
947	fd_set rset, wset;
948	struct timespec now, timeout, finish;
949
950	origflags = fcntl(sock, F_GETFL, 0);
951	fcntl(sock, F_SETFL, origflags | O_NONBLOCK);
952
953	res = connect(sock, nsap, salen);
954	if (res < 0 && errno != EINPROGRESS) {
955                res = -1;
956                goto done;
957	}
958	if (res != 0) {
959		now = evNowTime();
960		timeout = evConsTime((long)sec, 0L);
961		finish = evAddTime(now, timeout);
962		if (DBG) {
963			__libc_format_log(ANDROID_LOG_DEBUG, "libc", "  %d send_vc\n", sock);
964		}
965
966		res = retrying_select(sock, &rset, &wset, &finish);
967		if (res <= 0) {
968                        res = -1;
969		}
970	}
971done:
972	fcntl(sock, F_SETFL, origflags);
973	if (DBG) {
974		__libc_format_log(ANDROID_LOG_DEBUG, "libc",
975			"  %d connect_with_timeout returning %d\n", sock, res);
976	}
977	return res;
978}
979
980static int
981retrying_select(const int sock, fd_set *readset, fd_set *writeset, const struct timespec *finish)
982{
983	struct timespec now, timeout;
984	int n, error;
985	socklen_t len;
986
987
988retry:
989	if (DBG) {
990		__libc_format_log(ANDROID_LOG_DEBUG, "libc", "  %d retying_select\n", sock);
991	}
992
993	now = evNowTime();
994	if (readset) {
995		FD_ZERO(readset);
996		FD_SET(sock, readset);
997	}
998	if (writeset) {
999		FD_ZERO(writeset);
1000		FD_SET(sock, writeset);
1001	}
1002	if (evCmpTime(*finish, now) > 0)
1003		timeout = evSubTime(*finish, now);
1004	else
1005		timeout = evConsTime(0L, 0L);
1006
1007	n = pselect(sock + 1, readset, writeset, NULL, &timeout, NULL);
1008	if (n == 0) {
1009		if (DBG) {
1010			__libc_format_log(ANDROID_LOG_DEBUG, " libc",
1011				"  %d retrying_select timeout\n", sock);
1012		}
1013		errno = ETIMEDOUT;
1014		return 0;
1015	}
1016	if (n < 0) {
1017		if (errno == EINTR)
1018			goto retry;
1019		if (DBG) {
1020			__libc_format_log(ANDROID_LOG_DEBUG, "libc",
1021				"  %d retrying_select got error %d\n",sock, n);
1022		}
1023		return n;
1024	}
1025	if ((readset && FD_ISSET(sock, readset)) || (writeset && FD_ISSET(sock, writeset))) {
1026		len = sizeof(error);
1027		if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &error, &len) < 0 || error) {
1028			errno = error;
1029			if (DBG) {
1030				__libc_format_log(ANDROID_LOG_DEBUG, "libc",
1031					"  %d retrying_select dot error2 %d\n", sock, errno);
1032			}
1033
1034			return -1;
1035		}
1036	}
1037	if (DBG) {
1038		__libc_format_log(ANDROID_LOG_DEBUG, "libc",
1039			"  %d retrying_select returning %d\n",sock, n);
1040	}
1041
1042	return n;
1043}
1044
1045
1046static int
1047send_dg(res_state statp,
1048	const u_char *buf, int buflen, u_char *ans, int anssiz,
1049	int *terrno, int ns, int *v_circuit, int *gotsomewhere)
1050{
1051	const HEADER *hp = (const HEADER *)(const void *)buf;
1052	HEADER *anhp = (HEADER *)(void *)ans;
1053	const struct sockaddr *nsap;
1054	int nsaplen;
1055	struct timespec now, timeout, finish;
1056	fd_set dsmask;
1057	struct sockaddr_storage from;
1058	socklen_t fromlen;
1059	int resplen, seconds, n, s;
1060
1061	nsap = get_nsaddr(statp, (size_t)ns);
1062	nsaplen = get_salen(nsap);
1063	if (EXT(statp).nssocks[ns] == -1) {
1064		EXT(statp).nssocks[ns] = socket(nsap->sa_family, SOCK_DGRAM, 0);
1065		if (EXT(statp).nssocks[ns] > highestFD) {
1066			res_nclose(statp);
1067			errno = ENOTSOCK;
1068		}
1069		if (EXT(statp).nssocks[ns] < 0) {
1070			switch (errno) {
1071			case EPROTONOSUPPORT:
1072#ifdef EPFNOSUPPORT
1073			case EPFNOSUPPORT:
1074#endif
1075			case EAFNOSUPPORT:
1076				Perror(statp, stderr, "socket(dg)", errno);
1077				return (0);
1078			default:
1079				*terrno = errno;
1080				Perror(statp, stderr, "socket(dg)", errno);
1081				return (-1);
1082			}
1083		}
1084
1085		if (statp->_mark != 0) {
1086			if (setsockopt(EXT(statp).nssocks[ns], SOL_SOCKET,
1087					SO_MARK, &(statp->_mark), sizeof(statp->_mark)) < 0) {
1088				res_nclose(statp);
1089				return -1;
1090			}
1091		}
1092#ifndef CANNOT_CONNECT_DGRAM
1093		/*
1094		 * On a 4.3BSD+ machine (client and server,
1095		 * actually), sending to a nameserver datagram
1096		 * port with no nameserver will cause an
1097		 * ICMP port unreachable message to be returned.
1098		 * If our datagram socket is "connected" to the
1099		 * server, we get an ECONNREFUSED error on the next
1100		 * socket operation, and select returns if the
1101		 * error message is received.  We can thus detect
1102		 * the absence of a nameserver without timing out.
1103		 */
1104		if (random_bind(EXT(statp).nssocks[ns], nsap->sa_family) < 0) {
1105			Aerror(statp, stderr, "bind(dg)", errno, nsap,
1106			    nsaplen);
1107			res_nclose(statp);
1108			return (0);
1109		}
1110		if (connect(EXT(statp).nssocks[ns], nsap, (socklen_t)nsaplen) < 0) {
1111			Aerror(statp, stderr, "connect(dg)", errno, nsap,
1112			    nsaplen);
1113			res_nclose(statp);
1114			return (0);
1115		}
1116#endif /* !CANNOT_CONNECT_DGRAM */
1117		Dprint(statp->options & RES_DEBUG,
1118		       (stdout, ";; new DG socket\n"))
1119
1120	}
1121	s = EXT(statp).nssocks[ns];
1122#ifndef CANNOT_CONNECT_DGRAM
1123	if (send(s, (const char*)buf, (size_t)buflen, 0) != buflen) {
1124		Perror(statp, stderr, "send", errno);
1125		res_nclose(statp);
1126		return (0);
1127	}
1128#else /* !CANNOT_CONNECT_DGRAM */
1129	if (sendto(s, (const char*)buf, buflen, 0, nsap, nsaplen) != buflen)
1130	{
1131		Aerror(statp, stderr, "sendto", errno, nsap, nsaplen);
1132		res_nclose(statp);
1133		return (0);
1134	}
1135#endif /* !CANNOT_CONNECT_DGRAM */
1136
1137	/*
1138	 * Wait for reply.
1139	 */
1140	seconds = get_timeout(statp, ns);
1141	now = evNowTime();
1142	timeout = evConsTime((long)seconds, 0L);
1143	finish = evAddTime(now, timeout);
1144retry:
1145	n = retrying_select(s, &dsmask, NULL, &finish);
1146
1147	if (n == 0) {
1148		Dprint(statp->options & RES_DEBUG, (stdout, ";; timeout\n"));
1149		*gotsomewhere = 1;
1150		return (0);
1151	}
1152	if (n < 0) {
1153		Perror(statp, stderr, "select", errno);
1154		res_nclose(statp);
1155		return (0);
1156	}
1157	errno = 0;
1158	fromlen = sizeof(from);
1159	resplen = recvfrom(s, (char*)ans, (size_t)anssiz,0,
1160			   (struct sockaddr *)(void *)&from, &fromlen);
1161	if (resplen <= 0) {
1162		Perror(statp, stderr, "recvfrom", errno);
1163		res_nclose(statp);
1164		return (0);
1165	}
1166	*gotsomewhere = 1;
1167	if (resplen < HFIXEDSZ) {
1168		/*
1169		 * Undersized message.
1170		 */
1171		Dprint(statp->options & RES_DEBUG,
1172		       (stdout, ";; undersized: %d\n",
1173			resplen));
1174		*terrno = EMSGSIZE;
1175		res_nclose(statp);
1176		return (0);
1177	}
1178	if (hp->id != anhp->id) {
1179		/*
1180		 * response from old query, ignore it.
1181		 * XXX - potential security hazard could
1182		 *	 be detected here.
1183		 */
1184#ifdef ANDROID_CHANGES
1185		__libc_android_log_event_uid(BIONIC_EVENT_RESOLVER_OLD_RESPONSE);
1186#endif
1187		DprintQ((statp->options & RES_DEBUG) ||
1188			(statp->pfcode & RES_PRF_REPLY),
1189			(stdout, ";; old answer:\n"),
1190			ans, (resplen > anssiz) ? anssiz : resplen);
1191		goto retry;
1192	}
1193	if (!(statp->options & RES_INSECURE1) &&
1194	    !res_ourserver_p(statp, (struct sockaddr *)(void *)&from)) {
1195		/*
1196		 * response from wrong server? ignore it.
1197		 * XXX - potential security hazard could
1198		 *	 be detected here.
1199		 */
1200#ifdef ANDROID_CHANGES
1201		__libc_android_log_event_uid(BIONIC_EVENT_RESOLVER_WRONG_SERVER);
1202#endif
1203		DprintQ((statp->options & RES_DEBUG) ||
1204			(statp->pfcode & RES_PRF_REPLY),
1205			(stdout, ";; not our server:\n"),
1206			ans, (resplen > anssiz) ? anssiz : resplen);
1207		goto retry;
1208	}
1209#ifdef RES_USE_EDNS0
1210	if (anhp->rcode == FORMERR && (statp->options & RES_USE_EDNS0) != 0U) {
1211		/*
1212		 * Do not retry if the server do not understand EDNS0.
1213		 * The case has to be captured here, as FORMERR packet do not
1214		 * carry query section, hence res_queriesmatch() returns 0.
1215		 */
1216		DprintQ(statp->options & RES_DEBUG,
1217			(stdout, "server rejected query with EDNS0:\n"),
1218			ans, (resplen > anssiz) ? anssiz : resplen);
1219		/* record the error */
1220		statp->_flags |= RES_F_EDNS0ERR;
1221		res_nclose(statp);
1222		return (0);
1223	}
1224#endif
1225	if (!(statp->options & RES_INSECURE2) &&
1226	    !res_queriesmatch(buf, buf + buflen,
1227			      ans, ans + anssiz)) {
1228		/*
1229		 * response contains wrong query? ignore it.
1230		 * XXX - potential security hazard could
1231		 *	 be detected here.
1232		 */
1233#ifdef ANDROID_CHANGES
1234		__libc_android_log_event_uid(BIONIC_EVENT_RESOLVER_WRONG_QUERY);
1235#endif
1236		DprintQ((statp->options & RES_DEBUG) ||
1237			(statp->pfcode & RES_PRF_REPLY),
1238			(stdout, ";; wrong query name:\n"),
1239			ans, (resplen > anssiz) ? anssiz : resplen);
1240		goto retry;;
1241	}
1242	if (anhp->rcode == SERVFAIL ||
1243	    anhp->rcode == NOTIMP ||
1244	    anhp->rcode == REFUSED) {
1245		DprintQ(statp->options & RES_DEBUG,
1246			(stdout, "server rejected query:\n"),
1247			ans, (resplen > anssiz) ? anssiz : resplen);
1248		res_nclose(statp);
1249		/* don't retry if called from dig */
1250		if (!statp->pfcode)
1251			return (0);
1252	}
1253	if (!(statp->options & RES_IGNTC) && anhp->tc) {
1254		/*
1255		 * To get the rest of answer,
1256		 * use TCP with same server.
1257		 */
1258		Dprint(statp->options & RES_DEBUG,
1259		       (stdout, ";; truncated answer\n"));
1260		*v_circuit = 1;
1261		res_nclose(statp);
1262		return (1);
1263	}
1264	/*
1265	 * All is well, or the error is fatal.  Signal that the
1266	 * next nameserver ought not be tried.
1267	 */
1268	return (resplen);
1269}
1270
1271static void
1272Aerror(const res_state statp, FILE *file, const char *string, int error,
1273       const struct sockaddr *address, int alen)
1274{
1275	int save = errno;
1276	char hbuf[NI_MAXHOST];
1277	char sbuf[NI_MAXSERV];
1278
1279	alen = alen;
1280
1281	if ((statp->options & RES_DEBUG) != 0U) {
1282		if (getnameinfo(address, (socklen_t)alen, hbuf, sizeof(hbuf),
1283		    sbuf, sizeof(sbuf), niflags)) {
1284			strncpy(hbuf, "?", sizeof(hbuf) - 1);
1285			hbuf[sizeof(hbuf) - 1] = '\0';
1286			strncpy(sbuf, "?", sizeof(sbuf) - 1);
1287			sbuf[sizeof(sbuf) - 1] = '\0';
1288		}
1289		fprintf(file, "res_send: %s ([%s].%s): %s\n",
1290			string, hbuf, sbuf, strerror(error));
1291	}
1292	errno = save;
1293}
1294
1295static void
1296Perror(const res_state statp, FILE *file, const char *string, int error) {
1297	int save = errno;
1298
1299	if ((statp->options & RES_DEBUG) != 0U)
1300		fprintf(file, "res_send: %s: %s\n",
1301			string, strerror(error));
1302	errno = save;
1303}
1304
1305static int
1306sock_eq(struct sockaddr *a, struct sockaddr *b) {
1307	struct sockaddr_in *a4, *b4;
1308	struct sockaddr_in6 *a6, *b6;
1309
1310	if (a->sa_family != b->sa_family)
1311		return 0;
1312	switch (a->sa_family) {
1313	case AF_INET:
1314		a4 = (struct sockaddr_in *)(void *)a;
1315		b4 = (struct sockaddr_in *)(void *)b;
1316		return a4->sin_port == b4->sin_port &&
1317		    a4->sin_addr.s_addr == b4->sin_addr.s_addr;
1318	case AF_INET6:
1319		a6 = (struct sockaddr_in6 *)(void *)a;
1320		b6 = (struct sockaddr_in6 *)(void *)b;
1321		return a6->sin6_port == b6->sin6_port &&
1322#ifdef HAVE_SIN6_SCOPE_ID
1323		    a6->sin6_scope_id == b6->sin6_scope_id &&
1324#endif
1325		    IN6_ARE_ADDR_EQUAL(&a6->sin6_addr, &b6->sin6_addr);
1326	default:
1327		return 0;
1328	}
1329}
1330
1331#ifdef NEED_PSELECT
1332/* XXX needs to move to the porting library. */
1333static int
1334pselect(int nfds, void *rfds, void *wfds, void *efds,
1335	struct timespec *tsp, const sigset_t *sigmask)
1336{
1337	struct timeval tv, *tvp;
1338	sigset_t sigs;
1339	int n;
1340
1341	if (tsp) {
1342		tvp = &tv;
1343		tv = evTimeVal(*tsp);
1344	} else
1345		tvp = NULL;
1346	if (sigmask)
1347		sigprocmask(SIG_SETMASK, sigmask, &sigs);
1348	n = select(nfds, rfds, wfds, efds, tvp);
1349	if (sigmask)
1350		sigprocmask(SIG_SETMASK, &sigs, NULL);
1351	if (tsp)
1352		*tsp = evTimeSpec(tv);
1353	return (n);
1354}
1355#endif
1356