Include <signal.h> in sysdeps/nptl/allocrtsig.c
[platform/upstream/glibc.git] / resolv / res_init.c
1 /*
2  * Copyright (c) 1985, 1989, 1993
3  *    The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 4. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 /*
31  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
32  *
33  * Permission to use, copy, modify, and distribute this software for any
34  * purpose with or without fee is hereby granted, provided that the above
35  * copyright notice and this permission notice appear in all copies, and that
36  * the name of Digital Equipment Corporation not be used in advertising or
37  * publicity pertaining to distribution of the document or software without
38  * specific, written prior permission.
39  *
40  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
41  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
42  * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
43  * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
44  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
45  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
46  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
47  * SOFTWARE.
48  */
49
50 /*
51  * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
52  *
53  * Permission to use, copy, modify, and distribute this software for any
54  * purpose with or without fee is hereby granted, provided that the above
55  * copyright notice and this permission notice appear in all copies.
56  *
57  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
58  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
59  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
60  * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
61  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
62  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
63  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
64  * SOFTWARE.
65  */
66
67 #if defined(LIBC_SCCS) && !defined(lint)
68 static const char sccsid[] = "@(#)res_init.c    8.1 (Berkeley) 6/7/93";
69 static const char rcsid[] = "$BINDId: res_init.c,v 8.16 2000/05/09 07:10:12 vixie Exp $";
70 #endif /* LIBC_SCCS and not lint */
71
72 #include <ctype.h>
73 #include <netdb.h>
74 #include <resolv.h>
75 #include <stdio.h>
76 #include <stdio_ext.h>
77 #include <stdlib.h>
78 #include <string.h>
79 #include <unistd.h>
80 #include <stdint.h>
81 #include <arpa/inet.h>
82 #include <arpa/nameser.h>
83 #include <net/if.h>
84 #include <netinet/in.h>
85 #include <sys/param.h>
86 #include <sys/socket.h>
87 #include <sys/time.h>
88 #include <sys/types.h>
89
90 #include <not-cancel.h>
91
92 /* Options.  Should all be left alone. */
93 #define RESOLVSORT
94 #define RFC1535
95 /* #undef DEBUG */
96
97 static void res_setoptions (res_state, const char *, const char *)
98      internal_function;
99
100 #ifdef RESOLVSORT
101 static const char sort_mask_chars[] = "/&";
102 #define ISSORTMASK(ch) (strchr(sort_mask_chars, ch) != NULL)
103 static u_int32_t net_mask (struct in_addr) __THROW;
104 #endif
105
106 #if !defined(isascii)   /* XXX - could be a function */
107 # define isascii(c) (!(c & 0200))
108 #endif
109
110 #ifdef _LIBC
111 unsigned long long int __res_initstamp attribute_hidden;
112 #endif
113
114 /*
115  * Resolver state default settings.
116  */
117
118 /*
119  * Set up default settings.  If the configuration file exist, the values
120  * there will have precedence.  Otherwise, the server address is set to
121  * INADDR_ANY and the default domain name comes from the gethostname().
122  *
123  * An interrim version of this code (BIND 4.9, pre-4.4BSD) used 127.0.0.1
124  * rather than INADDR_ANY ("0.0.0.0") as the default name server address
125  * since it was noted that INADDR_ANY actually meant ``the first interface
126  * you "ifconfig"'d at boot time'' and if this was a SLIP or PPP interface,
127  * it had to be "up" in order for you to reach your own name server.  It
128  * was later decided that since the recommended practice is to always
129  * install local static routes through 127.0.0.1 for all your network
130  * interfaces, that we could solve this problem without a code change.
131  *
132  * The configuration file should always be used, since it is the only way
133  * to specify a default domain.  If you are running a server on your local
134  * machine, you should say "nameserver 0.0.0.0" or "nameserver 127.0.0.1"
135  * in the configuration file.
136  *
137  * Return 0 if completes successfully, -1 on error
138  */
139 int
140 res_ninit(res_state statp) {
141         extern int __res_vinit(res_state, int);
142
143         return (__res_vinit(statp, 0));
144 }
145 #ifdef _LIBC
146 libc_hidden_def (__res_ninit)
147 #endif
148
149 /* This function has to be reachable by res_data.c but not publically. */
150 int
151 __res_vinit(res_state statp, int preinit) {
152         FILE *fp;
153         char *cp, **pp;
154         int n;
155         char buf[BUFSIZ];
156         int nserv = 0;    /* number of IPv4 nameservers read from file */
157 #ifdef _LIBC
158         int nservall = 0; /* number of (IPv4 + IPV6) nameservers read from file */
159 #endif
160         int haveenv = 0;
161         int havesearch = 0;
162 #ifdef RESOLVSORT
163         int nsort = 0;
164         char *net;
165 #endif
166 #ifndef RFC1535
167         int dots;
168 #endif
169 #ifdef _LIBC
170         statp->_u._ext.initstamp = __res_initstamp;
171 #endif
172
173         if (!preinit) {
174                 statp->retrans = RES_TIMEOUT;
175                 statp->retry = RES_DFLRETRY;
176                 statp->options = RES_DEFAULT;
177                 statp->id = res_randomid();
178         }
179
180         statp->nscount = 0;
181         statp->ndots = 1;
182         statp->pfcode = 0;
183         statp->_vcsock = -1;
184         statp->_flags = 0;
185         statp->qhook = NULL;
186         statp->rhook = NULL;
187         statp->_u._ext.nsinit = 0;
188         statp->_u._ext.nscount = 0;
189 #ifdef _LIBC
190         statp->_u._ext.nscount6 = 0;
191         for (n = 0; n < MAXNS; n++) {
192                 statp->_u._ext.nsaddrs[n] = NULL;
193                 statp->_u._ext.nsmap[n] = MAXNS;
194         }
195 #endif
196
197         /* Allow user to override the local domain definition */
198         if ((cp = getenv("LOCALDOMAIN")) != NULL) {
199                 (void)strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
200                 statp->defdname[sizeof(statp->defdname) - 1] = '\0';
201                 haveenv++;
202
203                 /*
204                  * Set search list to be blank-separated strings
205                  * from rest of env value.  Permits users of LOCALDOMAIN
206                  * to still have a search list, and anyone to set the
207                  * one that they want to use as an individual (even more
208                  * important now that the rfc1535 stuff restricts searches)
209                  */
210                 cp = statp->defdname;
211                 pp = statp->dnsrch;
212                 *pp++ = cp;
213                 for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) {
214                         if (*cp == '\n')        /* silly backwards compat */
215                                 break;
216                         else if (*cp == ' ' || *cp == '\t') {
217                                 *cp = 0;
218                                 n = 1;
219                         } else if (n) {
220                                 *pp++ = cp;
221                                 n = 0;
222                                 havesearch = 1;
223                         }
224                 }
225                 /* null terminate last domain if there are excess */
226                 while (*cp != '\0' && *cp != ' ' && *cp != '\t' && *cp != '\n')
227                         cp++;
228                 *cp = '\0';
229                 *pp++ = 0;
230         }
231
232 #define MATCH(line, name) \
233         (!strncmp(line, name, sizeof(name) - 1) && \
234         (line[sizeof(name) - 1] == ' ' || \
235          line[sizeof(name) - 1] == '\t'))
236
237         if ((fp = fopen(_PATH_RESCONF, "rce")) != NULL) {
238             /* No threads use this stream.  */
239             __fsetlocking (fp, FSETLOCKING_BYCALLER);
240             /* read the config file */
241             while (__fgets_unlocked(buf, sizeof(buf), fp) != NULL) {
242                 /* skip comments */
243                 if (*buf == ';' || *buf == '#')
244                         continue;
245                 /* read default domain name */
246                 if (MATCH(buf, "domain")) {
247                     if (haveenv)        /* skip if have from environ */
248                             continue;
249                     cp = buf + sizeof("domain") - 1;
250                     while (*cp == ' ' || *cp == '\t')
251                             cp++;
252                     if ((*cp == '\0') || (*cp == '\n'))
253                             continue;
254                     strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
255                     statp->defdname[sizeof(statp->defdname) - 1] = '\0';
256                     if ((cp = strpbrk(statp->defdname, " \t\n")) != NULL)
257                             *cp = '\0';
258                     havesearch = 0;
259                     continue;
260                 }
261                 /* set search list */
262                 if (MATCH(buf, "search")) {
263                     if (haveenv)        /* skip if have from environ */
264                             continue;
265                     cp = buf + sizeof("search") - 1;
266                     while (*cp == ' ' || *cp == '\t')
267                             cp++;
268                     if ((*cp == '\0') || (*cp == '\n'))
269                             continue;
270                     strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
271                     statp->defdname[sizeof(statp->defdname) - 1] = '\0';
272                     if ((cp = strchr(statp->defdname, '\n')) != NULL)
273                             *cp = '\0';
274                     /*
275                      * Set search list to be blank-separated strings
276                      * on rest of line.
277                      */
278                     cp = statp->defdname;
279                     pp = statp->dnsrch;
280                     *pp++ = cp;
281                     for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) {
282                             if (*cp == ' ' || *cp == '\t') {
283                                     *cp = 0;
284                                     n = 1;
285                             } else if (n) {
286                                     *pp++ = cp;
287                                     n = 0;
288                             }
289                     }
290                     /* null terminate last domain if there are excess */
291                     while (*cp != '\0' && *cp != ' ' && *cp != '\t')
292                             cp++;
293                     *cp = '\0';
294                     *pp++ = 0;
295                     havesearch = 1;
296                     continue;
297                 }
298                 /* read nameservers to query */
299 #ifdef _LIBC
300                 if (MATCH(buf, "nameserver") && nservall < MAXNS) {
301 #else
302                 if (MATCH(buf, "nameserver") && nserv < MAXNS) {
303 #endif
304                     struct in_addr a;
305
306                     cp = buf + sizeof("nameserver") - 1;
307                     while (*cp == ' ' || *cp == '\t')
308                         cp++;
309                     if ((*cp != '\0') && (*cp != '\n')
310                         && __inet_aton(cp, &a)) {
311                         statp->nsaddr_list[nservall].sin_addr = a;
312                         statp->nsaddr_list[nservall].sin_family = AF_INET;
313                         statp->nsaddr_list[nservall].sin_port =
314                                 htons(NAMESERVER_PORT);
315                         nserv++;
316 #ifdef _LIBC
317                         nservall++;
318                     } else {
319                         struct in6_addr a6;
320                         char *el;
321
322                         if ((el = strpbrk(cp, " \t\n")) != NULL)
323                             *el = '\0';
324                         if ((el = strchr(cp, SCOPE_DELIMITER)) != NULL)
325                             *el = '\0';
326                         if ((*cp != '\0') &&
327                             (__inet_pton(AF_INET6, cp, &a6) > 0)) {
328                             struct sockaddr_in6 *sa6;
329
330                             sa6 = malloc(sizeof(*sa6));
331                             if (sa6 != NULL) {
332                                 sa6->sin6_family = AF_INET6;
333                                 sa6->sin6_port = htons(NAMESERVER_PORT);
334                                 sa6->sin6_flowinfo = 0;
335                                 sa6->sin6_addr = a6;
336
337                                 if (__glibc_likely (el == NULL))
338                                     sa6->sin6_scope_id = 0;
339                                 else {
340                                     int try_numericscope = 1;
341                                     if (IN6_IS_ADDR_LINKLOCAL (&a6)
342                                         || IN6_IS_ADDR_MC_LINKLOCAL (&a6)) {
343                                         sa6->sin6_scope_id
344                                           = __if_nametoindex (el + 1);
345                                         if (sa6->sin6_scope_id != 0)
346                                             try_numericscope = 0;
347                                     }
348
349                                     if (try_numericscope) {
350                                         char *end;
351                                         sa6->sin6_scope_id
352                                           = (uint32_t) strtoul (el + 1, &end,
353                                                                 10);
354                                         if (*end != '\0')
355                                             sa6->sin6_scope_id = 0;
356                                     }
357                                 }
358
359                                 statp->_u._ext.nsaddrs[nservall] = sa6;
360                                 statp->_u._ext.nssocks[nservall] = -1;
361                                 statp->_u._ext.nsmap[nservall] = MAXNS + 1;
362                                 nservall++;
363                             }
364                         }
365 #endif
366                     }
367                     continue;
368                 }
369 #ifdef RESOLVSORT
370                 if (MATCH(buf, "sortlist")) {
371                     struct in_addr a;
372
373                     cp = buf + sizeof("sortlist") - 1;
374                     while (nsort < MAXRESOLVSORT) {
375                         while (*cp == ' ' || *cp == '\t')
376                             cp++;
377                         if (*cp == '\0' || *cp == '\n' || *cp == ';')
378                             break;
379                         net = cp;
380                         while (*cp && !ISSORTMASK(*cp) && *cp != ';' &&
381                                isascii(*cp) && !isspace(*cp))
382                                 cp++;
383                         n = *cp;
384                         *cp = 0;
385                         if (__inet_aton(net, &a)) {
386                             statp->sort_list[nsort].addr = a;
387                             if (ISSORTMASK(n)) {
388                                 *cp++ = n;
389                                 net = cp;
390                                 while (*cp && *cp != ';' &&
391                                         isascii(*cp) && !isspace(*cp))
392                                     cp++;
393                                 n = *cp;
394                                 *cp = 0;
395                                 if (__inet_aton(net, &a)) {
396                                     statp->sort_list[nsort].mask = a.s_addr;
397                                 } else {
398                                     statp->sort_list[nsort].mask =
399                                         net_mask(statp->sort_list[nsort].addr);
400                                 }
401                             } else {
402                                 statp->sort_list[nsort].mask =
403                                     net_mask(statp->sort_list[nsort].addr);
404                             }
405                             nsort++;
406                         }
407                         *cp = n;
408                     }
409                     continue;
410                 }
411 #endif
412                 if (MATCH(buf, "options")) {
413                     res_setoptions(statp, buf + sizeof("options") - 1, "conf");
414                     continue;
415                 }
416             }
417             statp->nscount = nservall;
418 #ifdef _LIBC
419             if (nservall - nserv > 0) {
420                 statp->_u._ext.nscount6 = nservall - nserv;
421                 /* We try IPv6 servers again.  */
422                 statp->ipv6_unavail = false;
423             }
424 #endif
425 #ifdef RESOLVSORT
426             statp->nsort = nsort;
427 #endif
428             (void) fclose(fp);
429         }
430         if (__builtin_expect(statp->nscount == 0, 0)) {
431             statp->nsaddr.sin_addr = __inet_makeaddr(IN_LOOPBACKNET, 1);
432             statp->nsaddr.sin_family = AF_INET;
433             statp->nsaddr.sin_port = htons(NAMESERVER_PORT);
434             statp->nscount = 1;
435         }
436         if (statp->defdname[0] == 0 &&
437             __gethostname(buf, sizeof(statp->defdname) - 1) == 0 &&
438             (cp = strchr(buf, '.')) != NULL)
439                 strcpy(statp->defdname, cp + 1);
440
441         /* find components of local domain that might be searched */
442         if (havesearch == 0) {
443                 pp = statp->dnsrch;
444                 *pp++ = statp->defdname;
445                 *pp = NULL;
446
447 #ifndef RFC1535
448                 dots = 0;
449                 for (cp = statp->defdname; *cp; cp++)
450                         dots += (*cp == '.');
451
452                 cp = statp->defdname;
453                 while (pp < statp->dnsrch + MAXDFLSRCH) {
454                         if (dots < LOCALDOMAINPARTS)
455                                 break;
456                         cp = __rawmemchr(cp, '.') + 1;    /* we know there is one */
457                         *pp++ = cp;
458                         dots--;
459                 }
460                 *pp = NULL;
461 #ifdef DEBUG
462                 if (statp->options & RES_DEBUG) {
463                         printf(";; res_init()... default dnsrch list:\n");
464                         for (pp = statp->dnsrch; *pp; pp++)
465                                 printf(";;\t%s\n", *pp);
466                         printf(";;\t..END..\n");
467                 }
468 #endif
469 #endif /* !RFC1535 */
470         }
471
472         if ((cp = getenv("RES_OPTIONS")) != NULL)
473                 res_setoptions(statp, cp, "env");
474         statp->options |= RES_INIT;
475         return (0);
476 }
477
478 static void
479 internal_function
480 res_setoptions(res_state statp, const char *options, const char *source) {
481         const char *cp = options;
482         int i;
483
484 #ifdef DEBUG
485         if (statp->options & RES_DEBUG)
486                 printf(";; res_setoptions(\"%s\", \"%s\")...\n",
487                        options, source);
488 #endif
489         while (*cp) {
490                 /* skip leading and inner runs of spaces */
491                 while (*cp == ' ' || *cp == '\t')
492                         cp++;
493                 /* search for and process individual options */
494                 if (!strncmp(cp, "ndots:", sizeof("ndots:") - 1)) {
495                         i = atoi(cp + sizeof("ndots:") - 1);
496                         if (i <= RES_MAXNDOTS)
497                                 statp->ndots = i;
498                         else
499                                 statp->ndots = RES_MAXNDOTS;
500 #ifdef DEBUG
501                         if (statp->options & RES_DEBUG)
502                                 printf(";;\tndots=%d\n", statp->ndots);
503 #endif
504                 } else if (!strncmp(cp, "timeout:", sizeof("timeout:") - 1)) {
505                         i = atoi(cp + sizeof("timeout:") - 1);
506                         if (i <= RES_MAXRETRANS)
507                                 statp->retrans = i;
508                         else
509                                 statp->retrans = RES_MAXRETRANS;
510                 } else if (!strncmp(cp, "attempts:", sizeof("attempts:") - 1)){
511                         i = atoi(cp + sizeof("attempts:") - 1);
512                         if (i <= RES_MAXRETRY)
513                                 statp->retry = i;
514                         else
515                                 statp->retry = RES_MAXRETRY;
516                 } else if (!strncmp(cp, "debug", sizeof("debug") - 1)) {
517 #ifdef DEBUG
518                         if (!(statp->options & RES_DEBUG)) {
519                                 printf(";; res_setoptions(\"%s\", \"%s\")..\n",
520                                        options, source);
521                                 statp->options |= RES_DEBUG;
522                         }
523                         printf(";;\tdebug\n");
524 #endif
525                 } else {
526                   static const struct
527                   {
528                     char str[22];
529                     uint8_t len;
530                     uint8_t clear;
531                     unsigned long int flag;
532                   } options[] = {
533 #define STRnLEN(str) str, sizeof (str) - 1
534                     { STRnLEN ("inet6"), 0, RES_USE_INET6 },
535                     { STRnLEN ("ip6-bytestring"), 0, RES_USEBSTRING },
536                     { STRnLEN ("no-ip6-dotint"), 0, RES_NOIP6DOTINT },
537                     { STRnLEN ("ip6-dotint"), 1, ~RES_NOIP6DOTINT },
538                     { STRnLEN ("rotate"), 0, RES_ROTATE },
539                     { STRnLEN ("no-check-names"), 0, RES_NOCHECKNAME },
540                     { STRnLEN ("edns0"), 0, RES_USE_EDNS0 },
541                     { STRnLEN ("single-request-reopen"), 0, RES_SNGLKUPREOP },
542                     { STRnLEN ("single-request"), 0, RES_SNGLKUP },
543                     { STRnLEN ("no_tld_query"), 0, RES_NOTLDQUERY },
544                     { STRnLEN ("no-tld-query"), 0, RES_NOTLDQUERY },
545                     { STRnLEN ("use-vc"), 0, RES_USEVC }
546                   };
547 #define noptions (sizeof (options) / sizeof (options[0]))
548                   int i;
549                   for (i = 0; i < noptions; ++i)
550                     if (strncmp (cp, options[i].str, options[i].len) == 0)
551                       {
552                         if (options[i].clear)
553                           statp->options &= options[i].flag;
554                         else
555                           statp->options |= options[i].flag;
556                         break;
557                       }
558                   if (i == noptions) {
559                     /* XXX - print a warning here? */
560                   }
561                 }
562                 /* skip to next run of spaces */
563                 while (*cp && *cp != ' ' && *cp != '\t')
564                         cp++;
565         }
566 }
567
568 #ifdef RESOLVSORT
569 /* XXX - should really support CIDR which means explicit masks always. */
570 static u_int32_t
571 net_mask(in)            /* XXX - should really use system's version of this */
572         struct in_addr in;
573 {
574         u_int32_t i = ntohl(in.s_addr);
575
576         if (IN_CLASSA(i))
577                 return (htonl(IN_CLASSA_NET));
578         else if (IN_CLASSB(i))
579                 return (htonl(IN_CLASSB_NET));
580         return (htonl(IN_CLASSC_NET));
581 }
582 #endif
583
584 u_int
585 res_randomid(void) {
586         return 0xffff & __getpid();
587 }
588 #ifdef _LIBC
589 libc_hidden_def (__res_randomid)
590 #endif
591
592
593 /*
594  * This routine is for closing the socket if a virtual circuit is used and
595  * the program wants to close it.  This provides support for endhostent()
596  * which expects to close the socket.
597  *
598  * This routine is not expected to be user visible.
599  */
600 void
601 __res_iclose(res_state statp, bool free_addr) {
602         int ns;
603
604         if (statp->_vcsock >= 0) {
605                 close_not_cancel_no_status(statp->_vcsock);
606                 statp->_vcsock = -1;
607                 statp->_flags &= ~(RES_F_VC | RES_F_CONN);
608         }
609 #ifdef _LIBC
610         for (ns = 0; ns < MAXNS; ns++)
611 #else
612         for (ns = 0; ns < statp->_u._ext.nscount; ns++)
613 #endif
614                 if (statp->_u._ext.nsaddrs[ns]) {
615                         if (statp->_u._ext.nssocks[ns] != -1) {
616                                 close_not_cancel_no_status(statp->_u._ext.nssocks[ns]);
617                                 statp->_u._ext.nssocks[ns] = -1;
618                         }
619                         if (free_addr) {
620                                 free (statp->_u._ext.nsaddrs[ns]);
621                                 statp->_u._ext.nsaddrs[ns] = NULL;
622                         }
623                 }
624         if (free_addr)
625                 statp->_u._ext.nsinit = 0;
626 }
627 libc_hidden_def (__res_iclose)
628
629 void
630 res_nclose(res_state statp)
631 {
632   __res_iclose (statp, true);
633 }
634 #ifdef _LIBC
635 libc_hidden_def (__res_nclose)
636 #endif
637
638 #ifdef _LIBC
639 # ifdef _LIBC_REENTRANT
640 /* This is called when a thread is exiting to free resources held in _res.  */
641 static void __attribute__ ((section ("__libc_thread_freeres_fn")))
642 res_thread_freeres (void)
643 {
644   if (_res.nscount == 0)
645     /* Never called res_ninit.  */
646     return;
647
648   __res_iclose (&_res, true);           /* Close any VC sockets.  */
649
650   /* Make sure we do a full re-initialization the next time.  */
651   _res.options = 0;
652 }
653 text_set_element (__libc_thread_subfreeres, res_thread_freeres);
654 text_set_element (__libc_subfreeres, res_thread_freeres);
655 # endif
656 #endif