]> git.proxmox.com Git - mirror_edk2.git/blame - StdLib/BsdSocketLib/res_send.c
Fix send to properly wait while long transmits are in progress
[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
117static int use_poll = 0;\r
118#else\r
119#include <poll.h>\r
120static int use_poll = 1; /* adapt to poll() syscall availability */\r
121 /* 0 = not present, 1 = try it, 2 = exists */\r
122#endif\r
123\r
124static int s = -1; /* socket used for communications */\r
125static int connected = 0; /* is the socket connected */\r
126static int vc = 0; /* is the socket a virtual circuit? */\r
127static res_send_qhook Qhook = NULL;\r
128static res_send_rhook Rhook = NULL;\r
129\r
130\r
131#define CAN_RECONNECT 1\r
132\r
133#ifndef DEBUG\r
134# define Dprint(cond, args) /*empty*/\r
135# define DprintQ(cond, args, query, size) /*empty*/\r
136# define Aerror(file, string, error, address) /*empty*/\r
137# define Perror(file, string, error) /*empty*/\r
138#else\r
139# define Dprint(cond, args) if (cond) {fprintf args;} else {}\r
140# define DprintQ(cond, args, query, size) if (cond) {\\r
141 fprintf args;\\r
142 __fp_nquery(query, size, stdout);\\r
143 } else {}\r
144\r
145static void\r
146Aerror(\r
147 FILE *file,\r
148 char *string,\r
149 int error,\r
150 struct sockaddr_in address\r
151 )\r
152{\r
153 int save = errno;\r
154\r
155 if (_res.options & RES_DEBUG) {\r
156 fprintf(file, "res_send: %s ([%s].%u): %s\n",\r
157 string,\r
158 inet_ntoa(address.sin_addr),\r
159 ntohs(address.sin_port),\r
160 strerror(error));\r
161 }\r
162 errno = save;\r
163}\r
164\r
165\r
166static void\r
167Perror(\r
168 FILE *file,\r
169 char *string,\r
170 int error\r
171 )\r
172{\r
173 int save = errno;\r
174\r
175 if (_res.options & RES_DEBUG) {\r
176 fprintf(file, "res_send: %s: %s\n",\r
177 string, strerror(error));\r
178 }\r
179 errno = save;\r
180}\r
181#endif\r
182\r
183void\r
184res_send_setqhook(\r
185 res_send_qhook hook\r
186 )\r
187{\r
188\r
189 Qhook = hook;\r
190}\r
191\r
192void\r
193res_send_setrhook(\r
194 res_send_rhook hook\r
195 )\r
196{\r
197\r
198 Rhook = hook;\r
199}\r
200\r
201/* int\r
202 * res_isourserver(ina)\r
203 * looks up "ina" in _res.ns_addr_list[]\r
204 * returns:\r
205 * 0 : not found\r
206 * >0 : found\r
207 * author:\r
208 * paul vixie, 29may94\r
209 */\r
210int\r
211res_isourserver(\r
212 const struct sockaddr_in *inp\r
213 )\r
214{\r
215 struct sockaddr_in ina;\r
216 int ns, ret;\r
217\r
218 ina = *inp;\r
219 ret = 0;\r
220 for (ns = 0; ns < _res.nscount; ns++) {\r
221 const struct sockaddr_in *srv = &_res.nsaddr_list[ns];\r
222\r
223 if (srv->sin_family == ina.sin_family &&\r
224 srv->sin_port == ina.sin_port &&\r
225 (srv->sin_addr.s_addr == INADDR_ANY ||\r
226 srv->sin_addr.s_addr == ina.sin_addr.s_addr)) {\r
227 ret++;\r
228 break;\r
229 }\r
230 }\r
231 return (ret);\r
232}\r
233\r
234/* int\r
235 * res_nameinquery(name, type, class, buf, eom)\r
236 * look for (name,type,class) in the query section of packet (buf,eom)\r
237 * requires:\r
238 * buf + HFIXEDSZ <= eom\r
239 * returns:\r
240 * -1 : format error\r
241 * 0 : not found\r
242 * >0 : found\r
243 * author:\r
244 * paul vixie, 29may94\r
245 */\r
246int\r
247res_nameinquery(\r
248 const char *name,\r
249 int type,\r
250 int class,\r
251 const u_char *buf,\r
252 const u_char *eom\r
253 )\r
254{\r
255 const u_char *cp = buf + HFIXEDSZ;\r
256 int qdcount = ntohs(((HEADER*)buf)->qdcount);\r
257\r
258 while (qdcount-- > 0) {\r
259 char tname[MAXDNAME+1];\r
260 int n, ttype, tclass;\r
261\r
262 n = dn_expand(buf, eom, cp, tname, sizeof tname);\r
263 if (n < 0)\r
264 return (-1);\r
265 cp += n;\r
266 if (cp + 2 * INT16SZ > eom)\r
267 return (-1);\r
268 ttype = ns_get16(cp); cp += INT16SZ;\r
269 tclass = ns_get16(cp); cp += INT16SZ;\r
270 if (ttype == type &&\r
271 tclass == class &&\r
272 strcasecmp(tname, name) == 0)\r
273 return (1);\r
274 }\r
275 return (0);\r
276}\r
277\r
278/* int\r
279 * res_queriesmatch(buf1, eom1, buf2, eom2)\r
280 * is there a 1:1 mapping of (name,type,class)\r
281 * in (buf1,eom1) and (buf2,eom2)?\r
282 * returns:\r
283 * -1 : format error\r
284 * 0 : not a 1:1 mapping\r
285 * >0 : is a 1:1 mapping\r
286 * author:\r
287 * paul vixie, 29may94\r
288 */\r
289int\r
290res_queriesmatch(\r
291 const u_char *buf1,\r
292 const u_char *eom1,\r
293 const u_char *buf2,\r
294 const u_char *eom2\r
295 )\r
296{\r
297 const u_char *cp = buf1 + HFIXEDSZ;\r
298 int qdcount = ntohs(((HEADER*)buf1)->qdcount);\r
299\r
300 if (buf1 + HFIXEDSZ > eom1 || buf2 + HFIXEDSZ > eom2)\r
301 return (-1);\r
302\r
303 /*\r
304 * Only header section present in replies to\r
305 * dynamic update packets.\r
306 */\r
307 if ( (((HEADER *)buf1)->opcode == ns_o_update) &&\r
308 (((HEADER *)buf2)->opcode == ns_o_update) )\r
309 return (1);\r
310\r
311 if (qdcount != ntohs(((HEADER*)buf2)->qdcount))\r
312 return (0);\r
313 while (qdcount-- > 0) {\r
314 char tname[MAXDNAME+1];\r
315 int n, ttype, tclass;\r
316\r
317 n = dn_expand(buf1, eom1, cp, tname, sizeof tname);\r
318 if (n < 0)\r
319 return (-1);\r
320 cp += n;\r
321 if (cp + 2 * INT16SZ > eom1)\r
322 return (-1);\r
323 ttype = ns_get16(cp); cp += INT16SZ;\r
324 tclass = ns_get16(cp); cp += INT16SZ;\r
325 if (!res_nameinquery(tname, ttype, tclass, buf2, eom2))\r
326 return (0);\r
327 }\r
328 return (1);\r
329}\r
330\r
331int\r
332res_send(\r
333 const u_char *buf,\r
334 int buflen,\r
335 u_char *ans,\r
336 int anssiz\r
337 )\r
338{\r
339 HEADER *hp = (HEADER *) buf;\r
340 HEADER *anhp = (HEADER *) ans;\r
341 int gotsomewhere, connreset, terrno, try, v_circuit, resplen, ns;\r
342 ssize_t n;\r
343 u_int32_t badns; /* XXX NSMAX can't exceed #/bits in this variable */\r
344\r
345 if ((_res.options & RES_INIT) == 0 && res_init() == -1) {\r
346 /* errno should have been set by res_init() in this case. */\r
347 return (-1);\r
348 }\r
349 if (anssiz < HFIXEDSZ) {\r
350 errno = EINVAL;\r
351 return (-1);\r
352 }\r
353 DprintQ((_res.options & RES_DEBUG) || (_res.pfcode & RES_PRF_QUERY),\r
354 (stdout, ";; res_send()\n"), buf, buflen);\r
355 v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;\r
356 gotsomewhere = 0;\r
357 connreset = 0;\r
358 terrno = ETIMEDOUT;\r
359 badns = 0;\r
360\r
361 /*\r
362 * Send request, RETRY times, or until successful\r
363 */\r
364 for (try = 0; try < _res.retry; try++) {\r
365 for (ns = 0; ns < _res.nscount; ns++) {\r
366 struct sockaddr_in *nsap = &_res.nsaddr_list[ns];\r
367 same_ns:\r
368 if (badns & (1 << ns)) {\r
369 res_close();\r
370 goto next_ns;\r
371 }\r
372\r
373 if (Qhook) {\r
374 int done = 0, loops = 0;\r
375\r
376 do {\r
377 res_sendhookact act;\r
378\r
379 act = (*Qhook)(&nsap, &buf, &buflen,\r
380 ans, anssiz, &resplen);\r
381 switch (act) {\r
382 case res_goahead:\r
383 done = 1;\r
384 break;\r
385 case res_nextns:\r
386 res_close();\r
387 goto next_ns;\r
388 case res_done:\r
389 return (resplen);\r
390 case res_modified:\r
391 /* give the hook another try */\r
392 if (++loops < 42) /*doug adams*/\r
393 break;\r
394 /*FALLTHROUGH*/\r
395 case res_error:\r
396 /*FALLTHROUGH*/\r
397 default:\r
398 return (-1);\r
399 }\r
400 } while (!done);\r
401 }\r
402\r
403 Dprint(_res.options & RES_DEBUG,\r
404 (stdout, ";; Querying server (# %d) address = %s\n",\r
405 ns + 1, inet_ntoa(nsap->sin_addr)));\r
406\r
407 if (v_circuit) {\r
408 int truncated;\r
409 struct iovec iov[2];\r
410 u_short len;\r
411 u_char *cp;\r
412\r
413 /*\r
414 * Use virtual circuit;\r
415 * at most one attempt per server.\r
416 */\r
417 try = _res.retry;\r
418 truncated = 0;\r
419 if (s < 0 || !vc || hp->opcode == ns_o_update) {\r
420 if (s >= 0)\r
421 res_close();\r
422\r
423 s = socket(PF_INET, SOCK_STREAM, 0);\r
424 if (s < 0) {\r
425 terrno = errno;\r
426 Perror(stderr, "socket(vc)", errno);\r
427 return (-1);\r
428 }\r
429 errno = 0;\r
430 nsap->sin_len = sizeof ( *nsap );\r
431 if (connect(s, (struct sockaddr *)nsap,\r
432 sizeof *nsap) < 0) {\r
433 terrno = errno;\r
434 Aerror(stderr, "connect/vc",\r
435 errno, *nsap);\r
436 badns |= (1 << ns);\r
437 res_close();\r
438 goto next_ns;\r
439 }\r
440 vc = 1;\r
441 }\r
442 /*\r
443 * Send length & message\r
444 */\r
445 putshort((u_short)buflen, (u_char*)&len);\r
446 iov[0].iov_base = (caddr_t)&len;\r
447 iov[0].iov_len = INT16SZ;\r
448 iov[1].iov_base = (caddr_t)buf;\r
449 iov[1].iov_len = buflen;\r
450 if (writev(s, iov, 2) != (INT16SZ + buflen)) {\r
451 terrno = errno;\r
452 Perror(stderr, "write failed", errno);\r
453 badns |= (1 << ns);\r
454 res_close();\r
455 goto next_ns;\r
456 }\r
457 /*\r
458 * Receive length & response\r
459 */\r
460read_len:\r
461 cp = ans;\r
462 len = INT16SZ;\r
463 while ((n = read(s, (char *)cp, (int)len)) > 0) {\r
464 cp += n;\r
465 len = (u_short)( len - n );\r
466 if (len <= 0)\r
467 break;\r
468 }\r
469 if (n <= 0) {\r
470 terrno = errno;\r
471 Perror(stderr, "read failed", errno);\r
472 res_close();\r
473 /*\r
474 * A long running process might get its TCP\r
475 * connection reset if the remote server was\r
476 * restarted. Requery the server instead of\r
477 * trying a new one. When there is only one\r
478 * server, this means that a query might work\r
479 * instead of failing. We only allow one reset\r
480 * per query to prevent looping.\r
481 */\r
482 if (terrno == ECONNRESET && !connreset) {\r
483 connreset = 1;\r
484 res_close();\r
485 goto same_ns;\r
486 }\r
487 res_close();\r
488 goto next_ns;\r
489 }\r
490 resplen = ns_get16(ans);\r
491 if (resplen > anssiz) {\r
492 Dprint(_res.options & RES_DEBUG,\r
493 (stdout, ";; response truncated\n")\r
494 );\r
495 truncated = 1;\r
496 len = (ushort)anssiz;\r
497 } else\r
498 len = (ushort)resplen;\r
499 if (len < HFIXEDSZ) {\r
500 /*\r
501 * Undersized message.\r
502 */\r
503 Dprint(_res.options & RES_DEBUG,\r
504 (stdout, ";; undersized: %d\n", len));\r
505 terrno = EMSGSIZE;\r
506 badns |= (1 << ns);\r
507 res_close();\r
508 goto next_ns;\r
509 }\r
510 cp = ans;\r
511 while (len != 0 &&\r
512 (n = read(s, (char *)cp, (int)len)) > 0) {\r
513 cp += n;\r
514 len = (u_short)( len - n );\r
515 }\r
516 if (n <= 0) {\r
517 terrno = errno;\r
518 Perror(stderr, "read(vc)", errno);\r
519 res_close();\r
520 goto next_ns;\r
521 }\r
522 if (truncated) {\r
523 /*\r
524 * Flush rest of answer\r
525 * so connection stays in synch.\r
526 */\r
527 anhp->tc = 1;\r
528 len = (ushort)( resplen - anssiz );\r
529 while (len != 0) {\r
530 char junk[PACKETSZ];\r
531\r
532 n = (len > sizeof(junk)\r
533 ? sizeof(junk)\r
534 : len);\r
535 if ((n = read(s, junk, n)) > 0)\r
536 len = (u_short)( len - n );\r
537 else\r
538 break;\r
539 }\r
540 }\r
541 /*\r
542 * The calling applicating has bailed out of\r
543 * a previous call and failed to arrange to have\r
544 * the circuit closed or the server has got\r
545 * itself confused. Anyway drop the packet and\r
546 * wait for the correct one.\r
547 */\r
548 if (hp->id != anhp->id) {\r
549 DprintQ((_res.options & RES_DEBUG) ||\r
550 (_res.pfcode & RES_PRF_REPLY),\r
551 (stdout, ";; old answer (unexpected):\n"),\r
552 ans, (resplen>anssiz)?anssiz:resplen);\r
553 goto read_len;\r
554 }\r
555 } else {\r
556 /*\r
557 * Use datagrams.\r
558 */\r
559#ifndef NOPOLL\r
560 struct pollfd pfd;\r
561 int msec;\r
562#endif\r
563 struct timeval timeout;\r
564 fd_set dsmask, *dsmaskp;\r
565 int dsmasklen;\r
566 struct sockaddr_in from;\r
567 int fromlen;\r
568\r
569 if ((s < 0) || vc) {\r
570 if (vc)\r
571 res_close();\r
572 s = socket(PF_INET, SOCK_DGRAM, 0);\r
573 if (s < 0) {\r
574#ifndef CAN_RECONNECT\r
575 bad_dg_sock:\r
576#endif\r
577 terrno = errno;\r
578 Perror(stderr, "socket(dg)", errno);\r
579 return (-1);\r
580 }\r
581 connected = 0;\r
582 }\r
583#ifndef CANNOT_CONNECT_DGRAM\r
584 /*\r
585 * On a 4.3BSD+ machine (client and server,\r
586 * actually), sending to a nameserver datagram\r
587 * port with no nameserver will cause an\r
588 * ICMP port unreachable message to be returned.\r
589 * If our datagram socket is "connected" to the\r
590 * server, we get an ECONNREFUSED error on the next\r
591 * socket operation, and select returns if the\r
592 * error message is received. We can thus detect\r
593 * the absence of a nameserver without timing out.\r
594 * If we have sent queries to at least two servers,\r
595 * however, we don't want to remain connected,\r
596 * as we wish to receive answers from the first\r
597 * server to respond.\r
598 */\r
599 if (_res.nscount == 1 || (try == 0 && ns == 0)) {\r
600 /*\r
601 * Connect only if we are sure we won't\r
602 * receive a response from another server.\r
603 */\r
604 if (!connected) {\r
605 nsap->sin_len = sizeof ( *nsap );\r
606 if (connect(s, (struct sockaddr *)nsap,\r
607 sizeof *nsap\r
608 ) < 0) {\r
609 Aerror(stderr,\r
610 "connect(dg)",\r
611 errno, *nsap);\r
612 badns |= (1 << ns);\r
613 res_close();\r
614 goto next_ns;\r
615 }\r
616 connected = 1;\r
617 }\r
618 if (send(s, (char*)buf, buflen, 0) != buflen) {\r
619 Perror(stderr, "send", errno);\r
620 badns |= (1 << ns);\r
621 res_close();\r
622 goto next_ns;\r
623 }\r
624 } else {\r
625 /*\r
626 * Disconnect if we want to listen\r
627 * for responses from more than one server.\r
628 */\r
629 if (connected) {\r
630#ifdef CAN_RECONNECT\r
631 struct sockaddr_in no_addr;\r
632\r
633 no_addr.sin_family = AF_INET;\r
634 no_addr.sin_addr.s_addr = INADDR_ANY;\r
635 no_addr.sin_port = 0;\r
636 (void) connect(s,\r
637 (struct sockaddr *)\r
638 &no_addr,\r
639 sizeof no_addr);\r
640#else\r
641 int s1 = socket(PF_INET, SOCK_DGRAM,0);\r
642 if (s1 < 0)\r
643 goto bad_dg_sock;\r
644 (void) dup2(s1, s);\r
645 (void) close(s1);\r
646 Dprint(_res.options & RES_DEBUG,\r
647 (stdout, ";; new DG socket\n"))\r
648#endif /* CAN_RECONNECT */\r
649 connected = 0;\r
650 errno = 0;\r
651 }\r
652#endif /* !CANNOT_CONNECT_DGRAM */\r
653 if (sendto(s, (char*)buf, buflen, 0,\r
654 (struct sockaddr *)nsap,\r
655 sizeof *nsap)\r
656 != buflen) {\r
657 Aerror(stderr, "sendto", errno, *nsap);\r
658 badns |= (1 << ns);\r
659 res_close();\r
660 goto next_ns;\r
661 }\r
662#ifndef CANNOT_CONNECT_DGRAM\r
663 }\r
664#endif /* !CANNOT_CONNECT_DGRAM */\r
665\r
666 /*\r
667 * Wait for reply\r
668 */\r
669#ifndef NOPOLL\r
670 othersyscall:\r
671 if (use_poll) {\r
672 msec = (_res.retrans << try) * 1000;\r
673 if (try > 0)\r
674 msec /= _res.nscount;\r
675 if (msec <= 0)\r
676 msec = 1000;\r
677 } else {\r
678#endif\r
679 timeout.tv_sec = (_res.retrans << try);\r
680 if (try > 0)\r
681 timeout.tv_sec /= _res.nscount;\r
682 if ((long) timeout.tv_sec <= 0)\r
683 timeout.tv_sec = 1;\r
684 timeout.tv_usec = 0;\r
685#ifndef NOPOLL\r
686 }\r
687#endif\r
688 wait:\r
689 if (s < 0) {\r
690 Perror(stderr, "s out-of-bounds", EMFILE);\r
691 res_close();\r
692 goto next_ns;\r
693 }\r
694#ifndef NOPOLL\r
695 if (use_poll) {\r
696 struct sigaction sa, osa;\r
697 int sigsys_installed = 0;\r
698\r
699 pfd.fd = s;\r
700 pfd.events = POLLIN;\r
701 if (use_poll == 1) {\r
702 bzero(&sa, sizeof(sa));\r
703 sa.sa_handler = SIG_IGN;\r
704 if (sigaction(SIGSYS, &sa, &osa) >= 0)\r
705 sigsys_installed = 1;\r
706 }\r
707 n = poll(&pfd, 1, msec);\r
708 if (sigsys_installed == 1) {\r
709 int oerrno = errno;\r
710 sigaction(SIGSYS, &osa, NULL);\r
711 errno = oerrno;\r
712 }\r
713 /* XXX why does nosys() return EINVAL? */\r
714 if (n < 0 && (errno == ENOSYS ||\r
715 errno == EINVAL)) {\r
716 use_poll = 0;\r
717 goto othersyscall;\r
718 } else if (use_poll == 1)\r
719 use_poll = 2;\r
720 if (n < 0) {\r
721 if (errno == EINTR)\r
722 goto wait;\r
723 Perror(stderr, "poll", errno);\r
724 res_close();\r
725 goto next_ns;\r
726 }\r
727 } else {\r
728#endif\r
729 dsmasklen = howmany(s + 1, NFDBITS) *\r
730 sizeof(fd_mask);\r
731 if (dsmasklen > sizeof(fd_set)) {\r
732 dsmaskp = (fd_set *)malloc(dsmasklen);\r
733 if (dsmaskp == NULL) {\r
734 res_close();\r
735 goto next_ns;\r
736 }\r
737 } else\r
738 dsmaskp = &dsmask;\r
739 /* only zero what we need */\r
740 memset((char *)dsmaskp, 0, dsmasklen);\r
741 FD_SET(s, dsmaskp);\r
742 n = select(s + 1, dsmaskp, (fd_set *)NULL,\r
743 (fd_set *)NULL, &timeout);\r
744 if (dsmaskp != &dsmask)\r
745 free(dsmaskp);\r
746 if (n < 0) {\r
747 if (errno == EINTR)\r
748 goto wait;\r
749 Perror(stderr, "select", errno);\r
750 res_close();\r
751 goto next_ns;\r
752 }\r
753#ifndef NOPOLL\r
754 }\r
755#endif\r
756\r
757 if (n == 0) {\r
758 /*\r
759 * timeout\r
760 */\r
761 Dprint(_res.options & RES_DEBUG,\r
762 (stdout, ";; timeout\n"));\r
763 gotsomewhere = 1;\r
764 res_close();\r
765 goto next_ns;\r
766 }\r
767 errno = 0;\r
768 fromlen = sizeof(struct sockaddr_in);\r
769 resplen = (int)recvfrom(s, (char*)ans, anssiz, 0,\r
770 (struct sockaddr *)&from, &fromlen);\r
771 if (resplen <= 0) {\r
772 Perror(stderr, "recvfrom", errno);\r
773 res_close();\r
774 goto next_ns;\r
775 }\r
776 gotsomewhere = 1;\r
777 if (resplen < HFIXEDSZ) {\r
778 /*\r
779 * Undersized message.\r
780 */\r
781 Dprint(_res.options & RES_DEBUG,\r
782 (stdout, ";; undersized: %d\n",\r
783 resplen));\r
784 terrno = EMSGSIZE;\r
785 badns |= (1 << ns);\r
786 res_close();\r
787 goto next_ns;\r
788 }\r
789 if (hp->id != anhp->id) {\r
790 /*\r
791 * response from old query, ignore it.\r
792 * XXX - potential security hazard could\r
793 * be detected here.\r
794 */\r
795 DprintQ((_res.options & RES_DEBUG) ||\r
796 (_res.pfcode & RES_PRF_REPLY),\r
797 (stdout, ";; old answer:\n"),\r
798 ans, (resplen>anssiz)?anssiz:resplen);\r
799 goto wait;\r
800 }\r
801#ifdef CHECK_SRVR_ADDR\r
802 if (!(_res.options & RES_INSECURE1) &&\r
803 !res_isourserver(&from)) {\r
804 /*\r
805 * response from wrong server? ignore it.\r
806 * XXX - potential security hazard could\r
807 * be detected here.\r
808 */\r
809 DprintQ((_res.options & RES_DEBUG) ||\r
810 (_res.pfcode & RES_PRF_REPLY),\r
811 (stdout, ";; not our server:\n"),\r
812 ans, (resplen>anssiz)?anssiz:resplen);\r
813 goto wait;\r
814 }\r
815#endif\r
816 if (!(_res.options & RES_INSECURE2) &&\r
817 !res_queriesmatch(buf, buf + buflen,\r
818 ans, ans + anssiz)) {\r
819 /*\r
820 * response contains wrong query? ignore it.\r
821 * XXX - potential security hazard could\r
822 * be detected here.\r
823 */\r
824 DprintQ((_res.options & RES_DEBUG) ||\r
825 (_res.pfcode & RES_PRF_REPLY),\r
826 (stdout, ";; wrong query name:\n"),\r
827 ans, (resplen>anssiz)?anssiz:resplen);\r
828 goto wait;\r
829 }\r
830 if (anhp->rcode == SERVFAIL ||\r
831 anhp->rcode == NOTIMP ||\r
832 anhp->rcode == REFUSED) {\r
833 DprintQ(_res.options & RES_DEBUG,\r
834 (stdout, "server rejected query:\n"),\r
835 ans, (resplen>anssiz)?anssiz:resplen);\r
836 badns |= (1 << ns);\r
837 res_close();\r
838 /* don't retry if called from dig */\r
839 if (!_res.pfcode)\r
840 goto next_ns;\r
841 }\r
842 if (!(_res.options & RES_IGNTC) && anhp->tc) {\r
843 /*\r
844 * get rest of answer;\r
845 * use TCP with same server.\r
846 */\r
847 Dprint(_res.options & RES_DEBUG,\r
848 (stdout, ";; truncated answer\n"));\r
849 v_circuit = 1;\r
850 res_close();\r
851 goto same_ns;\r
852 }\r
853 } /*if vc/dg*/\r
854 Dprint((_res.options & RES_DEBUG) ||\r
855 ((_res.pfcode & RES_PRF_REPLY) &&\r
856 (_res.pfcode & RES_PRF_HEAD1)),\r
857 (stdout, ";; got answer:\n"));\r
858 DprintQ((_res.options & RES_DEBUG) ||\r
859 (_res.pfcode & RES_PRF_REPLY),\r
860 (stdout, ""),\r
861 ans, (resplen>anssiz)?anssiz:resplen);\r
862 /*\r
863 * If using virtual circuits, we assume that the first server\r
864 * is preferred over the rest (i.e. it is on the local\r
865 * machine) and only keep that one open.\r
866 * If we have temporarily opened a virtual circuit,\r
867 * or if we haven't been asked to keep a socket open,\r
868 * close the socket.\r
869 */\r
870 if ((v_circuit && (!(_res.options & RES_USEVC) || ns != 0)) ||\r
871 !(_res.options & RES_STAYOPEN)) {\r
872 res_close();\r
873 }\r
874 if (Rhook) {\r
875 int done = 0, loops = 0;\r
876\r
877 do {\r
878 res_sendhookact act;\r
879\r
880 act = (*Rhook)(nsap, buf, buflen,\r
881 ans, anssiz, &resplen);\r
882 switch (act) {\r
883 case res_goahead:\r
884 case res_done:\r
885 done = 1;\r
886 break;\r
887 case res_nextns:\r
888 res_close();\r
889 goto next_ns;\r
890 case res_modified:\r
891 /* give the hook another try */\r
892 if (++loops < 42) /*doug adams*/\r
893 break;\r
894 /*FALLTHROUGH*/\r
895 case res_error:\r
896 /*FALLTHROUGH*/\r
897 default:\r
898 return (-1);\r
899 }\r
900 } while (!done);\r
901\r
902 }\r
903 return (resplen);\r
904 next_ns: ;\r
905 } /*foreach ns*/\r
906 } /*foreach retry*/\r
907 res_close();\r
908 if (!v_circuit) {\r
909 if (!gotsomewhere)\r
910 errno = ECONNREFUSED; /* no nameservers found */\r
911 else\r
912 errno = ETIMEDOUT; /* no answer obtained */\r
913 } else\r
914 errno = terrno;\r
915 return (-1);\r
916}\r
917\r
918/*\r
919 * This routine is for closing the socket if a virtual circuit is used and\r
920 * the program wants to close it. This provides support for endhostent()\r
921 * which expects to close the socket.\r
922 *\r
923 * This routine is not expected to be user visible.\r
924 */\r
925void\r
926res_close()\r
927{\r
928 if (s >= 0) {\r
929 (void) close(s);\r
930 s = -1;\r
931 connected = 0;\r
932 vc = 0;\r
933 }\r
934}\r