]> git.proxmox.com Git - mirror_edk2.git/blame - StdLib/BsdSocketLib/res_send.c
IntelFsp2WrapperPkg: Update gFspWrapperTokenSpaceGuid to gIntelFsp2WrapperTokenSpaceGuid.
[mirror_edk2.git] / StdLib / BsdSocketLib / res_send.c
CommitLineData
d7ce7006 1/*\r
2 * Copyright (c) 1985, 1989, 1993\r
3 * The Regents of the University of California. All rights reserved.\r
4 *\r
5 * Portions copyright (c) 1999, 2000\r
6 * Intel Corporation.\r
7 * All rights reserved.\r
8 *\r
9 * Redistribution and use in source and binary forms, with or without\r
10 * modification, are permitted provided that the following conditions\r
11 * are met:\r
12 *\r
13 * 1. Redistributions of source code must retain the above copyright\r
14 * notice, this list of conditions and the following disclaimer.\r
15 *\r
16 * 2. Redistributions in binary form must reproduce the above copyright\r
17 * notice, this list of conditions and the following disclaimer in the\r
18 * documentation and/or other materials provided with the distribution.\r
19 *\r
20 * 3. All advertising materials mentioning features or use of this software\r
21 * must display the following acknowledgement:\r
22 *\r
23 * This product includes software developed by the University of\r
24 * California, Berkeley, Intel Corporation, and its contributors.\r
25 *\r
26 * 4. Neither the name of University, Intel Corporation, or their respective\r
27 * contributors may be used to endorse or promote products derived from\r
28 * this software without specific prior written permission.\r
29 *\r
30 * THIS SOFTWARE IS PROVIDED BY THE REGENTS, INTEL CORPORATION AND\r
31 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\r
32 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\r
33 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS,\r
34 * INTEL CORPORATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
35 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
36 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
37 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
38 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
39 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
40 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
41 *\r
42 */\r
43\r
44/*\r
45 * Portions Copyright (c) 1993 by Digital Equipment Corporation.\r
46 *\r
47 * Permission to use, copy, modify, and distribute this software for any\r
48 * purpose with or without fee is hereby granted, provided that the above\r
49 * copyright notice and this permission notice appear in all copies, and that\r
50 * the name of Digital Equipment Corporation not be used in advertising or\r
51 * publicity pertaining to distribution of the document or software without\r
52 * specific, written prior permission.\r
53 *\r
54 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL\r
55 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES\r
56 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT\r
57 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL\r
58 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR\r
59 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS\r
60 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS\r
61 * SOFTWARE.\r
62 */\r
63\r
64/*\r
65 * Portions Copyright (c) 1996 by Internet Software Consortium.\r
66 *\r
67 * Permission to use, copy, modify, and distribute this software for any\r
68 * purpose with or without fee is hereby granted, provided that the above\r
69 * copyright notice and this permission notice appear in all copies.\r
70 *\r
71 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS\r
72 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES\r
73 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE\r
74 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL\r
75 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR\r
76 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS\r
77 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS\r
78 * SOFTWARE.\r
79 */\r
80\r
81#if defined(LIBC_SCCS) && !defined(lint)\r
82static char sccsid[] = "@(#)res_send.c 8.1 (Berkeley) 6/4/93";\r
83static char orig_rcsid[] = "From: Id: res_send.c,v 8.20 1998/04/06 23:27:51 halley Exp $";\r
84static char rcsid[] = "$Id: res_send.c,v 1.1.1.1 2003/11/19 01:51:39 kyu3 Exp $";\r
85#endif /* LIBC_SCCS and not lint */\r
86\r
87/*\r
88 * Send query to name server and wait for reply.\r
89 */\r
90\r
91#include <sys/types.h>\r
92#include <sys/param.h>\r
93#include <sys/select.h>\r
94#include <sys/socket.h>\r
95#include <sys/time.h>\r
96#include <sys/uio.h>\r
97\r
98#include <netinet/in.h>\r
99#include <arpa/nameser.h>\r
100#include <arpa/inet.h>\r
101\r
102#include <errno.h>\r
103#include <netdb.h>\r
104#include <resolv.h>\r
105#include <stdio.h>\r
106#include <stdlib.h>\r
107#include <string.h>\r
108#include <unistd.h>\r
109\r
110#include "res_config.h"\r
111\r
112#ifndef _ORG_FREEBSD_\r
113#define NOPOLL\r
114#endif\r
115\r
116#ifdef NOPOLL /* libc_r doesn't wrap poll yet() */\r
d7ce7006 117#else\r
118#include <poll.h>\r
119static int use_poll = 1; /* adapt to poll() syscall availability */\r
120 /* 0 = not present, 1 = try it, 2 = exists */\r
121#endif\r
122\r
123static int s = -1; /* socket used for communications */\r
124static int connected = 0; /* is the socket connected */\r
125static int vc = 0; /* is the socket a virtual circuit? */\r
126static res_send_qhook Qhook = NULL;\r
127static res_send_rhook Rhook = NULL;\r
128\r
129\r
130#define CAN_RECONNECT 1\r
131\r
132#ifndef DEBUG\r
133# define Dprint(cond, args) /*empty*/\r
134# define DprintQ(cond, args, query, size) /*empty*/\r
135# define Aerror(file, string, error, address) /*empty*/\r
136# define Perror(file, string, error) /*empty*/\r
137#else\r
138# define Dprint(cond, args) if (cond) {fprintf args;} else {}\r
139# define DprintQ(cond, args, query, size) if (cond) {\\r
140 fprintf args;\\r
141 __fp_nquery(query, size, stdout);\\r
142 } else {}\r
143\r
144static void\r
145Aerror(\r
146 FILE *file,\r
147 char *string,\r
148 int error,\r
149 struct sockaddr_in address\r
150 )\r
151{\r
152 int save = errno;\r
153\r
154 if (_res.options & RES_DEBUG) {\r
155 fprintf(file, "res_send: %s ([%s].%u): %s\n",\r
156 string,\r
157 inet_ntoa(address.sin_addr),\r
158 ntohs(address.sin_port),\r
159 strerror(error));\r
160 }\r
161 errno = save;\r
162}\r
163\r
164\r
165static void\r
166Perror(\r
167 FILE *file,\r
168 char *string,\r
169 int error\r
170 )\r
171{\r
172 int save = errno;\r
173\r
174 if (_res.options & RES_DEBUG) {\r
175 fprintf(file, "res_send: %s: %s\n",\r
176 string, strerror(error));\r
177 }\r
178 errno = save;\r
179}\r
180#endif\r
181\r
182void\r
183res_send_setqhook(\r
184 res_send_qhook hook\r
185 )\r
186{\r
187\r
188 Qhook = hook;\r
189}\r
190\r
191void\r
192res_send_setrhook(\r
193 res_send_rhook hook\r
194 )\r
195{\r
196\r
197 Rhook = hook;\r
198}\r
199\r
200/* int\r
201 * res_isourserver(ina)\r
202 * looks up "ina" in _res.ns_addr_list[]\r
203 * returns:\r
204 * 0 : not found\r
205 * >0 : found\r
206 * author:\r
207 * paul vixie, 29may94\r
208 */\r
209int\r
210res_isourserver(\r
211 const struct sockaddr_in *inp\r
212 )\r
213{\r
214 struct sockaddr_in ina;\r
215 int ns, ret;\r
216\r
217 ina = *inp;\r
218 ret = 0;\r
219 for (ns = 0; ns < _res.nscount; ns++) {\r
220 const struct sockaddr_in *srv = &_res.nsaddr_list[ns];\r
221\r
222 if (srv->sin_family == ina.sin_family &&\r
223 srv->sin_port == ina.sin_port &&\r
224 (srv->sin_addr.s_addr == INADDR_ANY ||\r
225 srv->sin_addr.s_addr == ina.sin_addr.s_addr)) {\r
226 ret++;\r
227 break;\r
228 }\r
229 }\r
230 return (ret);\r
231}\r
232\r
233/* int\r
234 * res_nameinquery(name, type, class, buf, eom)\r
235 * look for (name,type,class) in the query section of packet (buf,eom)\r
236 * requires:\r
237 * buf + HFIXEDSZ <= eom\r
238 * returns:\r
239 * -1 : format error\r
240 * 0 : not found\r
241 * >0 : found\r
242 * author:\r
243 * paul vixie, 29may94\r
244 */\r
245int\r
246res_nameinquery(\r
247 const char *name,\r
248 int type,\r
249 int class,\r
250 const u_char *buf,\r
251 const u_char *eom\r
252 )\r
253{\r
254 const u_char *cp = buf + HFIXEDSZ;\r
255 int qdcount = ntohs(((HEADER*)buf)->qdcount);\r
256\r
257 while (qdcount-- > 0) {\r
258 char tname[MAXDNAME+1];\r
259 int n, ttype, tclass;\r
260\r
261 n = dn_expand(buf, eom, cp, tname, sizeof tname);\r
262 if (n < 0)\r
263 return (-1);\r
264 cp += n;\r
265 if (cp + 2 * INT16SZ > eom)\r
266 return (-1);\r
267 ttype = ns_get16(cp); cp += INT16SZ;\r
268 tclass = ns_get16(cp); cp += INT16SZ;\r
269 if (ttype == type &&\r
270 tclass == class &&\r
271 strcasecmp(tname, name) == 0)\r
272 return (1);\r
273 }\r
274 return (0);\r
275}\r
276\r
277/* int\r
278 * res_queriesmatch(buf1, eom1, buf2, eom2)\r
279 * is there a 1:1 mapping of (name,type,class)\r
280 * in (buf1,eom1) and (buf2,eom2)?\r
281 * returns:\r
282 * -1 : format error\r
283 * 0 : not a 1:1 mapping\r
284 * >0 : is a 1:1 mapping\r
285 * author:\r
286 * paul vixie, 29may94\r
287 */\r
288int\r
289res_queriesmatch(\r
290 const u_char *buf1,\r
291 const u_char *eom1,\r
292 const u_char *buf2,\r
293 const u_char *eom2\r
294 )\r
295{\r
296 const u_char *cp = buf1 + HFIXEDSZ;\r
297 int qdcount = ntohs(((HEADER*)buf1)->qdcount);\r
298\r
299 if (buf1 + HFIXEDSZ > eom1 || buf2 + HFIXEDSZ > eom2)\r
300 return (-1);\r
301\r
302 /*\r
303 * Only header section present in replies to\r
304 * dynamic update packets.\r
305 */\r
306 if ( (((HEADER *)buf1)->opcode == ns_o_update) &&\r
307 (((HEADER *)buf2)->opcode == ns_o_update) )\r
308 return (1);\r
309\r
310 if (qdcount != ntohs(((HEADER*)buf2)->qdcount))\r
311 return (0);\r
312 while (qdcount-- > 0) {\r
313 char tname[MAXDNAME+1];\r
314 int n, ttype, tclass;\r
315\r
316 n = dn_expand(buf1, eom1, cp, tname, sizeof tname);\r
317 if (n < 0)\r
318 return (-1);\r
319 cp += n;\r
320 if (cp + 2 * INT16SZ > eom1)\r
321 return (-1);\r
322 ttype = ns_get16(cp); cp += INT16SZ;\r
323 tclass = ns_get16(cp); cp += INT16SZ;\r
324 if (!res_nameinquery(tname, ttype, tclass, buf2, eom2))\r
325 return (0);\r
326 }\r
327 return (1);\r
328}\r
329\r
330int\r
331res_send(\r
332 const u_char *buf,\r
333 int buflen,\r
334 u_char *ans,\r
335 int anssiz\r
336 )\r
337{\r
338 HEADER *hp = (HEADER *) buf;\r
339 HEADER *anhp = (HEADER *) ans;\r
340 int gotsomewhere, connreset, terrno, try, v_circuit, resplen, ns;\r
341 ssize_t n;\r
342 u_int32_t badns; /* XXX NSMAX can't exceed #/bits in this variable */\r
343\r
344 if ((_res.options & RES_INIT) == 0 && res_init() == -1) {\r
345 /* errno should have been set by res_init() in this case. */\r
346 return (-1);\r
347 }\r
348 if (anssiz < HFIXEDSZ) {\r
349 errno = EINVAL;\r
350 return (-1);\r
351 }\r
352 DprintQ((_res.options & RES_DEBUG) || (_res.pfcode & RES_PRF_QUERY),\r
353 (stdout, ";; res_send()\n"), buf, buflen);\r
354 v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;\r
355 gotsomewhere = 0;\r
356 connreset = 0;\r
357 terrno = ETIMEDOUT;\r
358 badns = 0;\r
359\r
360 /*\r
361 * Send request, RETRY times, or until successful\r
362 */\r
363 for (try = 0; try < _res.retry; try++) {\r
364 for (ns = 0; ns < _res.nscount; ns++) {\r
365 struct sockaddr_in *nsap = &_res.nsaddr_list[ns];\r
366 same_ns:\r
367 if (badns & (1 << ns)) {\r
368 res_close();\r
369 goto next_ns;\r
370 }\r
371\r
372 if (Qhook) {\r
373 int done = 0, loops = 0;\r
374\r
375 do {\r
376 res_sendhookact act;\r
377\r
378 act = (*Qhook)(&nsap, &buf, &buflen,\r
379 ans, anssiz, &resplen);\r
380 switch (act) {\r
381 case res_goahead:\r
382 done = 1;\r
383 break;\r
384 case res_nextns:\r
385 res_close();\r
386 goto next_ns;\r
387 case res_done:\r
388 return (resplen);\r
389 case res_modified:\r
390 /* give the hook another try */\r
391 if (++loops < 42) /*doug adams*/\r
392 break;\r
393 /*FALLTHROUGH*/\r
394 case res_error:\r
395 /*FALLTHROUGH*/\r
396 default:\r
397 return (-1);\r
398 }\r
399 } while (!done);\r
400 }\r
401\r
402 Dprint(_res.options & RES_DEBUG,\r
403 (stdout, ";; Querying server (# %d) address = %s\n",\r
404 ns + 1, inet_ntoa(nsap->sin_addr)));\r
405\r
406 if (v_circuit) {\r
407 int truncated;\r
408 struct iovec iov[2];\r
409 u_short len;\r
410 u_char *cp;\r
411\r
412 /*\r
413 * Use virtual circuit;\r
414 * at most one attempt per server.\r
415 */\r
416 try = _res.retry;\r
417 truncated = 0;\r
418 if (s < 0 || !vc || hp->opcode == ns_o_update) {\r
419 if (s >= 0)\r
420 res_close();\r
421\r
422 s = socket(PF_INET, SOCK_STREAM, 0);\r
423 if (s < 0) {\r
424 terrno = errno;\r
425 Perror(stderr, "socket(vc)", errno);\r
426 return (-1);\r
427 }\r
428 errno = 0;\r
429 nsap->sin_len = sizeof ( *nsap );\r
430 if (connect(s, (struct sockaddr *)nsap,\r
431 sizeof *nsap) < 0) {\r
432 terrno = errno;\r
433 Aerror(stderr, "connect/vc",\r
434 errno, *nsap);\r
435 badns |= (1 << ns);\r
436 res_close();\r
437 goto next_ns;\r
438 }\r
439 vc = 1;\r
440 }\r
441 /*\r
442 * Send length & message\r
443 */\r
444 putshort((u_short)buflen, (u_char*)&len);\r
445 iov[0].iov_base = (caddr_t)&len;\r
446 iov[0].iov_len = INT16SZ;\r
447 iov[1].iov_base = (caddr_t)buf;\r
448 iov[1].iov_len = buflen;\r
449 if (writev(s, iov, 2) != (INT16SZ + buflen)) {\r
450 terrno = errno;\r
451 Perror(stderr, "write failed", errno);\r
452 badns |= (1 << ns);\r
453 res_close();\r
454 goto next_ns;\r
455 }\r
456 /*\r
457 * Receive length & response\r
458 */\r
459read_len:\r
460 cp = ans;\r
461 len = INT16SZ;\r
462 while ((n = read(s, (char *)cp, (int)len)) > 0) {\r
463 cp += n;\r
464 len = (u_short)( len - n );\r
465 if (len <= 0)\r
466 break;\r
467 }\r
468 if (n <= 0) {\r
469 terrno = errno;\r
470 Perror(stderr, "read failed", errno);\r
471 res_close();\r
472 /*\r
473 * A long running process might get its TCP\r
474 * connection reset if the remote server was\r
475 * restarted. Requery the server instead of\r
476 * trying a new one. When there is only one\r
477 * server, this means that a query might work\r
478 * instead of failing. We only allow one reset\r
479 * per query to prevent looping.\r
480 */\r
481 if (terrno == ECONNRESET && !connreset) {\r
482 connreset = 1;\r
483 res_close();\r
484 goto same_ns;\r
485 }\r
486 res_close();\r
487 goto next_ns;\r
488 }\r
489 resplen = ns_get16(ans);\r
490 if (resplen > anssiz) {\r
491 Dprint(_res.options & RES_DEBUG,\r
492 (stdout, ";; response truncated\n")\r
493 );\r
494 truncated = 1;\r
495 len = (ushort)anssiz;\r
496 } else\r
497 len = (ushort)resplen;\r
498 if (len < HFIXEDSZ) {\r
499 /*\r
500 * Undersized message.\r
501 */\r
502 Dprint(_res.options & RES_DEBUG,\r
503 (stdout, ";; undersized: %d\n", len));\r
504 terrno = EMSGSIZE;\r
505 badns |= (1 << ns);\r
506 res_close();\r
507 goto next_ns;\r
508 }\r
509 cp = ans;\r
510 while (len != 0 &&\r
511 (n = read(s, (char *)cp, (int)len)) > 0) {\r
512 cp += n;\r
513 len = (u_short)( len - n );\r
514 }\r
515 if (n <= 0) {\r
516 terrno = errno;\r
517 Perror(stderr, "read(vc)", errno);\r
518 res_close();\r
519 goto next_ns;\r
520 }\r
521 if (truncated) {\r
522 /*\r
523 * Flush rest of answer\r
524 * so connection stays in synch.\r
525 */\r
526 anhp->tc = 1;\r
527 len = (ushort)( resplen - anssiz );\r
528 while (len != 0) {\r
529 char junk[PACKETSZ];\r
530\r
531 n = (len > sizeof(junk)\r
532 ? sizeof(junk)\r
533 : len);\r
534 if ((n = read(s, junk, n)) > 0)\r
535 len = (u_short)( len - n );\r
536 else\r
537 break;\r
538 }\r
539 }\r
540 /*\r
541 * The calling applicating has bailed out of\r
542 * a previous call and failed to arrange to have\r
543 * the circuit closed or the server has got\r
544 * itself confused. Anyway drop the packet and\r
545 * wait for the correct one.\r
546 */\r
547 if (hp->id != anhp->id) {\r
548 DprintQ((_res.options & RES_DEBUG) ||\r
549 (_res.pfcode & RES_PRF_REPLY),\r
550 (stdout, ";; old answer (unexpected):\n"),\r
551 ans, (resplen>anssiz)?anssiz:resplen);\r
552 goto read_len;\r
553 }\r
554 } else {\r
555 /*\r
556 * Use datagrams.\r
557 */\r
558#ifndef NOPOLL\r
559 struct pollfd pfd;\r
560 int msec;\r
561#endif\r
562 struct timeval timeout;\r
563 fd_set dsmask, *dsmaskp;\r
564 int dsmasklen;\r
565 struct sockaddr_in from;\r
566 int fromlen;\r
567\r
568 if ((s < 0) || vc) {\r
569 if (vc)\r
570 res_close();\r
571 s = socket(PF_INET, SOCK_DGRAM, 0);\r
572 if (s < 0) {\r
573#ifndef CAN_RECONNECT\r
574 bad_dg_sock:\r
575#endif\r
576 terrno = errno;\r
577 Perror(stderr, "socket(dg)", errno);\r
578 return (-1);\r
579 }\r
580 connected = 0;\r
581 }\r
582#ifndef CANNOT_CONNECT_DGRAM\r
583 /*\r
584 * On a 4.3BSD+ machine (client and server,\r
585 * actually), sending to a nameserver datagram\r
586 * port with no nameserver will cause an\r
587 * ICMP port unreachable message to be returned.\r
588 * If our datagram socket is "connected" to the\r
589 * server, we get an ECONNREFUSED error on the next\r
590 * socket operation, and select returns if the\r
591 * error message is received. We can thus detect\r
592 * the absence of a nameserver without timing out.\r
593 * If we have sent queries to at least two servers,\r
594 * however, we don't want to remain connected,\r
595 * as we wish to receive answers from the first\r
596 * server to respond.\r
597 */\r
598 if (_res.nscount == 1 || (try == 0 && ns == 0)) {\r
599 /*\r
600 * Connect only if we are sure we won't\r
601 * receive a response from another server.\r
602 */\r
603 if (!connected) {\r
604 nsap->sin_len = sizeof ( *nsap );\r
605 if (connect(s, (struct sockaddr *)nsap,\r
606 sizeof *nsap\r
607 ) < 0) {\r
608 Aerror(stderr,\r
609 "connect(dg)",\r
610 errno, *nsap);\r
611 badns |= (1 << ns);\r
612 res_close();\r
613 goto next_ns;\r
614 }\r
615 connected = 1;\r
616 }\r
617 if (send(s, (char*)buf, buflen, 0) != buflen) {\r
618 Perror(stderr, "send", errno);\r
619 badns |= (1 << ns);\r
620 res_close();\r
621 goto next_ns;\r
622 }\r
623 } else {\r
624 /*\r
625 * Disconnect if we want to listen\r
626 * for responses from more than one server.\r
627 */\r
628 if (connected) {\r
629#ifdef CAN_RECONNECT\r
630 struct sockaddr_in no_addr;\r
631\r
632 no_addr.sin_family = AF_INET;\r
633 no_addr.sin_addr.s_addr = INADDR_ANY;\r
634 no_addr.sin_port = 0;\r
635 (void) connect(s,\r
636 (struct sockaddr *)\r
637 &no_addr,\r
638 sizeof no_addr);\r
639#else\r
640 int s1 = socket(PF_INET, SOCK_DGRAM,0);\r
641 if (s1 < 0)\r
642 goto bad_dg_sock;\r
643 (void) dup2(s1, s);\r
644 (void) close(s1);\r
645 Dprint(_res.options & RES_DEBUG,\r
646 (stdout, ";; new DG socket\n"))\r
647#endif /* CAN_RECONNECT */\r
648 connected = 0;\r
649 errno = 0;\r
650 }\r
651#endif /* !CANNOT_CONNECT_DGRAM */\r
652 if (sendto(s, (char*)buf, buflen, 0,\r
653 (struct sockaddr *)nsap,\r
654 sizeof *nsap)\r
655 != buflen) {\r
656 Aerror(stderr, "sendto", errno, *nsap);\r
657 badns |= (1 << ns);\r
658 res_close();\r
659 goto next_ns;\r
660 }\r
661#ifndef CANNOT_CONNECT_DGRAM\r
662 }\r
663#endif /* !CANNOT_CONNECT_DGRAM */\r
664\r
665 /*\r
666 * Wait for reply\r
667 */\r
668#ifndef NOPOLL\r
669 othersyscall:\r
670 if (use_poll) {\r
671 msec = (_res.retrans << try) * 1000;\r
672 if (try > 0)\r
673 msec /= _res.nscount;\r
674 if (msec <= 0)\r
675 msec = 1000;\r
676 } else {\r
677#endif\r
678 timeout.tv_sec = (_res.retrans << try);\r
679 if (try > 0)\r
680 timeout.tv_sec /= _res.nscount;\r
681 if ((long) timeout.tv_sec <= 0)\r
682 timeout.tv_sec = 1;\r
683 timeout.tv_usec = 0;\r
684#ifndef NOPOLL\r
685 }\r
686#endif\r
687 wait:\r
688 if (s < 0) {\r
689 Perror(stderr, "s out-of-bounds", EMFILE);\r
690 res_close();\r
691 goto next_ns;\r
692 }\r
693#ifndef NOPOLL\r
694 if (use_poll) {\r
695 struct sigaction sa, osa;\r
696 int sigsys_installed = 0;\r
697\r
698 pfd.fd = s;\r
699 pfd.events = POLLIN;\r
700 if (use_poll == 1) {\r
701 bzero(&sa, sizeof(sa));\r
702 sa.sa_handler = SIG_IGN;\r
703 if (sigaction(SIGSYS, &sa, &osa) >= 0)\r
704 sigsys_installed = 1;\r
705 }\r
706 n = poll(&pfd, 1, msec);\r
707 if (sigsys_installed == 1) {\r
708 int oerrno = errno;\r
709 sigaction(SIGSYS, &osa, NULL);\r
710 errno = oerrno;\r
711 }\r
712 /* XXX why does nosys() return EINVAL? */\r
713 if (n < 0 && (errno == ENOSYS ||\r
714 errno == EINVAL)) {\r
715 use_poll = 0;\r
716 goto othersyscall;\r
717 } else if (use_poll == 1)\r
718 use_poll = 2;\r
719 if (n < 0) {\r
720 if (errno == EINTR)\r
721 goto wait;\r
722 Perror(stderr, "poll", errno);\r
723 res_close();\r
724 goto next_ns;\r
725 }\r
726 } else {\r
727#endif\r
728 dsmasklen = howmany(s + 1, NFDBITS) *\r
729 sizeof(fd_mask);\r
730 if (dsmasklen > sizeof(fd_set)) {\r
731 dsmaskp = (fd_set *)malloc(dsmasklen);\r
732 if (dsmaskp == NULL) {\r
733 res_close();\r
734 goto next_ns;\r
735 }\r
736 } else\r
737 dsmaskp = &dsmask;\r
738 /* only zero what we need */\r
739 memset((char *)dsmaskp, 0, dsmasklen);\r
740 FD_SET(s, dsmaskp);\r
741 n = select(s + 1, dsmaskp, (fd_set *)NULL,\r
742 (fd_set *)NULL, &timeout);\r
743 if (dsmaskp != &dsmask)\r
744 free(dsmaskp);\r
745 if (n < 0) {\r
746 if (errno == EINTR)\r
747 goto wait;\r
748 Perror(stderr, "select", errno);\r
749 res_close();\r
750 goto next_ns;\r
751 }\r
752#ifndef NOPOLL\r
753 }\r
754#endif\r
755\r
756 if (n == 0) {\r
757 /*\r
758 * timeout\r
759 */\r
760 Dprint(_res.options & RES_DEBUG,\r
761 (stdout, ";; timeout\n"));\r
762 gotsomewhere = 1;\r
763 res_close();\r
764 goto next_ns;\r
765 }\r
766 errno = 0;\r
767 fromlen = sizeof(struct sockaddr_in);\r
768 resplen = (int)recvfrom(s, (char*)ans, anssiz, 0,\r
a88c3163 769 (struct sockaddr *)&from, (socklen_t *)&fromlen);\r
d7ce7006 770 if (resplen <= 0) {\r
771 Perror(stderr, "recvfrom", errno);\r
772 res_close();\r
773 goto next_ns;\r
774 }\r
775 gotsomewhere = 1;\r
776 if (resplen < HFIXEDSZ) {\r
777 /*\r
778 * Undersized message.\r
779 */\r
780 Dprint(_res.options & RES_DEBUG,\r
781 (stdout, ";; undersized: %d\n",\r
782 resplen));\r
783 terrno = EMSGSIZE;\r
784 badns |= (1 << ns);\r
785 res_close();\r
786 goto next_ns;\r
787 }\r
788 if (hp->id != anhp->id) {\r
789 /*\r
790 * response from old query, ignore it.\r
791 * XXX - potential security hazard could\r
792 * be detected here.\r
793 */\r
794 DprintQ((_res.options & RES_DEBUG) ||\r
795 (_res.pfcode & RES_PRF_REPLY),\r
796 (stdout, ";; old answer:\n"),\r
797 ans, (resplen>anssiz)?anssiz:resplen);\r
798 goto wait;\r
799 }\r
800#ifdef CHECK_SRVR_ADDR\r
801 if (!(_res.options & RES_INSECURE1) &&\r
802 !res_isourserver(&from)) {\r
803 /*\r
804 * response from wrong server? ignore it.\r
805 * XXX - potential security hazard could\r
806 * be detected here.\r
807 */\r
808 DprintQ((_res.options & RES_DEBUG) ||\r
809 (_res.pfcode & RES_PRF_REPLY),\r
810 (stdout, ";; not our server:\n"),\r
811 ans, (resplen>anssiz)?anssiz:resplen);\r
812 goto wait;\r
813 }\r
814#endif\r
815 if (!(_res.options & RES_INSECURE2) &&\r
816 !res_queriesmatch(buf, buf + buflen,\r
817 ans, ans + anssiz)) {\r
818 /*\r
819 * response contains wrong query? ignore it.\r
820 * XXX - potential security hazard could\r
821 * be detected here.\r
822 */\r
823 DprintQ((_res.options & RES_DEBUG) ||\r
824 (_res.pfcode & RES_PRF_REPLY),\r
825 (stdout, ";; wrong query name:\n"),\r
826 ans, (resplen>anssiz)?anssiz:resplen);\r
827 goto wait;\r
828 }\r
829 if (anhp->rcode == SERVFAIL ||\r
830 anhp->rcode == NOTIMP ||\r
831 anhp->rcode == REFUSED) {\r
832 DprintQ(_res.options & RES_DEBUG,\r
833 (stdout, "server rejected query:\n"),\r
834 ans, (resplen>anssiz)?anssiz:resplen);\r
835 badns |= (1 << ns);\r
836 res_close();\r
837 /* don't retry if called from dig */\r
838 if (!_res.pfcode)\r
839 goto next_ns;\r
840 }\r
841 if (!(_res.options & RES_IGNTC) && anhp->tc) {\r
842 /*\r
843 * get rest of answer;\r
844 * use TCP with same server.\r
845 */\r
846 Dprint(_res.options & RES_DEBUG,\r
847 (stdout, ";; truncated answer\n"));\r
848 v_circuit = 1;\r
849 res_close();\r
850 goto same_ns;\r
851 }\r
852 } /*if vc/dg*/\r
853 Dprint((_res.options & RES_DEBUG) ||\r
854 ((_res.pfcode & RES_PRF_REPLY) &&\r
855 (_res.pfcode & RES_PRF_HEAD1)),\r
856 (stdout, ";; got answer:\n"));\r
7700f0f5 857 if((_res.options & RES_DEBUG) ||\r
858 (_res.pfcode & RES_PRF_REPLY)) {\r
859 __fp_nquery(ans, (resplen>anssiz)?anssiz:resplen, stdout);\r
860 }\r
d7ce7006 861 /*\r
862 * If using virtual circuits, we assume that the first server\r
863 * is preferred over the rest (i.e. it is on the local\r
864 * machine) and only keep that one open.\r
865 * If we have temporarily opened a virtual circuit,\r
866 * or if we haven't been asked to keep a socket open,\r
867 * close the socket.\r
868 */\r
869 if ((v_circuit && (!(_res.options & RES_USEVC) || ns != 0)) ||\r
870 !(_res.options & RES_STAYOPEN)) {\r
871 res_close();\r
872 }\r
873 if (Rhook) {\r
874 int done = 0, loops = 0;\r
875\r
876 do {\r
877 res_sendhookact act;\r
878\r
879 act = (*Rhook)(nsap, buf, buflen,\r
880 ans, anssiz, &resplen);\r
881 switch (act) {\r
882 case res_goahead:\r
883 case res_done:\r
884 done = 1;\r
885 break;\r
886 case res_nextns:\r
887 res_close();\r
888 goto next_ns;\r
889 case res_modified:\r
890 /* give the hook another try */\r
891 if (++loops < 42) /*doug adams*/\r
892 break;\r
893 /*FALLTHROUGH*/\r
894 case res_error:\r
895 /*FALLTHROUGH*/\r
896 default:\r
897 return (-1);\r
898 }\r
899 } while (!done);\r
900\r
901 }\r
902 return (resplen);\r
903 next_ns: ;\r
904 } /*foreach ns*/\r
905 } /*foreach retry*/\r
906 res_close();\r
907 if (!v_circuit) {\r
908 if (!gotsomewhere)\r
909 errno = ECONNREFUSED; /* no nameservers found */\r
910 else\r
911 errno = ETIMEDOUT; /* no answer obtained */\r
912 } else\r
913 errno = terrno;\r
914 return (-1);\r
915}\r
916\r
917/*\r
918 * This routine is for closing the socket if a virtual circuit is used and\r
919 * the program wants to close it. This provides support for endhostent()\r
920 * which expects to close the socket.\r
921 *\r
922 * This routine is not expected to be user visible.\r
923 */\r
924void\r
925res_close()\r
926{\r
927 if (s >= 0) {\r
928 (void) close(s);\r
929 s = -1;\r
930 connected = 0;\r
931 vc = 0;\r
932 }\r
933}\r