2 * Copyright (c) 1985, 1989, 1993
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
37 * Permission to use, copy, modify, and distribute this software for any
38 * purpose with or without fee is hereby granted, provided that the above
39 * copyright notice and this permission notice appear in all copies, and that
40 * the name of Digital Equipment Corporation not be used in advertising or
41 * publicity pertaining to distribution of the document or software without
42 * specific, written prior permission.
44 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
45 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
46 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
47 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
48 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
49 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
50 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
55 * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
57 * Permission to use, copy, modify, and distribute this software for any
58 * purpose with or without fee is hereby granted, provided that the above
59 * copyright notice and this permission notice appear in all copies.
61 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
62 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
63 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
64 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
65 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
66 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
67 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
71 #if defined(LIBC_SCCS) && !defined(lint)
72 static const char sccsid
[] = "@(#)res_send.c 8.1 (Berkeley) 6/4/93";
73 static const char rcsid
[] = "$Id: res_send.c,v 1.1 2006/03/01 19:01:38 majka Exp $";
74 #endif /* LIBC_SCCS and not lint */
77 * Send query to name server and wait for reply.
81 #include "port_before.h"
82 #include "fd_setsize.h"
86 * internal_recvfrom uses RFC 2292 API (IPV6_PKTINFO)
87 * __APPLE_USE_RFC_2292 selects the appropriate API in <netinet6/in6.h>
89 #define __APPLE_USE_RFC_2292
91 #include <sys/types.h>
92 #include <sys/param.h>
94 #include <sys/socket.h>
97 #include <netinet/in.h>
98 #include <arpa/nameser.h>
99 #include <arpa/inet.h>
113 #include <net/if_dl.h>
114 #include "res_private.h"
117 #include <isc/eventlib.h>
118 #include "port_after.h"
122 #define ISC_SOCKLEN_T unsigned int
125 /* Options. Leave them on. */
127 #define CANNOT_CONNECT_DGRAM
132 #include "res_debug.h"
133 #include "res_private.h"
134 #include <sys/fcntl.h>
136 #define EXT(res) ((res)->_u._ext)
138 static const int highestFD
= FD_SETSIZE
- 1;
140 #define MAX_HOOK_RETRIES 42
142 /* port randomization */
143 #define RANDOM_BIND_MAX_TRIES 16
144 #define RANDOM_BIND_FIRST IPPORT_HIFIRSTAUTO
145 #define RANDOM_BIND_LAST IPPORT_HILASTAUTO
149 static int get_salen
__P((const struct sockaddr
*));
150 static int send_vc(res_state
, const u_char
*, int, u_char
*, int *, int *, int, struct sockaddr
*, int *, int);
151 static int send_dg(res_state
, const u_char
*, int, u_char
*, int *, int *, int, int *, int *, struct sockaddr
*, int *, int);
152 static void Aerror(const res_state
, FILE *, const char *, int, const struct sockaddr
*, int);
153 static void Perror(const res_state
, FILE *, const char *, int);
154 static int sock_eq(struct sockaddr
*, struct sockaddr
*);
155 #ifdef USE_DNS_PSELECT
156 static int dns_pselect(int, void *, void *, void *, struct timespec
*, const sigset_t
*);
159 static const int niflags
= NI_NUMERICHOST
| NI_NUMERICSERV
;
161 /* interrupt mechanism is shared with res_query.c */
162 int interrupt_pipe_enabled
= 0;
163 pthread_key_t interrupt_pipe_key
;
166 bind_random(int sock
)
170 struct sockaddr_in local
;
175 for (i
= 0; (i
< RANDOM_BIND_MAX_TRIES
) && (status
< 0); i
++)
177 /* random port in the range RANDOM_BIND_FIRST to RANDOM_BIND_LAST */
178 src_port
= (res_randomid() % (RANDOM_BIND_LAST
- RANDOM_BIND_FIRST
)) + RANDOM_BIND_FIRST
;
179 memset(&local
, 0, sizeof(struct sockaddr_in
));
180 local
.sin_port
= htons(src_port
);
182 status
= bind(sock
, (struct sockaddr
*)&local
, sizeof(struct sockaddr_in
));
189 res_delete_interrupt_token(void *token
)
193 interrupt_pipe
= token
;
194 if (interrupt_pipe
== NULL
) return;
196 if (interrupt_pipe
[0] >= 0)
198 close(interrupt_pipe
[0]);
199 interrupt_pipe
[0] = -1;
202 if (interrupt_pipe
[1] >= 0)
204 close(interrupt_pipe
[1]);
205 interrupt_pipe
[1] = -1;
208 pthread_setspecific(interrupt_pipe_key
, NULL
);
209 free(interrupt_pipe
);
213 res_init_interrupt_token(void)
217 interrupt_pipe
= (int *)malloc(2 * sizeof(int));
218 if (interrupt_pipe
== NULL
) return NULL
;
220 if (pipe(interrupt_pipe
) < 0)
222 /* this shouldn't happen */
223 interrupt_pipe
[0] = -1;
224 interrupt_pipe
[1] = -1;
228 fcntl(interrupt_pipe
[0], F_SETFD
, FD_CLOEXEC
| O_NONBLOCK
);
229 fcntl(interrupt_pipe
[1], F_SETFD
, FD_CLOEXEC
| O_NONBLOCK
);
232 pthread_setspecific(interrupt_pipe_key
, interrupt_pipe
);
234 return interrupt_pipe
;
238 res_interrupt_requests_enable(void)
240 interrupt_pipe_enabled
= 1;
241 pthread_key_create(&interrupt_pipe_key
, NULL
);
245 res_interrupt_requests_disable(void)
247 interrupt_pipe_enabled
= 0;
248 pthread_key_delete(interrupt_pipe_key
);
252 res_interrupt_request(void *token
)
257 interrupt_pipe
= token
;
259 if ((interrupt_pipe
== NULL
) || (interrupt_pipe_enabled
== 0)) return;
261 oldwrite
= interrupt_pipe
[1];
262 interrupt_pipe
[1] = -1;
264 if (oldwrite
>= 0) close(oldwrite
);
269 evConsIovec(void *buf
, size_t cnt
)
273 memset(&ret
, 0xf5, sizeof ret
);
279 static struct timespec
280 evConsTime(time_t sec
, long nsec
)
289 static struct timespec
290 evTimeSpec(struct timeval tv
)
294 ts
.tv_sec
= tv
.tv_sec
;
295 ts
.tv_nsec
= tv
.tv_usec
* 1000;
299 static struct timespec
304 if (gettimeofday(&now
, NULL
) < 0) return (evConsTime(0, 0));
305 return (evTimeSpec(now
));
308 #ifdef USE_DNS_PSELECT
309 static struct timeval
310 evTimeVal(struct timespec ts
)
314 tv
.tv_sec
= ts
.tv_sec
;
315 tv
.tv_usec
= ts
.tv_nsec
/ 1000;
320 #define BILLION 1000000000
321 static struct timespec
322 evAddTime(struct timespec addend1
, struct timespec addend2
)
326 x
.tv_sec
= addend1
.tv_sec
+ addend2
.tv_sec
;
327 x
.tv_nsec
= addend1
.tv_nsec
+ addend2
.tv_nsec
;
328 if (x
.tv_nsec
>= BILLION
)
331 x
.tv_nsec
-= BILLION
;
337 static struct timespec
338 evSubTime(struct timespec minuend
, struct timespec subtrahend
)
342 x
.tv_sec
= minuend
.tv_sec
- subtrahend
.tv_sec
;
343 if (minuend
.tv_nsec
>= subtrahend
.tv_nsec
)
345 x
.tv_nsec
= minuend
.tv_nsec
- subtrahend
.tv_nsec
;
349 x
.tv_nsec
= BILLION
- subtrahend
.tv_nsec
+ minuend
.tv_nsec
;
357 evCmpTime(struct timespec a
, struct timespec b
)
359 long x
= a
.tv_sec
- b
.tv_sec
;
361 if (x
== 0L) x
= a
.tv_nsec
- b
.tv_nsec
;
362 return (x
< 0L ? (-1) : x
> 0L ? (1) : (0));
365 #endif /* __APPLE__ */
370 * res_isourserver(ina)
371 * looks up "ina" in _res.ns_addr_list[]
376 * paul vixie, 29may94
379 res_ourserver_p(const res_state statp
, const struct sockaddr
*sa
)
381 const struct sockaddr_in
*inp
, *srv
;
382 const struct sockaddr_in6
*in6p
, *srv6
;
385 switch (sa
->sa_family
)
388 inp
= (const struct sockaddr_in
*)sa
;
389 for (ns
= 0; ns
< statp
->nscount
; ns
++)
391 srv
= (struct sockaddr_in
*)get_nsaddr(statp
, ns
);
392 if (srv
->sin_family
== inp
->sin_family
&&
393 srv
->sin_port
== inp
->sin_port
&&
394 (srv
->sin_addr
.s_addr
== INADDR_ANY
||
395 srv
->sin_addr
.s_addr
== inp
->sin_addr
.s_addr
))
400 if (EXT(statp
).ext
== NULL
) break;
401 in6p
= (const struct sockaddr_in6
*)sa
;
402 for (ns
= 0; ns
< statp
->nscount
; ns
++)
404 srv6
= (struct sockaddr_in6
*)get_nsaddr(statp
, ns
);
405 if (srv6
->sin6_family
== in6p
->sin6_family
&&
406 srv6
->sin6_port
== in6p
->sin6_port
&&
407 (IN6_IS_ADDR_UNSPECIFIED(&srv6
->sin6_addr
) ||
408 IN6_ARE_ADDR_EQUAL(&srv6
->sin6_addr
, &in6p
->sin6_addr
)))
419 * res_nameinquery(name, type, class, buf, eom)
420 * look for (name,type,class) in the query section of packet (buf,eom)
422 * buf + NS_HFIXEDSZ <= eom
428 * paul vixie, 29may94
431 res_nameinquery(const char *name
, int type
, int class, const u_char
*buf
, const u_char
*eom
)
433 const u_char
*cp
= buf
+ NS_HFIXEDSZ
;
434 int qdcount
= ntohs(((const HEADER
*)buf
)->qdcount
);
436 while (qdcount
-- > 0)
438 char tname
[NS_MAXDNAME
+1];
439 int n
, ttype
, tclass
;
441 n
= dn_expand(buf
, eom
, cp
, tname
, sizeof tname
);
442 if (n
< 0) return (-1);
445 if (cp
+ 2 * NS_INT16SZ
> eom
) return (-1);
447 ttype
= ns_get16(cp
); cp
+= NS_INT16SZ
;
448 tclass
= ns_get16(cp
); cp
+= NS_INT16SZ
;
449 if (ttype
== type
&& tclass
== class && ns_samename(tname
, name
) == 1) return (1);
456 * res_queriesmatch(buf1, eom1, buf2, eom2)
457 * is there a 1:1 mapping of (name,type,class)
458 * in (buf1,eom1) and (buf2,eom2)?
461 * 0 : not a 1:1 mapping
462 * >0 : is a 1:1 mapping
464 * paul vixie, 29may94
467 res_queriesmatch(const u_char
*buf1
, const u_char
*eom1
, const u_char
*buf2
, const u_char
*eom2
)
469 const u_char
*cp
= buf1
+ NS_HFIXEDSZ
;
470 int qdcount
= ntohs(((const HEADER
*)buf1
)->qdcount
);
472 if (buf1
+ NS_HFIXEDSZ
> eom1
|| buf2
+ NS_HFIXEDSZ
> eom2
)
476 * Only header section present in replies to
477 * dynamic update packets.
479 if ((((const HEADER
*)buf1
)->opcode
== ns_o_update
) &&
480 (((const HEADER
*)buf2
)->opcode
== ns_o_update
))
483 if (qdcount
!= ntohs(((const HEADER
*)buf2
)->qdcount
)) return (0);
485 while (qdcount
-- > 0)
487 char tname
[NS_MAXDNAME
+1];
488 int n
, ttype
, tclass
;
490 n
= dn_expand(buf1
, eom1
, cp
, tname
, sizeof tname
);
491 if (n
< 0) return (-1);
494 if (cp
+ 2 * NS_INT16SZ
> eom1
) return (-1);
496 ttype
= ns_get16(cp
); cp
+= NS_INT16SZ
;
497 tclass
= ns_get16(cp
); cp
+= NS_INT16SZ
;
498 if (!res_nameinquery(tname
, ttype
, tclass
, buf2
, eom2
)) return (0);
505 dns_res_send(res_state statp
, const u_char
*buf
, int buflen
, u_char
*ans
, int *anssiz
, struct sockaddr
*from
, int *fromlen
)
507 int gotsomewhere
, terrno
, try, v_circuit
, resplen
, ns
;
508 char abuf
[NI_MAXHOST
];
510 int notify_token
, status
, send_status
, reply_buf_size
;
511 uint64_t exit_requested
;
513 if (statp
->nscount
== 0)
516 return DNS_RES_STATUS_INVALID_RES_STATE
;
519 reply_buf_size
= *anssiz
;
520 if (reply_buf_size
< NS_HFIXEDSZ
)
523 return DNS_RES_STATUS_INVALID_ARGUMENT
;
526 DprintQ((statp
->options
& RES_DEBUG
) || (statp
->pfcode
& RES_PRF_QUERY
), (stdout
, ";; res_send()\n"), buf
, buflen
);
528 v_circuit
= (statp
->options
& RES_USEVC
) || (buflen
> NS_PACKETSZ
);
534 * If the ns_addr_list in the resolver context has changed, then
535 * invalidate our cached copy and the associated timing data.
537 if (EXT(statp
).nscount
!= 0)
540 struct sockaddr_storage peer
;
541 ISC_SOCKLEN_T peerlen
;
543 if (EXT(statp
).nscount
!= statp
->nscount
)
549 for (ns
= 0; ns
< statp
->nscount
; ns
++)
551 if ((statp
->nsaddr_list
[ns
].sin_family
) && (EXT(statp
).ext
!= NULL
) && (!sock_eq((struct sockaddr
*)&statp
->nsaddr_list
[ns
], (struct sockaddr
*)&EXT(statp
).ext
->nsaddrs
[ns
])))
557 if (EXT(statp
).nssocks
[ns
] == -1) continue;
559 peerlen
= sizeof(peer
);
560 if (getsockname(EXT(statp
).nssocks
[ns
], (struct sockaddr
*)&peer
, &peerlen
) < 0)
566 if (!sock_eq((struct sockaddr
*)&peer
, get_nsaddr(statp
, ns
)))
577 EXT(statp
).nscount
= 0;
582 * Maybe initialize our private copy of the ns_addr_list.
584 if (EXT(statp
).nscount
== 0)
586 for (ns
= 0; ns
< statp
->nscount
; ns
++)
588 EXT(statp
).nstimes
[ns
] = RES_MAXTIME
;
589 EXT(statp
).nssocks
[ns
] = -1;
590 if (!statp
->nsaddr_list
[ns
].sin_family
) continue;
591 if (EXT(statp
).ext
!= NULL
) EXT(statp
).ext
->nsaddrs
[ns
].sin
= statp
->nsaddr_list
[ns
];
594 EXT(statp
).nscount
= statp
->nscount
;
598 * Some resolvers want to even out the load on their nameservers.
599 * Note that RES_BLAST overrides RES_ROTATE.
601 if (((statp
->options
& RES_ROTATE
) != 0) && ((statp
->options
& RES_BLAST
) == 0))
603 union res_sockaddr_union inu
;
604 struct sockaddr_in ina
;
605 int lastns
= statp
->nscount
- 1;
609 if (EXT(statp
).ext
!= NULL
) inu
= EXT(statp
).ext
->nsaddrs
[0];
610 ina
= statp
->nsaddr_list
[0];
611 fd
= EXT(statp
).nssocks
[0];
612 nstime
= EXT(statp
).nstimes
[0];
614 for (ns
= 0; ns
< lastns
; ns
++)
616 if (EXT(statp
).ext
!= NULL
)
618 EXT(statp
).ext
->nsaddrs
[ns
] =EXT(statp
).ext
->nsaddrs
[ns
+ 1];
621 statp
->nsaddr_list
[ns
] = statp
->nsaddr_list
[ns
+ 1];
622 EXT(statp
).nssocks
[ns
] = EXT(statp
).nssocks
[ns
+ 1];
623 EXT(statp
).nstimes
[ns
] = EXT(statp
).nstimes
[ns
+ 1];
626 if (EXT(statp
).ext
!= NULL
) EXT(statp
).ext
->nsaddrs
[lastns
] = inu
;
627 statp
->nsaddr_list
[lastns
] = ina
;
628 EXT(statp
).nssocks
[lastns
] = fd
;
629 EXT(statp
).nstimes
[lastns
] = nstime
;
633 * Get notification token
634 * we use a self-notification token to allow a caller
635 * to signal the thread doing this DNS query to quit.
640 asprintf(¬ify_name
, "self.thread.%lu", (unsigned long)pthread_self());
641 if (notify_name
!= NULL
)
643 status
= notify_register_plain(notify_name
, ¬ify_token
);
648 * Send request, RETRY times, or until successful.
650 for (try = 0; try < statp
->retry
; try++)
652 for (ns
= 0; ns
< statp
->nscount
; ns
++)
654 struct sockaddr
*nsap
;
656 nsap
= get_nsaddr(statp
, ns
);
657 nsaplen
= get_salen(nsap
);
663 int done
= 0, loops
= 0;
669 act
= (*statp
->qhook
)(&nsap
, &buf
, &buflen
, ans
, reply_buf_size
, &resplen
);
679 if (notify_token
!= -1) notify_cancel(notify_token
);
680 return DNS_RES_STATUS_CANCELLED
;
682 /* give the hook another try */
683 if (++loops
< MAX_HOOK_RETRIES
) break;
688 if (notify_token
!= -1) notify_cancel(notify_token
);
689 return DNS_RES_STATUS_CANCELLED
;
694 if (notify_token
!= -1)
697 status
= notify_get_state(notify_token
, &exit_requested
);
698 if (exit_requested
== ThreadStateExitRequested
)
700 Dprint(statp
->options
& RES_DEBUG
, (stdout
, ";; cancelled\n"));
702 notify_cancel(notify_token
);
703 return DNS_RES_STATUS_CANCELLED
;
707 Dprint(((statp
->options
& RES_DEBUG
) && getnameinfo(nsap
, nsaplen
, abuf
, sizeof(abuf
), NULL
, 0, niflags
) == 0), (stdout
, ";; Querying server (# %d) address = %s\n", ns
+ 1, abuf
));
709 send_status
= ns_r_noerror
;
713 /* Use VC; at most one attempt per server. */
716 *anssiz
= reply_buf_size
;
717 send_status
= send_vc(statp
, buf
, buflen
, ans
, anssiz
, &terrno
, ns
, from
, fromlen
, notify_token
);
722 send_status
= send_dg(statp
, buf
, buflen
, ans
, anssiz
, &terrno
, ns
, &v_circuit
, &gotsomewhere
, from
, fromlen
, notify_token
);
723 if (v_circuit
!= 0) goto send_same_ns
;
726 if ((send_status
== DNS_RES_STATUS_SYSTEM_ERROR
) || (send_status
== DNS_RES_STATUS_CANCELLED
))
729 if (notify_token
!= -1) notify_cancel(notify_token
);
733 if (send_status
!= ns_r_noerror
) goto send_next_ns
;
735 Dprint((statp
->options
& RES_DEBUG
) || ((statp
->pfcode
& RES_PRF_REPLY
) && (statp
->pfcode
& RES_PRF_HEAD1
)), (stdout
, ";; got answer:\n"));
736 DprintQ((statp
->options
& RES_DEBUG
) || (statp
->pfcode
& RES_PRF_REPLY
), (stdout
, "%s", ""), ans
, (*anssiz
> reply_buf_size
) ? reply_buf_size
: *anssiz
);
739 * If we have temporarily opened a virtual circuit,
740 * or if we haven't been asked to keep a socket open,
743 if (((v_circuit
!= 0) && (statp
->options
& RES_USEVC
) == 0) || (statp
->options
& RES_STAYOPEN
) == 0) res_nclose(statp
);
747 int done
= 0, loops
= 0;
753 act
= (*statp
->rhook
)(nsap
, buf
, buflen
, ans
, *anssiz
, &resplen
);
764 /* give the hook another try */
765 if (++loops
< MAX_HOOK_RETRIES
) break;
771 if (notify_token
!= -1) notify_cancel(notify_token
);
772 return DNS_RES_STATUS_CANCELLED
;
778 if (notify_token
!= -1) notify_cancel(notify_token
);
783 } /* foreach retry */
786 if (notify_token
!= -1) notify_cancel(notify_token
);
791 if (gotsomewhere
!= 0)
793 errno
= ECONNREFUSED
;
794 return DNS_RES_STATUS_CONNECTION_REFUSED
;
798 return DNS_RES_STATUS_TIMEOUT
;
807 res_nsend_2(res_state statp
, const u_char
*buf
, int buflen
, u_char
*ans
, int anssiz
, struct sockaddr
*from
, int *fromlen
)
812 status
= dns_res_send(statp
, buf
, buflen
, ans
, &len
, from
, fromlen
);
813 if (status
!= ns_r_noerror
) len
= -1;
818 res_nsend(res_state statp
, const u_char
*buf
, int buflen
, u_char
*ans
, int anssiz
)
820 struct sockaddr_storage from
;
823 fromlen
= sizeof(struct sockaddr_storage
);
825 return res_nsend_2(statp
, buf
, buflen
, ans
, anssiz
, (struct sockaddr
*)&from
, &fromlen
);
831 get_salen(const struct sockaddr
*sa
)
834 /* There are people do not set sa_len. Be forgiving to them. */
835 if (sa
->sa_len
) return (sa
->sa_len
);
838 if (sa
->sa_family
== AF_INET
) return (sizeof(struct sockaddr_in
));
839 else if (sa
->sa_family
== AF_INET6
) return (sizeof(struct sockaddr_in6
));
840 else return (0); /* unknown, die on connect */
844 * pick appropriate nsaddr_list for use. see res_init() for initialization.
847 get_nsaddr(res_state statp
, size_t n
)
849 if ((!statp
->nsaddr_list
[n
].sin_family
) && (EXT(statp
).ext
!= NULL
))
852 * - EXT(statp).ext->nsaddrs[n] holds an address that is larger
853 * than struct sockaddr, and
854 * - user code did not update statp->nsaddr_list[n].
856 return (struct sockaddr
*)(void *)&EXT(statp
).ext
->nsaddrs
[n
];
861 * - user code updated statp->nsaddr_list[n], or
862 * - statp->nsaddr_list[n] has the same content as
863 * EXT(statp).ext->nsaddrs[n].
865 return (struct sockaddr
*)(void *)&statp
->nsaddr_list
[n
];
870 send_vc(res_state statp
, const u_char
*buf
, int buflen
, u_char
*ans
, int *anssiz
, int *terrno
, int ns
, struct sockaddr
*from
, int *fromlen
, int notify_token
)
872 const HEADER
*hp
= (const HEADER
*) buf
;
873 HEADER
*anhp
= (HEADER
*) ans
;
874 struct sockaddr
*nsap
;
876 int truncating
, connreset
, resplen
, n
;
882 uint64_t exit_requested
;
884 nsap
= get_nsaddr(statp
, ns
);
885 nsaplen
= get_salen(nsap
);
891 if (notify_token
!= -1)
894 status
= notify_get_state(notify_token
, &exit_requested
);
895 if (exit_requested
== ThreadStateExitRequested
)
897 Dprint(statp
->options
& RES_DEBUG
, (stdout
, ";; cancelled\n"));
899 return DNS_RES_STATUS_CANCELLED
;
905 /* Are we still talking to whom we want to talk? */
906 if (statp
->_vcsock
>= 0 && (statp
->_flags
& RES_F_VC
) != 0)
908 struct sockaddr_storage peer
;
909 ISC_SOCKLEN_T size
= sizeof peer
;
911 if (getpeername(statp
->_vcsock
, (struct sockaddr
*)&peer
, &size
) < 0 || !sock_eq((struct sockaddr
*)&peer
, nsap
))
914 statp
->_flags
&= ~RES_F_VC
;
918 if ((statp
->_vcsock
< 0) || ((statp
->_flags
& RES_F_VC
) == 0))
920 if (statp
->_vcsock
>= 0) res_nclose(statp
);
922 statp
->_vcsock
= socket(nsap
->sa_family
, SOCK_STREAM
, 0);
923 if (statp
->_vcsock
> highestFD
)
929 if (statp
->_vcsock
< 0)
932 Perror(statp
, stderr
, "socket(vc)", errno
);
933 return DNS_RES_STATUS_SYSTEM_ERROR
;
937 if (connect(statp
->_vcsock
, nsap
, nsaplen
) < 0)
940 Aerror(statp
, stderr
, "connect(vc)", errno
, nsap
, nsaplen
);
942 return DNS_RES_STATUS_CONNECTION_REFUSED
;
945 statp
->_flags
|= RES_F_VC
;
949 * Send length & message
951 putshort((u_short
)buflen
, (u_char
*)&len
);
952 iov
[0] = evConsIovec(&len
, NS_INT16SZ
);
958 iov
[1] = evConsIovec(tmp
, buflen
);
959 if (writev(statp
->_vcsock
, iov
, 2) != (NS_INT16SZ
+ buflen
))
962 Perror(statp
, stderr
, "write failed", errno
);
964 return DNS_RES_STATUS_CONNECTION_FAILED
;
968 * Receive length & response
972 if (notify_token
!= -1)
975 status
= notify_get_state(notify_token
, &exit_requested
);
976 if (exit_requested
== ThreadStateExitRequested
)
978 Dprint(statp
->options
& RES_DEBUG
, (stdout
, ";; cancelled\n"));
980 return DNS_RES_STATUS_CANCELLED
;
986 while ((n
= read(statp
->_vcsock
, (char *)cp
, (int)len
)) > 0)
989 if ((len
-= n
) <= 0) break;
995 Perror(statp
, stderr
, "read failed", errno
);
999 * A long running process might get its TCP
1000 * connection reset if the remote server was
1001 * restarted. Requery the server instead of
1002 * trying a new one. When there is only one
1003 * server, this means that a query might work
1004 * instead of failing. We only allow one reset
1005 * per query to prevent looping.
1007 if (*terrno
== ECONNRESET
&& !connreset
)
1015 return DNS_RES_STATUS_CONNECTION_FAILED
;
1018 resplen
= ns_get16(ans
);
1019 if (resplen
> *anssiz
)
1021 Dprint(statp
->options
& RES_DEBUG
, (stdout
, ";; response truncated\n"));
1030 if (len
< NS_HFIXEDSZ
)
1033 * Undersized message.
1035 Dprint(statp
->options
& RES_DEBUG
, (stdout
, ";; undersized: %d\n", len
));
1039 return DNS_RES_STATUS_INVALID_REPLY
;
1043 while (len
!= 0 && (n
= read(statp
->_vcsock
, (char *)cp
, (int)len
)) > 0)
1052 Perror(statp
, stderr
, "read(vc)", errno
);
1054 return DNS_RES_STATUS_CONNECTION_FAILED
;
1060 * Flush rest of answer so connection stays in synch.
1063 len
= resplen
- *anssiz
;
1066 char junk
[NS_PACKETSZ
];
1068 n
= read(statp
->_vcsock
, junk
, (len
> sizeof junk
) ? sizeof junk
: len
);
1069 if (n
> 0) len
-= n
;
1075 * If the calling applicating has bailed out of
1076 * a previous call and failed to arrange to have
1077 * the circuit closed or the server has got
1078 * itself confused, then drop the packet and
1079 * wait for the correct one.
1081 if (hp
->id
!= anhp
->id
)
1083 DprintQ((statp
->options
& RES_DEBUG
) || (statp
->pfcode
& RES_PRF_REPLY
), (stdout
, ";; old answer (unexpected):\n"), ans
, (resplen
> *anssiz
) ? *anssiz
: resplen
);
1088 * All is well, or the error is fatal. Signal that the
1089 * next nameserver ought not be tried.
1092 *fromlen
= sizeof(nsap
);
1093 memcpy(from
, &nsap
, *fromlen
);
1095 return ns_r_noerror
;
1099 internal_recvfrom(int s
, void *buf
, size_t len
, struct sockaddr
*from
, int *fromlen
, int *iface
)
1101 struct sockaddr_dl
*sdl
;
1102 struct iovec databuffers
= { buf
, len
};
1105 struct cmsghdr
*cmp
;
1106 char ancillary
[1024], ifname
[IF_NAMESIZE
];
1107 struct in6_pktinfo
*ip6_info
;
1108 struct sockaddr_in
*s4
;
1109 struct sockaddr_in6
*s6
;
1111 memset(&msg
, 0, sizeof(struct msghdr
));
1112 msg
.msg_name
= (caddr_t
)from
;
1113 msg
.msg_namelen
= *fromlen
;
1114 msg
.msg_iov
= &databuffers
;
1116 msg
.msg_control
= (caddr_t
)&ancillary
;
1117 msg
.msg_controllen
= sizeof(ancillary
);
1119 /* Receive the data */
1120 n
= recvmsg(s
, &msg
, 0);
1121 if ((n
< 0) || (msg
.msg_controllen
< sizeof(struct cmsghdr
)) || (msg
.msg_flags
& MSG_CTRUNC
))
1126 *fromlen
= msg
.msg_namelen
;
1128 s4
= (struct sockaddr_in
*)from
;
1129 s6
= (struct sockaddr_in6
*)from
;
1131 for (cmp
= CMSG_FIRSTHDR(&msg
); cmp
; cmp
= CMSG_NXTHDR(&msg
, cmp
))
1133 if ((cmp
->cmsg_level
== IPPROTO_IP
) && (cmp
->cmsg_type
== IP_RECVIF
))
1135 sdl
= (struct sockaddr_dl
*)CMSG_DATA(cmp
);
1136 if (sdl
->sdl_nlen
< IF_NAMESIZE
)
1138 memcpy(ifname
, sdl
->sdl_data
, sdl
->sdl_nlen
);
1139 ifname
[sdl
->sdl_nlen
] = 0;
1140 *iface
= if_nametoindex(ifname
);
1143 else if ((cmp
->cmsg_level
== IPPROTO_IPV6
) && (cmp
->cmsg_type
== IPV6_PKTINFO
))
1145 ip6_info
= (struct in6_pktinfo
*)CMSG_DATA(cmp
);
1146 *iface
= ip6_info
->ipi6_ifindex
;
1154 send_dg(res_state statp
, const u_char
*buf
, int buflen
, u_char
*ans
, int *anssiz
, int *terrno
, int ns
, int *v_circuit
, int *gotsomewhere
, struct sockaddr
*from
, int *fromlen
, int notify_token
)
1156 const HEADER
*hp
= (const HEADER
*) buf
;
1157 HEADER
*anhp
= (HEADER
*) ans
;
1158 const struct sockaddr
*nsap
;
1160 struct timespec now
, timeout
, finish
;
1162 int iface
, rif
, status
;
1163 uint64_t exit_requested
;
1164 int *interrupt_pipe
;
1166 struct sockaddr_storage from
;
1167 ISC_SOCKLEN_T fromlen
;
1169 int resplen
, seconds
, ntry
, n
, s
;
1174 interrupt_pipe
= NULL
;
1176 nsap
= get_nsaddr(statp
, ns
);
1177 nsaplen
= get_salen(nsap
);
1178 if (EXT(statp
).nssocks
[ns
] == -1)
1180 EXT(statp
).nssocks
[ns
] = socket(nsap
->sa_family
, SOCK_DGRAM
, 0);
1181 if (EXT(statp
).nssocks
[ns
] > highestFD
)
1187 if (EXT(statp
).nssocks
[ns
] < 0)
1190 Perror(statp
, stderr
, "socket(dg)", errno
);
1191 return DNS_RES_STATUS_SYSTEM_ERROR
;
1194 bind_random(EXT(statp
).nssocks
[ns
]);
1196 #ifndef CANNOT_CONNECT_DGRAM
1198 * On a 4.3BSD+ machine (client and server,
1199 * actually), sending to a nameserver datagram
1200 * port with no nameserver will cause an
1201 * ICMP port unreachable message to be returned.
1202 * If our datagram socket is "connected" to the
1203 * server, we get an ECONNREFUSED error on the next
1204 * socket operation, and select returns if the
1205 * error message is received. We can thus detect
1206 * the absence of a nameserver without timing out.
1208 if (connect(EXT(statp
).nssocks
[ns
], nsap
, nsaplen
) < 0)
1210 Aerror(statp
, stderr
, "connect(dg)", errno
, nsap
, nsaplen
);
1212 return DNS_RES_STATUS_CONNECTION_REFUSED
;
1215 #endif /* !CANNOT_CONNECT_DGRAM */
1216 Dprint(statp
->options
& RES_DEBUG
, (stdout
, ";; new DG socket\n"))
1219 s
= EXT(statp
).nssocks
[ns
];
1221 setsockopt(s
, IPPROTO_IP
, IP_RECVIF
, &rif
, sizeof(int));
1222 setsockopt(s
, IPPROTO_IPV6
, IPV6_PKTINFO
, &rif
, sizeof(int));
1227 if ((nsap
->sa_family
== AF_INET
) && (IN_MULTICAST(ntohl(((struct sockaddr_in
*)nsap
)->sin_addr
.s_addr
)))) multicast
= AF_INET
;
1228 else if ((nsap
->sa_family
== AF_INET6
) && (IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6
*)nsap
)->sin6_addr
))) multicast
= AF_INET6
;
1232 struct ifaddrs
*ifa
, *p
;
1233 struct sockaddr_in
*sin4
;
1234 struct sockaddr_in6
*sin6
;
1237 if (getifaddrs(&ifa
) < 0)
1239 Aerror(statp
, stderr
, "getifaddrs", errno
, nsap
, nsaplen
);
1241 return DNS_RES_STATUS_SYSTEM_ERROR
;
1244 for (p
= ifa
; p
!= NULL
; p
= p
->ifa_next
)
1246 if (p
->ifa_addr
== NULL
) continue;
1247 if ((p
->ifa_flags
& IFF_UP
) == 0) continue;
1248 if (p
->ifa_addr
->sa_family
!= multicast
) continue;
1249 if ((p
->ifa_flags
& IFF_MULTICAST
) == 0) continue;
1250 if ((p
->ifa_flags
& IFF_POINTOPOINT
) != 0)
1252 if ((multicast
== AF_INET
) && (ntohl(((struct sockaddr_in
*)nsap
)->sin_addr
.s_addr
) <= INADDR_MAX_LOCAL_GROUP
)) continue;
1255 sin4
= (struct sockaddr_in
*)p
->ifa_addr
;
1256 sin6
= (struct sockaddr_in6
*)p
->ifa_addr
;
1258 if (multicast
== AF_INET
) i
= setsockopt(s
, IPPROTO_IP
, IP_MULTICAST_IF
, &sin4
->sin_addr
, sizeof(sin4
->sin_addr
));
1259 else if (multicast
== AF_INET6
)
1261 ifnum
= if_nametoindex(p
->ifa_name
);
1262 ((struct sockaddr_in6
*)nsap
)->sin6_scope_id
= ifnum
;
1263 i
= setsockopt(s
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
, &ifnum
, sizeof(ifnum
));
1268 Aerror(statp
, stderr
, "setsockopt", errno
, nsap
, nsaplen
);
1269 if (multicast
== AF_INET6
) ((struct sockaddr_in6
*)nsap
)->sin6_scope_id
= 0;
1274 if (sendto(s
, (const char*)buf
, buflen
, 0, nsap
, nsaplen
) != buflen
)
1276 Aerror(statp
, stderr
, "sendto", errno
, nsap
, nsaplen
);
1277 if (multicast
== AF_INET6
) ((struct sockaddr_in6
*)nsap
)->sin6_scope_id
= 0;
1281 if (multicast
== AF_INET6
) ((struct sockaddr_in6
*)nsap
)->sin6_scope_id
= 0;
1289 #endif /* MULTICAST */
1291 #ifndef CANNOT_CONNECT_DGRAM
1292 if (send(s
, (const char*)buf
, buflen
, 0) != buflen
)
1294 Perror(statp
, stderr
, "send", errno
);
1296 return DNS_RES_STATUS_CONNECTION_FAILED
;
1299 #else /* !CANNOT_CONNECT_DGRAM */
1300 if (sendto(s
, (const char*)buf
, buflen
, 0, nsap
, nsaplen
) != buflen
)
1302 Aerror(statp
, stderr
, "sendto", errno
, nsap
, nsaplen
);
1304 return DNS_RES_STATUS_CONNECTION_FAILED
;
1306 #endif /* !CANNOT_CONNECT_DGRAM */
1310 #endif /* MULTICAST */
1316 ntry
= statp
->nscount
* statp
->retry
;
1317 seconds
= statp
->retrans
/ ntry
;
1318 if (seconds
<= 0) seconds
= 1;
1319 timeout
.tv_sec
= seconds
;
1320 timeout
.tv_nsec
= ((statp
->retrans
- (seconds
* ntry
)) * 1000) / ntry
;
1321 timeout
.tv_nsec
*= 1000000;
1323 finish
= evAddTime(now
, timeout
);
1325 if (interrupt_pipe_enabled
!= 0) interrupt_pipe
= pthread_getspecific(interrupt_pipe_key
);
1327 seconds
= (statp
->retrans
<< ns
);
1328 if (ns
> 0) seconds
/= statp
->nscount
;
1329 if (seconds
<= 0) seconds
= 1;
1331 timeout
= evConsTime(seconds
, 0);
1332 finish
= evAddTime(now
, timeout
);
1333 #endif /* __APPLE__ */
1341 if (notify_token
!= -1)
1344 status
= notify_get_state(notify_token
, &exit_requested
);
1345 if (exit_requested
== ThreadStateExitRequested
)
1347 Dprint(statp
->options
& RES_DEBUG
, (stdout
, ";; cancelled\n"));
1348 return DNS_RES_STATUS_CANCELLED
;
1356 if ((interrupt_pipe_enabled
!= 0) && (interrupt_pipe
!= NULL
))
1358 if (interrupt_pipe
[0] >= 0)
1360 FD_SET(interrupt_pipe
[0], &dsmask
);
1361 nfds
= MAX(s
, interrupt_pipe
[0]) + 1;
1365 if (evCmpTime(finish
, now
) > 0) timeout
= evSubTime(finish
, now
);
1366 else timeout
= evConsTime(0, 0);
1368 #ifdef USE_DNS_PSELECT
1369 n
= dns_pselect(nfds
, &dsmask
, NULL
, NULL
, &timeout
, NULL
);
1371 n
= pselect(nfds
, &dsmask
, NULL
, NULL
, &timeout
, NULL
);
1375 Dprint(statp
->options
& RES_DEBUG
, (stdout
, ";; timeout\n"));
1377 return DNS_RES_STATUS_TIMEOUT
;
1382 if (errno
== EINTR
) goto wait
;
1383 Perror(statp
, stderr
, "select", errno
);
1385 return DNS_RES_STATUS_SYSTEM_ERROR
;
1388 /* socket s and/or interrupt pipe got data */
1389 if ((interrupt_pipe_enabled
!= 0) && (interrupt_pipe
!= NULL
) && ((interrupt_pipe
[0] < 0) || (FD_ISSET(interrupt_pipe
[0], &dsmask
))))
1391 Dprint(statp
->options
& RES_DEBUG
, (stdout
, ";; cancelled\n"));
1392 return DNS_RES_STATUS_CANCELLED
;
1397 resplen
= internal_recvfrom(s
, (char *)ans
, *anssiz
, from
, fromlen
, &iface
);
1400 Perror(statp
, stderr
, "recvfrom", errno
);
1402 return DNS_RES_STATUS_CONNECTION_FAILED
;
1405 if (nsap
->sa_family
== AF_INET
) memcpy(((struct sockaddr_in
*)from
)->sin_zero
, &iface
, 4);
1406 else if (nsap
->sa_family
== AF_INET6
) ((struct sockaddr_in6
*)from
)->sin6_scope_id
= iface
;
1409 if (resplen
< NS_HFIXEDSZ
)
1412 * Undersized message.
1414 Dprint(statp
->options
& RES_DEBUG
, (stdout
, ";; undersized: %d\n", resplen
));
1417 return DNS_RES_STATUS_INVALID_REPLY
;
1420 if (hp
->id
!= anhp
->id
)
1423 * response from old query, ignore it.
1424 * XXX - potential security hazard could
1427 DprintQ((statp
->options
& RES_DEBUG
) || (statp
->pfcode
& RES_PRF_REPLY
), (stdout
, ";; old answer:\n"), ans
, (resplen
> *anssiz
) ? *anssiz
: resplen
);
1434 #endif /* MULTICAST */
1436 if (!(statp
->options
& RES_INSECURE1
) && !res_ourserver_p(statp
, from
))
1439 * response from wrong server? ignore it.
1440 * XXX - potential security hazard could
1443 DprintQ((statp
->options
& RES_DEBUG
) || (statp
->pfcode
& RES_PRF_REPLY
), (stdout
, ";; not our server:\n"), ans
, (resplen
> *anssiz
) ? *anssiz
: resplen
);
1449 #endif /* MULTICAST */
1451 #ifdef RES_USE_EDNS0
1452 if (anhp
->rcode
== ns_r_formerr
&& (statp
->options
& RES_USE_EDNS0
) != 0)
1455 * Do not retry if the server do not understand EDNS0.
1456 * The case has to be captured here, as FORMERR packet do not
1457 * carry query section, hence res_queriesmatch() returns 0.
1459 DprintQ(statp
->options
& RES_DEBUG
, (stdout
, "server rejected query with EDNS0:\n"), ans
, (resplen
> *anssiz
) ? *anssiz
: resplen
);
1460 /* record the error */
1461 statp
->_flags
|= RES_F_EDNS0ERR
;
1463 return DNS_RES_STATUS_CONNECTION_REFUSED
;
1467 if (!(statp
->options
& RES_INSECURE2
) && !res_queriesmatch(buf
, buf
+ buflen
, ans
, ans
+ *anssiz
))
1470 * response contains wrong query? ignore it.
1471 * XXX - potential security hazard could
1474 DprintQ((statp
->options
& RES_DEBUG
) || (statp
->pfcode
& RES_PRF_REPLY
), (stdout
, ";; wrong query name:\n"), ans
, (resplen
> *anssiz
) ? *anssiz
: resplen
);
1476 return DNS_RES_STATUS_INVALID_REPLY
;
1479 if (anhp
->rcode
== ns_r_servfail
|| anhp
->rcode
== ns_r_notimpl
|| anhp
->rcode
== ns_r_refused
)
1481 DprintQ(statp
->options
& RES_DEBUG
, (stdout
, "server rejected query:\n"), ans
, (resplen
> *anssiz
) ? *anssiz
: resplen
);
1483 /* don't retry if called from dig */
1484 if (!statp
->pfcode
) return anhp
->rcode
;
1487 if (!(statp
->options
& RES_IGNTC
) && anhp
->tc
)
1490 * To get the rest of answer,
1491 * use TCP with same server.
1493 Dprint(statp
->options
& RES_DEBUG
, (stdout
, ";; truncated answer\n"));
1496 return ns_r_noerror
;
1500 * All is well, or the error is fatal. Signal that the
1501 * next nameserver ought not be tried.
1504 return ns_r_noerror
;
1508 Aerror(const res_state statp
, FILE *file
, const char *string
, int error
, const struct sockaddr
*address
, int alen
)
1511 char hbuf
[NI_MAXHOST
];
1512 char sbuf
[NI_MAXSERV
];
1516 if ((statp
->options
& RES_DEBUG
) != 0)
1518 if (getnameinfo(address
, alen
, hbuf
, sizeof(hbuf
), sbuf
, sizeof(sbuf
), niflags
))
1520 strncpy(hbuf
, "?", sizeof(hbuf
) - 1);
1521 hbuf
[sizeof(hbuf
) - 1] = '\0';
1522 strncpy(sbuf
, "?", sizeof(sbuf
) - 1);
1523 sbuf
[sizeof(sbuf
) - 1] = '\0';
1526 fprintf(file
, "res_send: %s ([%s].%s): %s\n", string
, hbuf
, sbuf
, strerror(error
));
1533 Perror(const res_state statp
, FILE *file
, const char *string
, int error
)
1537 if ((statp
->options
& RES_DEBUG
) != 0) fprintf(file
, "res_send: %s: %s\n", string
, strerror(error
));
1542 sock_eq(struct sockaddr
*a
, struct sockaddr
*b
)
1544 struct sockaddr_in
*a4
, *b4
;
1545 struct sockaddr_in6
*a6
, *b6
;
1547 if (a
->sa_family
!= b
->sa_family
) return 0;
1549 switch (a
->sa_family
)
1552 a4
= (struct sockaddr_in
*)a
;
1553 b4
= (struct sockaddr_in
*)b
;
1554 return a4
->sin_port
== b4
->sin_port
&& a4
->sin_addr
.s_addr
== b4
->sin_addr
.s_addr
;
1556 a6
= (struct sockaddr_in6
*)a
;
1557 b6
= (struct sockaddr_in6
*)b
;
1558 return a6
->sin6_port
== b6
->sin6_port
&&
1559 #ifdef HAVE_SIN6_SCOPE_ID
1560 a6
->sin6_scope_id
== b6
->sin6_scope_id
&&
1562 IN6_ARE_ADDR_EQUAL(&a6
->sin6_addr
, &b6
->sin6_addr
);
1568 #ifdef USE_DNS_PSELECT
1570 dns_pselect(int nfds
, void *rfds
, void *wfds
, void *efds
, struct timespec
*tsp
, const sigset_t
*sigmask
)
1572 struct timeval tv
, *tvp
= NULL
;
1579 tv
= evTimeVal(*tsp
);
1582 if (sigmask
) sigprocmask(SIG_SETMASK
, sigmask
, &sigs
);
1583 n
= select(nfds
, rfds
, wfds
, efds
, tvp
);
1584 if (sigmask
) sigprocmask(SIG_SETMASK
, &sigs
, NULL
);
1585 if (tsp
) *tsp
= evTimeSpec(tv
);