res_send.c revision 156952
1156952Sume/* 2156952Sume * Copyright (c) 1985, 1989, 1993 3156952Sume * The Regents of the University of California. All rights reserved. 4156952Sume * 5156952Sume * Redistribution and use in source and binary forms, with or without 6156952Sume * modification, are permitted provided that the following conditions 7156952Sume * are met: 8156952Sume * 1. Redistributions of source code must retain the above copyright 9156952Sume * notice, this list of conditions and the following disclaimer. 10156952Sume * 2. Redistributions in binary form must reproduce the above copyright 11156952Sume * notice, this list of conditions and the following disclaimer in the 12156952Sume * documentation and/or other materials provided with the distribution. 13156952Sume * 3. All advertising materials mentioning features or use of this software 14156952Sume * must display the following acknowledgement: 15156952Sume * This product includes software developed by the University of 16156952Sume * California, Berkeley and its contributors. 17156952Sume * 4. Neither the name of the University nor the names of its contributors 18156952Sume * may be used to endorse or promote products derived from this software 19156952Sume * without specific prior written permission. 20156952Sume * 21156952Sume * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22156952Sume * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23156952Sume * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24156952Sume * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25156952Sume * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26156952Sume * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27156952Sume * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28156952Sume * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29156952Sume * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30156952Sume * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31156952Sume * SUCH DAMAGE. 32156952Sume */ 33156952Sume 34156952Sume/* 35156952Sume * Portions Copyright (c) 1993 by Digital Equipment Corporation. 36156952Sume * 37156952Sume * Permission to use, copy, modify, and distribute this software for any 38156952Sume * purpose with or without fee is hereby granted, provided that the above 39156952Sume * copyright notice and this permission notice appear in all copies, and that 40156952Sume * the name of Digital Equipment Corporation not be used in advertising or 41156952Sume * publicity pertaining to distribution of the document or software without 42156952Sume * specific, written prior permission. 43156952Sume * 44156952Sume * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL 45156952Sume * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES 46156952Sume * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT 47156952Sume * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 48156952Sume * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 49156952Sume * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 50156952Sume * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 51156952Sume * SOFTWARE. 52156952Sume */ 53156952Sume 54156952Sume/* 55156952Sume * Copyright (c) 2005 by Internet Systems Consortium, Inc. ("ISC") 56156952Sume * Portions Copyright (c) 1996-1999 by Internet Software Consortium. 57156952Sume * 58156952Sume * Permission to use, copy, modify, and distribute this software for any 59156952Sume * purpose with or without fee is hereby granted, provided that the above 60156952Sume * copyright notice and this permission notice appear in all copies. 61156952Sume * 62156952Sume * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 63156952Sume * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 64156952Sume * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 65156952Sume * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 66156952Sume * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 67156952Sume * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 68156952Sume * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 69156952Sume */ 70156952Sume 71156952Sume#if defined(LIBC_SCCS) && !defined(lint) 72156952Sumestatic const char sccsid[] = "@(#)res_send.c 8.1 (Berkeley) 6/4/93"; 73156952Sumestatic const char rcsid[] = "$Id: res_send.c,v 1.5.2.2.4.7 2005/08/15 02:04:41 marka Exp $"; 74156952Sume#endif /* LIBC_SCCS and not lint */ 75156952Sume 76156952Sume/* 77156952Sume * Send query to name server and wait for reply. 78156952Sume */ 79156952Sume 80156952Sume#include "port_before.h" 81156952Sume#include "fd_setsize.h" 82156952Sume 83156952Sume#include <sys/types.h> 84156952Sume#include <sys/param.h> 85156952Sume#include <sys/time.h> 86156952Sume#include <sys/socket.h> 87156952Sume#include <sys/uio.h> 88156952Sume 89156952Sume#include <netinet/in.h> 90156952Sume#include <arpa/nameser.h> 91156952Sume#include <arpa/inet.h> 92156952Sume 93156952Sume#include <errno.h> 94156952Sume#include <netdb.h> 95156952Sume#include <resolv.h> 96156952Sume#include <signal.h> 97156952Sume#include <stdio.h> 98156952Sume#include <stdlib.h> 99156952Sume#include <string.h> 100156952Sume#include <unistd.h> 101156952Sume 102156952Sume#include <isc/eventlib.h> 103156952Sume 104156952Sume#include "port_after.h" 105156952Sume 106156952Sume#ifdef USE_POLL 107156952Sume#ifdef HAVE_STROPTS_H 108156952Sume#include <stropts.h> 109156952Sume#endif 110156952Sume#include <poll.h> 111156952Sume#endif /* USE_POLL */ 112156952Sume 113156952Sume/* Options. Leave them on. */ 114156952Sume#define DEBUG 115156952Sume#include "res_debug.h" 116156952Sume#include "res_private.h" 117156952Sume 118156952Sume#define EXT(res) ((res)->_u._ext) 119156952Sume 120156952Sume#ifndef USE_POLL 121156952Sumestatic const int highestFD = FD_SETSIZE - 1; 122156952Sume#else 123156952Sumestatic int highestFD = 0; 124156952Sume#endif 125156952Sume 126156952Sume/* Forward. */ 127156952Sume 128156952Sumestatic int get_salen __P((const struct sockaddr *)); 129156952Sumestatic struct sockaddr * get_nsaddr __P((res_state, size_t)); 130156952Sumestatic int send_vc(res_state, const u_char *, int, 131156952Sume u_char *, int, int *, int); 132156952Sumestatic int send_dg(res_state, const u_char *, int, 133156952Sume u_char *, int, int *, int, 134156952Sume int *, int *); 135156952Sumestatic void Aerror(const res_state, FILE *, const char *, int, 136156952Sume const struct sockaddr *, int); 137156952Sumestatic void Perror(const res_state, FILE *, const char *, int); 138156952Sumestatic int sock_eq(struct sockaddr *, struct sockaddr *); 139156952Sume#if defined(NEED_PSELECT) && !defined(USE_POLL) 140156952Sumestatic int pselect(int, void *, void *, void *, 141156952Sume struct timespec *, 142156952Sume const sigset_t *); 143156952Sume#endif 144156952Sumevoid res_pquery(const res_state, const u_char *, int, FILE *); 145156952Sume 146156952Sumestatic const int niflags = NI_NUMERICHOST | NI_NUMERICSERV; 147156952Sume 148156952Sume/* Public. */ 149156952Sume 150156952Sume/* int 151156952Sume * res_isourserver(ina) 152156952Sume * looks up "ina" in _res.ns_addr_list[] 153156952Sume * returns: 154156952Sume * 0 : not found 155156952Sume * >0 : found 156156952Sume * author: 157156952Sume * paul vixie, 29may94 158156952Sume */ 159156952Sumeint 160156952Sumeres_ourserver_p(const res_state statp, const struct sockaddr *sa) { 161156952Sume const struct sockaddr_in *inp, *srv; 162156952Sume const struct sockaddr_in6 *in6p, *srv6; 163156952Sume int ns; 164156952Sume 165156952Sume switch (sa->sa_family) { 166156952Sume case AF_INET: 167156952Sume inp = (const struct sockaddr_in *)sa; 168156952Sume for (ns = 0; ns < statp->nscount; ns++) { 169156952Sume srv = (struct sockaddr_in *)get_nsaddr(statp, ns); 170156952Sume if (srv->sin_family == inp->sin_family && 171156952Sume srv->sin_port == inp->sin_port && 172156952Sume (srv->sin_addr.s_addr == INADDR_ANY || 173156952Sume srv->sin_addr.s_addr == inp->sin_addr.s_addr)) 174156952Sume return (1); 175156952Sume } 176156952Sume break; 177156952Sume case AF_INET6: 178156952Sume if (EXT(statp).ext == NULL) 179156952Sume break; 180156952Sume in6p = (const struct sockaddr_in6 *)sa; 181156952Sume for (ns = 0; ns < statp->nscount; ns++) { 182156952Sume srv6 = (struct sockaddr_in6 *)get_nsaddr(statp, ns); 183156952Sume if (srv6->sin6_family == in6p->sin6_family && 184156952Sume srv6->sin6_port == in6p->sin6_port && 185156952Sume#ifdef HAVE_SIN6_SCOPE_ID 186156952Sume (srv6->sin6_scope_id == 0 || 187156952Sume srv6->sin6_scope_id == in6p->sin6_scope_id) && 188156952Sume#endif 189156952Sume (IN6_IS_ADDR_UNSPECIFIED(&srv6->sin6_addr) || 190156952Sume IN6_ARE_ADDR_EQUAL(&srv6->sin6_addr, &in6p->sin6_addr))) 191156952Sume return (1); 192156952Sume } 193156952Sume break; 194156952Sume default: 195156952Sume break; 196156952Sume } 197156952Sume return (0); 198156952Sume} 199156952Sume 200156952Sume/* int 201156952Sume * res_nameinquery(name, type, class, buf, eom) 202156952Sume * look for (name,type,class) in the query section of packet (buf,eom) 203156952Sume * requires: 204156952Sume * buf + HFIXEDSZ <= eom 205156952Sume * returns: 206156952Sume * -1 : format error 207156952Sume * 0 : not found 208156952Sume * >0 : found 209156952Sume * author: 210156952Sume * paul vixie, 29may94 211156952Sume */ 212156952Sumeint 213156952Sumeres_nameinquery(const char *name, int type, int class, 214156952Sume const u_char *buf, const u_char *eom) 215156952Sume{ 216156952Sume const u_char *cp = buf + HFIXEDSZ; 217156952Sume int qdcount = ntohs(((const HEADER*)buf)->qdcount); 218156952Sume 219156952Sume while (qdcount-- > 0) { 220156952Sume char tname[MAXDNAME+1]; 221156952Sume int n, ttype, tclass; 222156952Sume 223156952Sume n = dn_expand(buf, eom, cp, tname, sizeof tname); 224156952Sume if (n < 0) 225156952Sume return (-1); 226156952Sume cp += n; 227156952Sume if (cp + 2 * INT16SZ > eom) 228156952Sume return (-1); 229156952Sume ttype = ns_get16(cp); cp += INT16SZ; 230156952Sume tclass = ns_get16(cp); cp += INT16SZ; 231156952Sume if (ttype == type && tclass == class && 232156952Sume ns_samename(tname, name) == 1) 233156952Sume return (1); 234156952Sume } 235156952Sume return (0); 236156952Sume} 237156952Sume 238156952Sume/* int 239156952Sume * res_queriesmatch(buf1, eom1, buf2, eom2) 240156952Sume * is there a 1:1 mapping of (name,type,class) 241156952Sume * in (buf1,eom1) and (buf2,eom2)? 242156952Sume * returns: 243156952Sume * -1 : format error 244156952Sume * 0 : not a 1:1 mapping 245156952Sume * >0 : is a 1:1 mapping 246156952Sume * author: 247156952Sume * paul vixie, 29may94 248156952Sume */ 249156952Sumeint 250156952Sumeres_queriesmatch(const u_char *buf1, const u_char *eom1, 251156952Sume const u_char *buf2, const u_char *eom2) 252156952Sume{ 253156952Sume const u_char *cp = buf1 + HFIXEDSZ; 254156952Sume int qdcount = ntohs(((const HEADER*)buf1)->qdcount); 255156952Sume 256156952Sume if (buf1 + HFIXEDSZ > eom1 || buf2 + HFIXEDSZ > eom2) 257156952Sume return (-1); 258156952Sume 259156952Sume /* 260156952Sume * Only header section present in replies to 261156952Sume * dynamic update packets. 262156952Sume */ 263156952Sume if ((((const HEADER *)buf1)->opcode == ns_o_update) && 264156952Sume (((const HEADER *)buf2)->opcode == ns_o_update)) 265156952Sume return (1); 266156952Sume 267156952Sume if (qdcount != ntohs(((const HEADER*)buf2)->qdcount)) 268156952Sume return (0); 269156952Sume while (qdcount-- > 0) { 270156952Sume char tname[MAXDNAME+1]; 271156952Sume int n, ttype, tclass; 272156952Sume 273156952Sume n = dn_expand(buf1, eom1, cp, tname, sizeof tname); 274156952Sume if (n < 0) 275156952Sume return (-1); 276156952Sume cp += n; 277156952Sume if (cp + 2 * INT16SZ > eom1) 278156952Sume return (-1); 279156952Sume ttype = ns_get16(cp); cp += INT16SZ; 280156952Sume tclass = ns_get16(cp); cp += INT16SZ; 281156952Sume if (!res_nameinquery(tname, ttype, tclass, buf2, eom2)) 282156952Sume return (0); 283156952Sume } 284156952Sume return (1); 285156952Sume} 286156952Sume 287156952Sumeint 288156952Sumeres_nsend(res_state statp, 289156952Sume const u_char *buf, int buflen, u_char *ans, int anssiz) 290156952Sume{ 291156952Sume int gotsomewhere, terrno, try, v_circuit, resplen, ns, n; 292156952Sume char abuf[NI_MAXHOST]; 293156952Sume 294156952Sume#ifdef USE_POLL 295156952Sume highestFD = sysconf(_SC_OPEN_MAX) - 1; 296156952Sume#endif 297156952Sume 298156952Sume if (statp->nscount == 0) { 299156952Sume errno = ESRCH; 300156952Sume return (-1); 301156952Sume } 302156952Sume if (anssiz < HFIXEDSZ) { 303156952Sume errno = EINVAL; 304156952Sume return (-1); 305156952Sume } 306156952Sume DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_QUERY), 307156952Sume (stdout, ";; res_send()\n"), buf, buflen); 308156952Sume v_circuit = (statp->options & RES_USEVC) || buflen > PACKETSZ; 309156952Sume gotsomewhere = 0; 310156952Sume terrno = ETIMEDOUT; 311156952Sume 312156952Sume /* 313156952Sume * If the ns_addr_list in the resolver context has changed, then 314156952Sume * invalidate our cached copy and the associated timing data. 315156952Sume */ 316156952Sume if (EXT(statp).nscount != 0) { 317156952Sume int needclose = 0; 318156952Sume struct sockaddr_storage peer; 319156952Sume ISC_SOCKLEN_T peerlen; 320156952Sume 321156952Sume if (EXT(statp).nscount != statp->nscount) 322156952Sume needclose++; 323156952Sume else 324156952Sume for (ns = 0; ns < statp->nscount; ns++) { 325156952Sume if (statp->nsaddr_list[ns].sin_family && 326156952Sume !sock_eq((struct sockaddr *)&statp->nsaddr_list[ns], 327156952Sume (struct sockaddr *)&EXT(statp).ext->nsaddrs[ns])) { 328156952Sume needclose++; 329156952Sume break; 330156952Sume } 331156952Sume 332156952Sume if (EXT(statp).nssocks[ns] == -1) 333156952Sume continue; 334156952Sume peerlen = sizeof(peer); 335156952Sume if (getsockname(EXT(statp).nssocks[ns], 336156952Sume (struct sockaddr *)&peer, &peerlen) < 0) { 337156952Sume needclose++; 338156952Sume break; 339156952Sume } 340156952Sume if (!sock_eq((struct sockaddr *)&peer, 341156952Sume get_nsaddr(statp, ns))) { 342156952Sume needclose++; 343156952Sume break; 344156952Sume } 345156952Sume } 346156952Sume if (needclose) { 347156952Sume res_nclose(statp); 348156952Sume EXT(statp).nscount = 0; 349156952Sume } 350156952Sume } 351156952Sume 352156952Sume /* 353156952Sume * Maybe initialize our private copy of the ns_addr_list. 354156952Sume */ 355156952Sume if (EXT(statp).nscount == 0) { 356156952Sume for (ns = 0; ns < statp->nscount; ns++) { 357156952Sume EXT(statp).nstimes[ns] = RES_MAXTIME; 358156952Sume EXT(statp).nssocks[ns] = -1; 359156952Sume if (!statp->nsaddr_list[ns].sin_family) 360156952Sume continue; 361156952Sume EXT(statp).ext->nsaddrs[ns].sin = 362156952Sume statp->nsaddr_list[ns]; 363156952Sume } 364156952Sume EXT(statp).nscount = statp->nscount; 365156952Sume } 366156952Sume 367156952Sume /* 368156952Sume * Some resolvers want to even out the load on their nameservers. 369156952Sume * Note that RES_BLAST overrides RES_ROTATE. 370156952Sume */ 371156952Sume if ((statp->options & RES_ROTATE) != 0U && 372156952Sume (statp->options & RES_BLAST) == 0U) { 373156952Sume union res_sockaddr_union inu; 374156952Sume struct sockaddr_in ina; 375156952Sume int lastns = statp->nscount - 1; 376156952Sume int fd; 377156952Sume u_int16_t nstime; 378156952Sume 379156952Sume if (EXT(statp).ext != NULL) 380156952Sume inu = EXT(statp).ext->nsaddrs[0]; 381156952Sume ina = statp->nsaddr_list[0]; 382156952Sume fd = EXT(statp).nssocks[0]; 383156952Sume nstime = EXT(statp).nstimes[0]; 384156952Sume for (ns = 0; ns < lastns; ns++) { 385156952Sume if (EXT(statp).ext != NULL) 386156952Sume EXT(statp).ext->nsaddrs[ns] = 387156952Sume EXT(statp).ext->nsaddrs[ns + 1]; 388156952Sume statp->nsaddr_list[ns] = statp->nsaddr_list[ns + 1]; 389156952Sume EXT(statp).nssocks[ns] = EXT(statp).nssocks[ns + 1]; 390156952Sume EXT(statp).nstimes[ns] = EXT(statp).nstimes[ns + 1]; 391156952Sume } 392156952Sume if (EXT(statp).ext != NULL) 393156952Sume EXT(statp).ext->nsaddrs[lastns] = inu; 394156952Sume statp->nsaddr_list[lastns] = ina; 395156952Sume EXT(statp).nssocks[lastns] = fd; 396156952Sume EXT(statp).nstimes[lastns] = nstime; 397156952Sume } 398156952Sume 399156952Sume /* 400156952Sume * Send request, RETRY times, or until successful. 401156952Sume */ 402156952Sume for (try = 0; try < statp->retry; try++) { 403156952Sume for (ns = 0; ns < statp->nscount; ns++) { 404156952Sume struct sockaddr *nsap; 405156952Sume int nsaplen; 406156952Sume nsap = get_nsaddr(statp, ns); 407156952Sume nsaplen = get_salen(nsap); 408156952Sume statp->_flags &= ~RES_F_LASTMASK; 409156952Sume statp->_flags |= (ns << RES_F_LASTSHIFT); 410156952Sume same_ns: 411156952Sume if (statp->qhook) { 412156952Sume int done = 0, loops = 0; 413156952Sume 414156952Sume do { 415156952Sume res_sendhookact act; 416156952Sume 417156952Sume act = (*statp->qhook)(&nsap, &buf, &buflen, 418156952Sume ans, anssiz, &resplen); 419156952Sume switch (act) { 420156952Sume case res_goahead: 421156952Sume done = 1; 422156952Sume break; 423156952Sume case res_nextns: 424156952Sume res_nclose(statp); 425156952Sume goto next_ns; 426156952Sume case res_done: 427156952Sume return (resplen); 428156952Sume case res_modified: 429156952Sume /* give the hook another try */ 430156952Sume if (++loops < 42) /*doug adams*/ 431156952Sume break; 432156952Sume /*FALLTHROUGH*/ 433156952Sume case res_error: 434156952Sume /*FALLTHROUGH*/ 435156952Sume default: 436156952Sume goto fail; 437156952Sume } 438156952Sume } while (!done); 439156952Sume } 440156952Sume 441156952Sume Dprint(((statp->options & RES_DEBUG) && 442156952Sume getnameinfo(nsap, nsaplen, abuf, sizeof(abuf), 443156952Sume NULL, 0, niflags) == 0), 444156952Sume (stdout, ";; Querying server (# %d) address = %s\n", 445156952Sume ns + 1, abuf)); 446156952Sume 447156952Sume 448156952Sume if (v_circuit) { 449156952Sume /* Use VC; at most one attempt per server. */ 450156952Sume try = statp->retry; 451156952Sume n = send_vc(statp, buf, buflen, ans, anssiz, &terrno, 452156952Sume ns); 453156952Sume if (n < 0) 454156952Sume goto fail; 455156952Sume if (n == 0) 456156952Sume goto next_ns; 457156952Sume resplen = n; 458156952Sume } else { 459156952Sume /* Use datagrams. */ 460156952Sume n = send_dg(statp, buf, buflen, ans, anssiz, &terrno, 461156952Sume ns, &v_circuit, &gotsomewhere); 462156952Sume if (n < 0) 463156952Sume goto fail; 464156952Sume if (n == 0) 465156952Sume goto next_ns; 466156952Sume if (v_circuit) 467156952Sume goto same_ns; 468156952Sume resplen = n; 469156952Sume } 470156952Sume 471156952Sume Dprint((statp->options & RES_DEBUG) || 472156952Sume ((statp->pfcode & RES_PRF_REPLY) && 473156952Sume (statp->pfcode & RES_PRF_HEAD1)), 474156952Sume (stdout, ";; got answer:\n")); 475156952Sume 476156952Sume DprintQ((statp->options & RES_DEBUG) || 477156952Sume (statp->pfcode & RES_PRF_REPLY), 478156952Sume (stdout, "%s", ""), 479156952Sume ans, (resplen > anssiz) ? anssiz : resplen); 480156952Sume 481156952Sume /* 482156952Sume * If we have temporarily opened a virtual circuit, 483156952Sume * or if we haven't been asked to keep a socket open, 484156952Sume * close the socket. 485156952Sume */ 486156952Sume if ((v_circuit && (statp->options & RES_USEVC) == 0U) || 487156952Sume (statp->options & RES_STAYOPEN) == 0U) { 488156952Sume res_nclose(statp); 489156952Sume } 490156952Sume if (statp->rhook) { 491156952Sume int done = 0, loops = 0; 492156952Sume 493156952Sume do { 494156952Sume res_sendhookact act; 495156952Sume 496156952Sume act = (*statp->rhook)(nsap, buf, buflen, 497156952Sume ans, anssiz, &resplen); 498156952Sume switch (act) { 499156952Sume case res_goahead: 500156952Sume case res_done: 501156952Sume done = 1; 502156952Sume break; 503156952Sume case res_nextns: 504156952Sume res_nclose(statp); 505156952Sume goto next_ns; 506156952Sume case res_modified: 507156952Sume /* give the hook another try */ 508156952Sume if (++loops < 42) /*doug adams*/ 509156952Sume break; 510156952Sume /*FALLTHROUGH*/ 511156952Sume case res_error: 512156952Sume /*FALLTHROUGH*/ 513156952Sume default: 514156952Sume goto fail; 515156952Sume } 516156952Sume } while (!done); 517156952Sume 518156952Sume } 519156952Sume return (resplen); 520156952Sume next_ns: ; 521156952Sume } /*foreach ns*/ 522156952Sume } /*foreach retry*/ 523156952Sume res_nclose(statp); 524156952Sume if (!v_circuit) { 525156952Sume if (!gotsomewhere) 526156952Sume errno = ECONNREFUSED; /* no nameservers found */ 527156952Sume else 528156952Sume errno = ETIMEDOUT; /* no answer obtained */ 529156952Sume } else 530156952Sume errno = terrno; 531156952Sume return (-1); 532156952Sume fail: 533156952Sume res_nclose(statp); 534156952Sume return (-1); 535156952Sume} 536156952Sume 537156952Sume/* Private */ 538156952Sume 539156952Sumestatic int 540156952Sumeget_salen(sa) 541156952Sume const struct sockaddr *sa; 542156952Sume{ 543156952Sume 544156952Sume#ifdef HAVE_SA_LEN 545156952Sume /* There are people do not set sa_len. Be forgiving to them. */ 546156952Sume if (sa->sa_len) 547156952Sume return (sa->sa_len); 548156952Sume#endif 549156952Sume 550156952Sume if (sa->sa_family == AF_INET) 551156952Sume return (sizeof(struct sockaddr_in)); 552156952Sume else if (sa->sa_family == AF_INET6) 553156952Sume return (sizeof(struct sockaddr_in6)); 554156952Sume else 555156952Sume return (0); /* unknown, die on connect */ 556156952Sume} 557156952Sume 558156952Sume/* 559156952Sume * pick appropriate nsaddr_list for use. see res_init() for initialization. 560156952Sume */ 561156952Sumestatic struct sockaddr * 562156952Sumeget_nsaddr(statp, n) 563156952Sume res_state statp; 564156952Sume size_t n; 565156952Sume{ 566156952Sume 567156952Sume if (!statp->nsaddr_list[n].sin_family && EXT(statp).ext) { 568156952Sume /* 569156952Sume * - EXT(statp).ext->nsaddrs[n] holds an address that is larger 570156952Sume * than struct sockaddr, and 571156952Sume * - user code did not update statp->nsaddr_list[n]. 572156952Sume */ 573156952Sume return (struct sockaddr *)(void *)&EXT(statp).ext->nsaddrs[n]; 574156952Sume } else { 575156952Sume /* 576156952Sume * - user code updated statp->nsaddr_list[n], or 577156952Sume * - statp->nsaddr_list[n] has the same content as 578156952Sume * EXT(statp).ext->nsaddrs[n]. 579156952Sume */ 580156952Sume return (struct sockaddr *)(void *)&statp->nsaddr_list[n]; 581156952Sume } 582156952Sume} 583156952Sume 584156952Sumestatic int 585156952Sumesend_vc(res_state statp, 586156952Sume const u_char *buf, int buflen, u_char *ans, int anssiz, 587156952Sume int *terrno, int ns) 588156952Sume{ 589156952Sume const HEADER *hp = (const HEADER *) buf; 590156952Sume HEADER *anhp = (HEADER *) ans; 591156952Sume struct sockaddr *nsap; 592156952Sume int nsaplen; 593156952Sume int truncating, connreset, resplen, n; 594156952Sume struct iovec iov[2]; 595156952Sume u_short len; 596156952Sume u_char *cp; 597156952Sume void *tmp; 598156952Sume 599156952Sume nsap = get_nsaddr(statp, ns); 600156952Sume nsaplen = get_salen(nsap); 601156952Sume 602156952Sume connreset = 0; 603156952Sume same_ns: 604156952Sume truncating = 0; 605156952Sume 606156952Sume /* Are we still talking to whom we want to talk to? */ 607156952Sume if (statp->_vcsock >= 0 && (statp->_flags & RES_F_VC) != 0) { 608156952Sume struct sockaddr_storage peer; 609156952Sume ISC_SOCKLEN_T size = sizeof peer; 610156952Sume 611156952Sume if (getpeername(statp->_vcsock, 612156952Sume (struct sockaddr *)&peer, &size) < 0 || 613156952Sume !sock_eq((struct sockaddr *)&peer, nsap)) { 614156952Sume res_nclose(statp); 615156952Sume statp->_flags &= ~RES_F_VC; 616156952Sume } 617156952Sume } 618156952Sume 619156952Sume if (statp->_vcsock < 0 || (statp->_flags & RES_F_VC) == 0) { 620156952Sume if (statp->_vcsock >= 0) 621156952Sume res_nclose(statp); 622156952Sume 623156952Sume statp->_vcsock = socket(nsap->sa_family, SOCK_STREAM, 0); 624156952Sume if (statp->_vcsock > highestFD) { 625156952Sume res_nclose(statp); 626156952Sume errno = ENOTSOCK; 627156952Sume } 628156952Sume if (statp->_vcsock < 0) { 629156952Sume switch (errno) { 630156952Sume case EPROTONOSUPPORT: 631156952Sume#ifdef EPFNOSUPPORT 632156952Sume case EPFNOSUPPORT: 633156952Sume#endif 634156952Sume case EAFNOSUPPORT: 635156952Sume Perror(statp, stderr, "socket(vc)", errno); 636156952Sume return (0); 637156952Sume default: 638156952Sume *terrno = errno; 639156952Sume Perror(statp, stderr, "socket(vc)", errno); 640156952Sume return (-1); 641156952Sume } 642156952Sume } 643156952Sume errno = 0; 644156952Sume if (connect(statp->_vcsock, nsap, nsaplen) < 0) { 645156952Sume *terrno = errno; 646156952Sume Aerror(statp, stderr, "connect/vc", errno, nsap, 647156952Sume nsaplen); 648156952Sume res_nclose(statp); 649156952Sume return (0); 650156952Sume } 651156952Sume statp->_flags |= RES_F_VC; 652156952Sume } 653156952Sume 654156952Sume /* 655156952Sume * Send length & message 656156952Sume */ 657156952Sume ns_put16((u_short)buflen, (u_char*)&len); 658156952Sume iov[0] = evConsIovec(&len, INT16SZ); 659156952Sume DE_CONST(buf, tmp); 660156952Sume iov[1] = evConsIovec(tmp, buflen); 661156952Sume if (writev(statp->_vcsock, iov, 2) != (INT16SZ + buflen)) { 662156952Sume *terrno = errno; 663156952Sume Perror(statp, stderr, "write failed", errno); 664156952Sume res_nclose(statp); 665156952Sume return (0); 666156952Sume } 667156952Sume /* 668156952Sume * Receive length & response 669156952Sume */ 670156952Sume read_len: 671156952Sume cp = ans; 672156952Sume len = INT16SZ; 673156952Sume while ((n = read(statp->_vcsock, (char *)cp, (int)len)) > 0) { 674156952Sume cp += n; 675156952Sume if ((len -= n) == 0) 676156952Sume break; 677156952Sume } 678156952Sume if (n <= 0) { 679156952Sume *terrno = errno; 680156952Sume Perror(statp, stderr, "read failed", errno); 681156952Sume res_nclose(statp); 682156952Sume /* 683156952Sume * A long running process might get its TCP 684156952Sume * connection reset if the remote server was 685156952Sume * restarted. Requery the server instead of 686156952Sume * trying a new one. When there is only one 687156952Sume * server, this means that a query might work 688156952Sume * instead of failing. We only allow one reset 689156952Sume * per query to prevent looping. 690156952Sume */ 691156952Sume if (*terrno == ECONNRESET && !connreset) { 692156952Sume connreset = 1; 693156952Sume res_nclose(statp); 694156952Sume goto same_ns; 695156952Sume } 696156952Sume res_nclose(statp); 697156952Sume return (0); 698156952Sume } 699156952Sume resplen = ns_get16(ans); 700156952Sume if (resplen > anssiz) { 701156952Sume Dprint(statp->options & RES_DEBUG, 702156952Sume (stdout, ";; response truncated\n") 703156952Sume ); 704156952Sume truncating = 1; 705156952Sume len = anssiz; 706156952Sume } else 707156952Sume len = resplen; 708156952Sume if (len < HFIXEDSZ) { 709156952Sume /* 710156952Sume * Undersized message. 711156952Sume */ 712156952Sume Dprint(statp->options & RES_DEBUG, 713156952Sume (stdout, ";; undersized: %d\n", len)); 714156952Sume *terrno = EMSGSIZE; 715156952Sume res_nclose(statp); 716156952Sume return (0); 717156952Sume } 718156952Sume cp = ans; 719156952Sume while (len != 0 && (n = read(statp->_vcsock, (char *)cp, (int)len)) > 0){ 720156952Sume cp += n; 721156952Sume len -= n; 722156952Sume } 723156952Sume if (n <= 0) { 724156952Sume *terrno = errno; 725156952Sume Perror(statp, stderr, "read(vc)", errno); 726156952Sume res_nclose(statp); 727156952Sume return (0); 728156952Sume } 729156952Sume if (truncating) { 730156952Sume /* 731156952Sume * Flush rest of answer so connection stays in synch. 732156952Sume */ 733156952Sume anhp->tc = 1; 734156952Sume len = resplen - anssiz; 735156952Sume while (len != 0) { 736156952Sume char junk[PACKETSZ]; 737156952Sume 738156952Sume n = read(statp->_vcsock, junk, 739156952Sume (len > sizeof junk) ? sizeof junk : len); 740156952Sume if (n > 0) 741156952Sume len -= n; 742156952Sume else 743156952Sume break; 744156952Sume } 745156952Sume } 746156952Sume /* 747156952Sume * If the calling applicating has bailed out of 748156952Sume * a previous call and failed to arrange to have 749156952Sume * the circuit closed or the server has got 750156952Sume * itself confused, then drop the packet and 751156952Sume * wait for the correct one. 752156952Sume */ 753156952Sume if (hp->id != anhp->id) { 754156952Sume DprintQ((statp->options & RES_DEBUG) || 755156952Sume (statp->pfcode & RES_PRF_REPLY), 756156952Sume (stdout, ";; old answer (unexpected):\n"), 757156952Sume ans, (resplen > anssiz) ? anssiz: resplen); 758156952Sume goto read_len; 759156952Sume } 760156952Sume 761156952Sume /* 762156952Sume * All is well, or the error is fatal. Signal that the 763156952Sume * next nameserver ought not be tried. 764156952Sume */ 765156952Sume return (resplen); 766156952Sume} 767156952Sume 768156952Sumestatic int 769156952Sumesend_dg(res_state statp, 770156952Sume const u_char *buf, int buflen, u_char *ans, int anssiz, 771156952Sume int *terrno, int ns, int *v_circuit, int *gotsomewhere) 772156952Sume{ 773156952Sume const HEADER *hp = (const HEADER *) buf; 774156952Sume HEADER *anhp = (HEADER *) ans; 775156952Sume const struct sockaddr *nsap; 776156952Sume int nsaplen; 777156952Sume struct timespec now, timeout, finish; 778156952Sume struct sockaddr_storage from; 779156952Sume ISC_SOCKLEN_T fromlen; 780156952Sume int resplen, seconds, n, s; 781156952Sume#ifdef USE_POLL 782156952Sume int polltimeout; 783156952Sume struct pollfd pollfd; 784156952Sume#else 785156952Sume fd_set dsmask; 786156952Sume#endif 787156952Sume 788156952Sume nsap = get_nsaddr(statp, ns); 789156952Sume nsaplen = get_salen(nsap); 790156952Sume if (EXT(statp).nssocks[ns] == -1) { 791156952Sume EXT(statp).nssocks[ns] = socket(nsap->sa_family, SOCK_DGRAM, 0); 792156952Sume if (EXT(statp).nssocks[ns] > highestFD) { 793156952Sume res_nclose(statp); 794156952Sume errno = ENOTSOCK; 795156952Sume } 796156952Sume if (EXT(statp).nssocks[ns] < 0) { 797156952Sume switch (errno) { 798156952Sume case EPROTONOSUPPORT: 799156952Sume#ifdef EPFNOSUPPORT 800156952Sume case EPFNOSUPPORT: 801156952Sume#endif 802156952Sume case EAFNOSUPPORT: 803156952Sume Perror(statp, stderr, "socket(dg)", errno); 804156952Sume return (0); 805156952Sume default: 806156952Sume *terrno = errno; 807156952Sume Perror(statp, stderr, "socket(dg)", errno); 808156952Sume return (-1); 809156952Sume } 810156952Sume } 811156952Sume#ifndef CANNOT_CONNECT_DGRAM 812156952Sume /* 813156952Sume * On a 4.3BSD+ machine (client and server, 814156952Sume * actually), sending to a nameserver datagram 815156952Sume * port with no nameserver will cause an 816156952Sume * ICMP port unreachable message to be returned. 817156952Sume * If our datagram socket is "connected" to the 818156952Sume * server, we get an ECONNREFUSED error on the next 819156952Sume * socket operation, and select returns if the 820156952Sume * error message is received. We can thus detect 821156952Sume * the absence of a nameserver without timing out. 822156952Sume */ 823156952Sume if (connect(EXT(statp).nssocks[ns], nsap, nsaplen) < 0) { 824156952Sume Aerror(statp, stderr, "connect(dg)", errno, nsap, 825156952Sume nsaplen); 826156952Sume res_nclose(statp); 827156952Sume return (0); 828156952Sume } 829156952Sume#endif /* !CANNOT_CONNECT_DGRAM */ 830156952Sume Dprint(statp->options & RES_DEBUG, 831156952Sume (stdout, ";; new DG socket\n")) 832156952Sume } 833156952Sume s = EXT(statp).nssocks[ns]; 834156952Sume#ifndef CANNOT_CONNECT_DGRAM 835156952Sume if (send(s, (const char*)buf, buflen, 0) != buflen) { 836156952Sume Perror(statp, stderr, "send", errno); 837156952Sume res_nclose(statp); 838156952Sume return (0); 839156952Sume } 840156952Sume#else /* !CANNOT_CONNECT_DGRAM */ 841156952Sume if (sendto(s, (const char*)buf, buflen, 0, nsap, nsaplen) != buflen) 842156952Sume { 843156952Sume Aerror(statp, stderr, "sendto", errno, nsap, nsaplen); 844156952Sume res_nclose(statp); 845156952Sume return (0); 846156952Sume } 847156952Sume#endif /* !CANNOT_CONNECT_DGRAM */ 848156952Sume 849156952Sume /* 850156952Sume * Wait for reply. 851156952Sume */ 852156952Sume seconds = (statp->retrans << ns); 853156952Sume if (ns > 0) 854156952Sume seconds /= statp->nscount; 855156952Sume if (seconds <= 0) 856156952Sume seconds = 1; 857156952Sume now = evNowTime(); 858156952Sume timeout = evConsTime(seconds, 0); 859156952Sume finish = evAddTime(now, timeout); 860156952Sume goto nonow; 861156952Sume wait: 862156952Sume now = evNowTime(); 863156952Sume nonow: 864156952Sume#ifndef USE_POLL 865156952Sume FD_ZERO(&dsmask); 866156952Sume FD_SET(s, &dsmask); 867156952Sume if (evCmpTime(finish, now) > 0) 868156952Sume timeout = evSubTime(finish, now); 869156952Sume else 870156952Sume timeout = evConsTime(0, 0); 871156952Sume n = pselect(s + 1, &dsmask, NULL, NULL, &timeout, NULL); 872156952Sume#else 873156952Sume timeout = evSubTime(finish, now); 874156952Sume if (timeout.tv_sec < 0) 875156952Sume timeout = evConsTime(0, 0); 876156952Sume polltimeout = 1000*timeout.tv_sec + 877156952Sume timeout.tv_nsec/1000000; 878156952Sume pollfd.fd = s; 879156952Sume pollfd.events = POLLRDNORM; 880156952Sume n = poll(&pollfd, 1, polltimeout); 881156952Sume#endif /* USE_POLL */ 882156952Sume 883156952Sume if (n == 0) { 884156952Sume Dprint(statp->options & RES_DEBUG, (stdout, ";; timeout\n")); 885156952Sume *gotsomewhere = 1; 886156952Sume return (0); 887156952Sume } 888156952Sume if (n < 0) { 889156952Sume if (errno == EINTR) 890156952Sume goto wait; 891156952Sume#ifndef USE_POLL 892156952Sume Perror(statp, stderr, "select", errno); 893156952Sume#else 894156952Sume Perror(statp, stderr, "poll", errno); 895156952Sume#endif /* USE_POLL */ 896156952Sume res_nclose(statp); 897156952Sume return (0); 898156952Sume } 899156952Sume errno = 0; 900156952Sume fromlen = sizeof(from); 901156952Sume resplen = recvfrom(s, (char*)ans, anssiz,0, 902156952Sume (struct sockaddr *)&from, &fromlen); 903156952Sume if (resplen <= 0) { 904156952Sume Perror(statp, stderr, "recvfrom", errno); 905156952Sume res_nclose(statp); 906156952Sume return (0); 907156952Sume } 908156952Sume *gotsomewhere = 1; 909156952Sume if (resplen < HFIXEDSZ) { 910156952Sume /* 911156952Sume * Undersized message. 912156952Sume */ 913156952Sume Dprint(statp->options & RES_DEBUG, 914156952Sume (stdout, ";; undersized: %d\n", 915156952Sume resplen)); 916156952Sume *terrno = EMSGSIZE; 917156952Sume res_nclose(statp); 918156952Sume return (0); 919156952Sume } 920156952Sume if (hp->id != anhp->id) { 921156952Sume /* 922156952Sume * response from old query, ignore it. 923156952Sume * XXX - potential security hazard could 924156952Sume * be detected here. 925156952Sume */ 926156952Sume DprintQ((statp->options & RES_DEBUG) || 927156952Sume (statp->pfcode & RES_PRF_REPLY), 928156952Sume (stdout, ";; old answer:\n"), 929156952Sume ans, (resplen > anssiz) ? anssiz : resplen); 930156952Sume goto wait; 931156952Sume } 932156952Sume if (!(statp->options & RES_INSECURE1) && 933156952Sume !res_ourserver_p(statp, (struct sockaddr *)&from)) { 934156952Sume /* 935156952Sume * response from wrong server? ignore it. 936156952Sume * XXX - potential security hazard could 937156952Sume * be detected here. 938156952Sume */ 939156952Sume DprintQ((statp->options & RES_DEBUG) || 940156952Sume (statp->pfcode & RES_PRF_REPLY), 941156952Sume (stdout, ";; not our server:\n"), 942156952Sume ans, (resplen > anssiz) ? anssiz : resplen); 943156952Sume goto wait; 944156952Sume } 945156952Sume#ifdef RES_USE_EDNS0 946156952Sume if (anhp->rcode == FORMERR && (statp->options & RES_USE_EDNS0) != 0U) { 947156952Sume /* 948156952Sume * Do not retry if the server do not understand EDNS0. 949156952Sume * The case has to be captured here, as FORMERR packet do not 950156952Sume * carry query section, hence res_queriesmatch() returns 0. 951156952Sume */ 952156952Sume DprintQ(statp->options & RES_DEBUG, 953156952Sume (stdout, "server rejected query with EDNS0:\n"), 954156952Sume ans, (resplen > anssiz) ? anssiz : resplen); 955156952Sume /* record the error */ 956156952Sume statp->_flags |= RES_F_EDNS0ERR; 957156952Sume res_nclose(statp); 958156952Sume return (0); 959156952Sume } 960156952Sume#endif 961156952Sume if (!(statp->options & RES_INSECURE2) && 962156952Sume !res_queriesmatch(buf, buf + buflen, 963156952Sume ans, ans + anssiz)) { 964156952Sume /* 965156952Sume * response contains wrong query? ignore it. 966156952Sume * XXX - potential security hazard could 967156952Sume * be detected here. 968156952Sume */ 969156952Sume DprintQ((statp->options & RES_DEBUG) || 970156952Sume (statp->pfcode & RES_PRF_REPLY), 971156952Sume (stdout, ";; wrong query name:\n"), 972156952Sume ans, (resplen > anssiz) ? anssiz : resplen); 973156952Sume goto wait; 974156952Sume } 975156952Sume if (anhp->rcode == SERVFAIL || 976156952Sume anhp->rcode == NOTIMP || 977156952Sume anhp->rcode == REFUSED) { 978156952Sume DprintQ(statp->options & RES_DEBUG, 979156952Sume (stdout, "server rejected query:\n"), 980156952Sume ans, (resplen > anssiz) ? anssiz : resplen); 981156952Sume res_nclose(statp); 982156952Sume /* don't retry if called from dig */ 983156952Sume if (!statp->pfcode) 984156952Sume return (0); 985156952Sume } 986156952Sume if (!(statp->options & RES_IGNTC) && anhp->tc) { 987156952Sume /* 988156952Sume * To get the rest of answer, 989156952Sume * use TCP with same server. 990156952Sume */ 991156952Sume Dprint(statp->options & RES_DEBUG, 992156952Sume (stdout, ";; truncated answer\n")); 993156952Sume *v_circuit = 1; 994156952Sume res_nclose(statp); 995156952Sume return (1); 996156952Sume } 997156952Sume /* 998156952Sume * All is well, or the error is fatal. Signal that the 999156952Sume * next nameserver ought not be tried. 1000156952Sume */ 1001156952Sume return (resplen); 1002156952Sume} 1003156952Sume 1004156952Sumestatic void 1005156952SumeAerror(const res_state statp, FILE *file, const char *string, int error, 1006156952Sume const struct sockaddr *address, int alen) 1007156952Sume{ 1008156952Sume int save = errno; 1009156952Sume char hbuf[NI_MAXHOST]; 1010156952Sume char sbuf[NI_MAXSERV]; 1011156952Sume 1012156952Sume alen = alen; 1013156952Sume 1014156952Sume if ((statp->options & RES_DEBUG) != 0U) { 1015156952Sume if (getnameinfo(address, alen, hbuf, sizeof(hbuf), 1016156952Sume sbuf, sizeof(sbuf), niflags)) { 1017156952Sume strncpy(hbuf, "?", sizeof(hbuf) - 1); 1018156952Sume hbuf[sizeof(hbuf) - 1] = '\0'; 1019156952Sume strncpy(sbuf, "?", sizeof(sbuf) - 1); 1020156952Sume sbuf[sizeof(sbuf) - 1] = '\0'; 1021156952Sume } 1022156952Sume fprintf(file, "res_send: %s ([%s].%s): %s\n", 1023156952Sume string, hbuf, sbuf, strerror(error)); 1024156952Sume } 1025156952Sume errno = save; 1026156952Sume} 1027156952Sume 1028156952Sumestatic void 1029156952SumePerror(const res_state statp, FILE *file, const char *string, int error) { 1030156952Sume int save = errno; 1031156952Sume 1032156952Sume if ((statp->options & RES_DEBUG) != 0U) 1033156952Sume fprintf(file, "res_send: %s: %s\n", 1034156952Sume string, strerror(error)); 1035156952Sume errno = save; 1036156952Sume} 1037156952Sume 1038156952Sumestatic int 1039156952Sumesock_eq(struct sockaddr *a, struct sockaddr *b) { 1040156952Sume struct sockaddr_in *a4, *b4; 1041156952Sume struct sockaddr_in6 *a6, *b6; 1042156952Sume 1043156952Sume if (a->sa_family != b->sa_family) 1044156952Sume return 0; 1045156952Sume switch (a->sa_family) { 1046156952Sume case AF_INET: 1047156952Sume a4 = (struct sockaddr_in *)a; 1048156952Sume b4 = (struct sockaddr_in *)b; 1049156952Sume return a4->sin_port == b4->sin_port && 1050156952Sume a4->sin_addr.s_addr == b4->sin_addr.s_addr; 1051156952Sume case AF_INET6: 1052156952Sume a6 = (struct sockaddr_in6 *)a; 1053156952Sume b6 = (struct sockaddr_in6 *)b; 1054156952Sume return a6->sin6_port == b6->sin6_port && 1055156952Sume#ifdef HAVE_SIN6_SCOPE_ID 1056156952Sume a6->sin6_scope_id == b6->sin6_scope_id && 1057156952Sume#endif 1058156952Sume IN6_ARE_ADDR_EQUAL(&a6->sin6_addr, &b6->sin6_addr); 1059156952Sume default: 1060156952Sume return 0; 1061156952Sume } 1062156952Sume} 1063156952Sume 1064156952Sume#if defined(NEED_PSELECT) && !defined(USE_POLL) 1065156952Sume/* XXX needs to move to the porting library. */ 1066156952Sumestatic int 1067156952Sumepselect(int nfds, void *rfds, void *wfds, void *efds, 1068156952Sume struct timespec *tsp, const sigset_t *sigmask) 1069156952Sume{ 1070156952Sume struct timeval tv, *tvp; 1071156952Sume sigset_t sigs; 1072156952Sume int n; 1073156952Sume 1074156952Sume if (tsp) { 1075156952Sume tvp = &tv; 1076156952Sume tv = evTimeVal(*tsp); 1077156952Sume } else 1078156952Sume tvp = NULL; 1079156952Sume if (sigmask) 1080156952Sume sigprocmask(SIG_SETMASK, sigmask, &sigs); 1081156952Sume n = select(nfds, rfds, wfds, efds, tvp); 1082156952Sume if (sigmask) 1083156952Sume sigprocmask(SIG_SETMASK, &sigs, NULL); 1084156952Sume if (tsp) 1085156952Sume *tsp = evTimeSpec(tv); 1086156952Sume return (n); 1087156952Sume} 1088156952Sume#endif 1089