Watt-32 tcp/ip  2.2 dev-rel.10
gethost.c
Go to the documentation of this file.
1 
6 /*
7  * Copyright (c) 1997-2002 Gisle Vanem <gvanem@yahoo.no>
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  * notice, this list of conditions and the following disclaimer in the
16  * documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  * must display the following acknowledgement:
19  * This product includes software developed by Gisle Vanem
20  * Bergen, Norway.
21  *
22  * THIS SOFTWARE IS PROVIDED BY ME (Gisle Vanem) AND CONTRIBUTORS ``AS IS''
23  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED. IN NO EVENT SHALL I OR CONTRIBUTORS BE LIABLE FOR ANY
26  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
29  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  *
34  * 18.aug 1996 (GV) - Created
35  * 02.dec 1997 (GV) - Integrated with resolve()
36  * 05.jan 1998 (GV) - Added host cache functionality
37  * 18.may 1999 (GV) - Added timeout of cached values
38  *
39  * todo: support real host aliases as they come from the name server
40  * todo: accept "rooted FQDN" strings as normal FQDN strings.
41  * Note: "domain_name.com" and "domain_name.com." are equivalent
42  * (both are valid forms of fully qualified domain names (FQDNs);
43  * with the period, it is referred to as a rooted FQDN). Both forms
44  * should work with all mail clients and servers. However, using the
45  * trailing "." is rarely used (except in DNS maintenance).
46  *
47  * Note: if gethostbyname("some.host") returns address a.b.c.d, then
48  * a call to gethostbyaddr(a.b.c.d) will return "some.host"
49  * immediately (from cached info provided it didn't time out).
50  * This is contrary to most Unixes where the calls doesn't share
51  * the same information.
52  */
53 
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <string.h>
57 #include <ctype.h>
58 #include <time.h>
59 #include <netdb.h>
60 #include <arpa/inet.h>
61 
62 #include "wattcp.h"
63 #include "strings.h"
64 #include "misc.h"
65 #include "run.h"
66 #include "timer.h"
67 #include "language.h"
68 #include "pcconfig.h"
69 #include "netaddr.h"
70 #include "pctcp.h"
71 #include "bsdname.h"
72 #include "bsddbug.h"
73 #include "pcdns.h"
74 #include "get_xby.h"
75 
76 int h_errno = 0;
77 
78 #if defined(USE_BSD_API) /* Whole file */
79 
80 unsigned netdbCacheLife = MAX_CACHE_LIFE;
81 
82 static char *hostFname = NULL;
83 static FILE *hostFile = NULL;
84 static BOOL hostClose = FALSE;
85 static const char *from_where = NULL;
86 static struct _hostent *host0 = NULL;
87 
88 static BOOL did_lookup = FALSE; /* tried a DNS lookup */
89 static BOOL is_addr = FALSE; /* name is simply an IPv4 address */
90 
91 static BOOL gethostbyname_internal (const char *name,
92  const char **alias,
93  struct _hostent *ret);
94 
95 static BOOL gethostbyaddr_internal (const char *addr_name, int len, int type,
96  struct _hostent *ret);
97 
98 static struct hostent *fill_hostent (const struct _hostent *h);
99 
100 static struct _hostent *add_hostent (struct _hostent *h,
101  const char *name, const char *cname,
102  DWORD *alist, DWORD addr, DWORD ttl,
103  BOOL windns);
104 
105 static void _endhostent (void)
106 {
107  endhostent();
108 }
109 
110 void W32_CALL ReadHostsFile (const char *fname)
111 {
112  static BOOL been_here = FALSE;
113 
114  if (!fname || !*fname)
115  return;
116 
117  if (been_here) /* loading multiple hosts files */
118  {
119  free (hostFname);
120  FCLOSE (hostFile);
121  hostFile = NULL;
122  }
123 
124  hostFname = strdup (fname);
125  if (!hostFname)
126  return;
127 
128  sethostent (1);
129  if (!hostFile)
130  return;
131 
132  been_here = TRUE;
133 
134  while (1)
135  {
136  struct hostent *h = gethostent();
137  struct _hostent *h2;
138  int i;
139 
140  if (!h)
141  break;
142 
143  h2 = calloc (sizeof(*h2), 1);
144  if (!h2)
145  {
146  outs (hostFname);
147  outsnl (_LANG(" too big!"));
148  break;
149  }
150 
151  for (i = 0; h->h_aliases[i]; i++)
152  h2->h_aliases[i] = strdup (h->h_aliases[i]);
153  h2->h_name = strdup (h->h_name);
154  h2->h_address[0] = *(DWORD*) h->h_addr_list[0];
155  h2->h_num_addr = 1;
156  if (!h2->h_name)
157  break;
158  h2->h_next = host0;
159  host0 = h2;
160  }
161 
162 #if 0 /* test !! */
163  {
164  const struct _hostent *h;
165  int i;
166 
167  printf ("\n%s entries:\n", hostFname);
168  for (h = host0; h; h = h->h_next)
169  {
170  printf ("address = %-17.17s name = %-30.30s Aliases:",
171  inet_ntoa(*(struct in_addr*)&h->h_address[0]), h->h_name);
172  for (i = 0; h->h_aliases[i]; i++)
173  printf (" %s,", h->h_aliases[i]);
174  puts ("");
175  }
176  fflush (stdout);
177  }
178 #endif
179  rewind (hostFile);
180  RUNDOWN_ADD (_endhostent, 254);
181 }
182 
187 const char * W32_CALL GetHostsFile (void)
188 {
189  return (hostFname);
190 }
191 
197 void W32_CALL CloseHostFile (void)
198 {
199  if (hostFile)
200  FCLOSE (hostFile);
201  hostFile = NULL;
202 }
203 
208 void W32_CALL ReopenHostFile (void)
209 {
210  ReadHostsFile (hostFname);
211 }
212 
218 struct hostent * W32_CALL gethostent (void)
219 {
220  struct _hostent h;
221  char *tok, *ip, *name, *alias, *tok_buf = NULL;
222  char buf [2*MAX_HOSTLEN];
223  int i;
224 
225  if (!netdb_init() || !hostFile)
226  {
227  h_errno = NO_RECOVERY;
228  return (NULL);
229  }
230 
231  while (1)
232  {
233  if (!fgets(buf,sizeof(buf),hostFile))
234  return (NULL);
235 
236  tok = strltrim (buf);
237  if (*tok == '#' || *tok == ';' || *tok == '\n')
238  continue;
239 
240  ip = strtok_r (tok, " \t", &tok_buf);
241  name = strtok_r (NULL, " \t\n", &tok_buf);
242  if (ip && name && isaddr(ip))
243  break;
244  }
245 
246  if (hostClose)
247  endhostent();
248 
249  memset (&h, 0, sizeof(h));
250  if (!strcmp(ip,"0.0.0.0")) /* inet_addr() maps 0 -> INADDR_NONE */
251  h.h_address[0] = INADDR_ANY;
252  else h.h_address[0] = inet_addr (ip);
253 
254  h.h_num_addr = 1;
255  h.h_name = name;
256  alias = strtok_r (NULL, " \t\n", &tok_buf);
257 
258  for (i = 0; alias && i < MAX_HOST_ALIASES; i++)
259  {
260  static char aliases [MAX_HOST_ALIASES][MAX_HOSTLEN];
261 
262  if (*alias == '#' || *alias == ';')
263  break;
264 
265  h.h_aliases[i] = _strlcpy (aliases[i], alias, sizeof(aliases[i]));
266  alias = strtok_r (NULL, " \t\n", &tok_buf);
267  }
268  return fill_hostent (&h);
269 }
270 
271 /*
272  * Return a 'struct hostent *' for name.
273  */
274 struct hostent * W32_CALL gethostbyname (const char *name)
275 {
276  struct _hostent h;
277  const char *alias;
278 
279  SOCK_DEBUGF (("\ngethostbyname: `%s'", name));
280  is_addr = FALSE;
281 
282  if (gethostbyname_internal(name, &alias, &h))
283  {
284 #if defined(USE_DEBUG)
285  int i;
286  for (i = 0; i < h.h_num_addr; i++)
287  SOCK_DEBUGF ((" %s,", inet_ntoa(*(struct in_addr*)&h.h_address[i])));
288 
289  if (!did_lookup)
290  SOCK_DEBUGF ((" %s", is_addr ? "" :
291  h.h_timeout ? "cached" :
292  from_where ? from_where : "hosts-file"));
293  if (alias)
294  SOCK_DEBUGF ((" (alias %s)", alias));
295 #endif
296  return fill_hostent (&h);
297  }
298 
300  SOCK_DEBUGF ((", unknown (called from resolve)"));
301  else SOCK_DEBUGF ((", failed (%s)", did_lookup ? dom_strerror(dom_errno) :
302  hstrerror(h_errno)));
303  return (NULL);
304 }
305 
306 static BOOL gethostbyname_internal (const char *name, const char **alias,
307  struct _hostent *ret)
308 {
309  static char our_name [MAX_HOSTLEN];
310  struct in_addr addr;
311  struct _hostent *h;
312  time_t now;
313  DWORD ip;
314 
315  h_errno = HOST_NOT_FOUND;
316  did_lookup = FALSE;
317  from_where = NULL;
318 
319  _resolve_exit = _resolve_timeout = 0;
320  memset (ret, 0, sizeof(*ret));
321  *alias = NULL;
322 
323  if (!netdb_init())
324  {
325  h_errno = NO_RECOVERY;
326  return (FALSE);
327  }
328 
329  if (inet_aton(name,&addr))
330  {
332  ret->h_name = (char*) name;
333  ret->h_address[0] = addr.s_addr;
334  ret->h_num_addr = 1;
335  is_addr = TRUE;
336  return (TRUE);
337  }
338 
339  now = time (NULL);
340 
341  for (h = host0; h; h = h->h_next)
342  {
343  int i;
344 
345  if (h->h_name && !stricmp(h->h_name,name))
346  {
347  /* if cached entry expired, do DNS lookup
348  */
349  if (h->h_timeout && now > h->h_timeout)
350  goto expired;
351 
352  *ret = *h;
353  return (h->h_address[0] != INADDR_NONE ? TRUE : FALSE);
354  }
355  for (i = 0; i < MAX_HOST_ALIASES && h->h_aliases[i]; i++)
356  if (!stricmp(name,h->h_aliases[i]))
357  {
358  if (h->h_timeout && now > h->h_timeout)
359  goto expired;
360 
361  *alias = h->h_aliases[i];
362  *ret = *h;
363  return (h->h_address[0] != INADDR_NONE ? TRUE : FALSE);
364  }
365  }
366 
367  /* Not found in linked list (hosts file or cache). Check name
368  * against our own host-name (short-name or FQDN).
369  * \todo Should return all our addresses if we're multihomed.
370  */
371  if (hostname[0] && !stricmp(name,hostname))
372  {
373  ret->h_num_addr = 1;
374  ret->h_address[0] = gethostid();
375  ret->h_name = hostname;
376  from_where = "gethostname";
377  return (TRUE);
378  }
379 
380  if (!gethostname(our_name,sizeof(our_name)) && !stricmp(name,our_name))
381  {
382  ret->h_num_addr = 1;
383  ret->h_address[0] = gethostid();
384  ret->h_name = our_name;
385  from_where = "gethostname";
386  return (TRUE);
387  }
388 
389 expired:
390 
391  if (called_from_resolve) /* prevent recursion */
392  return (FALSE);
393 
394  /* Do a full DNS lookup
395  */
396  called_from_ghbn = TRUE;
397  ip = resolve (name); /* do a normal lookup */
398  called_from_ghbn = FALSE;
399  did_lookup = TRUE;
400 
401  if (_resolve_exit || /* interrupted or other fail */
402  _resolve_timeout) /* timed out resolving */
403  return (FALSE);
404 
405  if (ip) /* successfully resolved */
406  {
407  h = add_hostent (h, name, dom_cname, dom_a4list, htonl(ip),
408  dom_ttl, from_windns);
409  return (h ? *ret = *h, TRUE : FALSE);
410  }
411 
412  /* Add the name to the list even if we got a negative DNS reply.
413  * Thus the next call to gethostbyxx() will return immediately.
414  */
415  add_hostent (h, name, NULL, NULL, INADDR_NONE, netdbCacheLife, from_windns);
416  return (FALSE);
417 }
418 
419 struct hostent * W32_CALL gethostbyname2 (const char *name, int family)
420 {
421  if (family == AF_INET)
422  return gethostbyname (name);
423 
424 #if defined(USE_IPV6)
425  if (family == AF_INET6)
426  return gethostbyname6 (name);
427 #endif
428 
429  h_errno = TRY_AGAIN;
430  return (NULL);
431 }
432 
433 
434 /*
435  * Return a 'struct hostent *' for an address.
436  */
437 struct hostent * W32_CALL gethostbyaddr (const char *addr_name, int len, int type)
438 {
439  struct _hostent h;
440 
441  SOCK_DEBUGF (("\ngethostbyaddr: %s",
442  (type == AF_INET && addr_name) ?
443  inet_ntoa(*(struct in_addr*)addr_name) :
444  (type == AF_INET6 && addr_name) ?
445  _inet6_ntoa(addr_name) : ""));
446 
447 #if defined(USE_IPV6)
448  if (type == AF_INET6 && len == sizeof(struct in6_addr))
449  {
450  struct hostent *he;
451 
452  SOCK_ENTER_SCOPE();
453  he = gethostbyaddr6 (addr_name);
454  SOCK_LEAVE_SCOPE();
455  return (he);
456  }
457 #endif
458 
459  if (gethostbyaddr_internal (addr_name, len, type, &h))
460  {
461  SOCK_DEBUGF ((" `%s'", h.h_name));
462  if (!did_lookup)
463  SOCK_DEBUGF ((", %s", h.h_timeout ? "cached" : "hosts-file"));
464  return fill_hostent (&h);
465  }
466 
467  SOCK_DEBUGF ((" failed (%s) ", did_lookup ? dom_strerror(dom_errno) :
468  hstrerror(h_errno)));
469  return (NULL);
470 }
471 
472 
473 void W32_CALL sethostent (int stayopen)
474 {
475  hostClose = (stayopen == 0);
476  if (!netdb_init() || !hostFname)
477  return;
478 
479  if (!hostFile)
480  FOPEN_TXT (hostFile, hostFname);
481  else rewind (hostFile);
482 }
483 
484 void W32_CALL endhostent (void)
485 {
486  struct _hostent *h, *next = NULL;
487 
488  if (_watt_fatal_error)
489  return;
490 
491  if (hostFname)
492  free (hostFname);
493  if (hostFile)
494  FCLOSE (hostFile);
495  hostFname = NULL;
496  hostFile = NULL;
497 
498  for (h = host0; h; h = next)
499  {
500  int i;
501  for (i = 0; h->h_aliases[i]; i++)
502  free (h->h_aliases[i]);
503  next = h->h_next;
504  free (h->h_name);
505  free (h);
506  }
507  host0 = NULL;
508  hostClose = TRUE;
509 }
510 
511 
512 static BOOL gethostbyaddr_internal (const char *addr_name, int len, int type,
513  struct _hostent *ret)
514 {
515  static char name [MAX_HOSTLEN];
516  struct _hostent *h = NULL;
517  DWORD addr;
518  BOOL rc;
519  time_t now;
520 
521  h_errno = HOST_NOT_FOUND;
522  did_lookup = FALSE;
523  from_where = NULL;
524  _resolve_exit = _resolve_timeout = 0;
525  memset (ret, 0, sizeof(*ret));
526 
527  if (type != AF_INET || len < SIZEOF(addr))
528  {
529  h_errno = NO_RECOVERY;
530  return (FALSE);
531  }
532 
533  if (!netdb_init())
534  {
535  h_errno = NO_RECOVERY;
536  return (FALSE);
537  }
538 
539  addr = *(DWORD*) addr_name;
540 
541  if ((addr == INADDR_ANY || /* 0.0.0.0 -> my_ip_addr */
542  addr == gethostid()) &&
543  gethostname(name,sizeof(name)) == 0)
544  {
547  ret->h_num_addr = 1;
548  ret->h_address[0] = gethostid();
549  ret->h_name = name;
550  from_where = "gethostname";
551  return (TRUE);
552  }
553 
554  if (addr == INADDR_BROADCAST || /* 255.255.255.255 */
555  (~ntohl(addr) & ~sin_mask) == 0) /* directed broadcast */
556  {
557  ret->h_num_addr = 1;
558  ret->h_address[0] = addr;
559  ret->h_name = (char*) "broadcast";
560  return (TRUE);
561  }
562 
563  now = time (NULL);
564 
565  /* If called from getnameinfo() with AI_CANONNAME, we
566  * should not search the host0 list. But do a full reeverse
567  * lookup.
568  */
569  if (called_from_getai)
570  goto expired;
571 
572  for (h = host0; h; h = h->h_next)
573  {
574  int i;
575 
576  for (i = 0; i < h->h_num_addr && h->h_address[i] != INADDR_NONE; i++)
577  {
578  if (addr == h->h_address[i])
579  {
580  /* if cached entry expired, do a new reverse lookup
581  */
582  if (h->h_timeout && now > h->h_timeout)
583  goto expired;
584 
585  *ret = *h;
586  if (!strcmp(h->h_name,"*unknown*"))
587  return (FALSE);
588  return (TRUE);
589  }
590  }
591  }
592 
593 expired:
594 
595  /* do a reverse ip lookup
596  */
597  did_lookup = TRUE;
598  rc = reverse_resolve_ip4 (addr, name, sizeof(name));
599 
600  /* interrupted or timedout
601  */
602  if (!rc && (_resolve_exit || _resolve_timeout))
603  return (FALSE);
604 
605  if (rc) /* successfully resolved */
606  {
607  h = add_hostent (h, name, dom_cname, NULL, addr, dom_ttl, from_windns);
609  return (h ? *ret = *h, TRUE : FALSE);
610  }
611 
612  /* Add the IP to the list even if reverse lookup failed and not
613  * interrupted by _resolve_hook(). Thus the next call to gethostbyxx()
614  * will return immediately.
615  */
616  add_hostent (h, "*unknown*", NULL, NULL, addr, 0UL, FALSE);
617  return (FALSE);
618 }
619 
620 
621 #if defined(NOT_USED)
622 /*
623  * Warn about calling 'getXbyY()' functions before calling
624  * 'watt_sock_init()'. Many other functions will fail if we're not
625  * initialised, but 'getXbyY()' are often used during application
626  * startup.
627  */
628 void uninit_warn (const char *func)
629 {
630  outs ("Warning: function \"");
631  outs (func);
632  outsnl ("()\" called before \"sock_init()\".");
633 }
634 #endif
635 
636 int * W32_CALL __h_errno_location (void)
637 {
638  return (&h_errno);
639 }
640 
641 static struct hostent *fill_hostent (const struct _hostent *h)
642 {
643  static struct hostent ret;
644  static struct in_addr addr [MAX_ADDRESSES+1];
645  static char *list [MAX_ADDRESSES+1];
646  static char hostnam [MAX_HOSTLEN+1];
647  static char *aliases [MAX_HOST_ALIASES+1];
648  int i;
649 
650  if (!h->h_name)
651  return (NULL);
652 
653  memset (&addr, 0, sizeof(addr));
654  memcpy (&aliases, h->h_aliases, sizeof(aliases));
655 
656  for (i = 0; i < h->h_num_addr && i < MAX_ADDRESSES; i++)
657  {
658  addr[i].s_addr = h->h_address[i];
659  list[i] = (char*) &addr[i];
660  }
661 
662  list[i] = NULL;
663  ret.h_addr_list = list;
664  ret.h_name = _strlcpy (hostnam, h->h_name, sizeof(hostnam));
665  ret.h_aliases = aliases;
666  ret.h_addrtype = AF_INET;
667  ret.h_length = sizeof (addr[0].s_addr);
668  h_errno = NETDB_SUCCESS;
669  return (&ret);
670 }
671 
672 /*
673  * Modify an expired cached entry or create a new node and
674  * add it to the linked list. Not used for entries in hosts-file.
675  */
676 static struct _hostent *add_hostent
677  (struct _hostent *h,
678  const char *name, /* Host name */
679  const char *cname, /* Canonical name (CNAME) */
680  DWORD *alist, /* List of alternate addresses */
681  DWORD addr, /* Main IP-address */
682  DWORD ttl, /* Time-to-live (sec) */
683  BOOL windns) /* answer came from WinDNS */
684 {
685  DWORD real_ttl = ttl;
686  int i;
687 
688  ttl = min (ttl, netdbCacheLife); /* clamp the TTL */
689 
690  if (h) /* reuse expired entry */
691  {
692  if (h->h_name)
693  free (h->h_name);
694  if (h->h_aliases[0])
695  free (h->h_aliases[0]); /* !! max 1 alias */
696  memset (&h->h_address[1], 0, /* clear old alternates */
697  sizeof(h->h_address)-sizeof(u_long));
698  h->h_aliases[0] = NULL;
699  }
700  else /* create a new node */
701  {
702  h = calloc (sizeof(*h), 1);
703  if (h)
704  {
705  h->h_next = host0;
706  host0 = h;
707  }
708  }
709 
710  if (!cname || !cname[0])
711  cname = NULL;
712 
713  if (addr != INADDR_NONE)
714  {
715  SOCK_DEBUGF ((", CNAME %s, TTL %s, ",
716  cname ? cname : "<none>", hms_str(real_ttl)));
717 #if defined(WIN32)
718  SOCK_DEBUGF (("WinDNS %d, ", windns));
719 #endif
720  }
721 
722  if (h)
723  {
724  h->h_timeout = ttl ? time (NULL) + ttl : 0;
725  h->h_real_ttl = real_ttl;
726  h->h_address[0] = addr;
727  h->h_num_addr = 1;
728 
729  for (i = 0; alist; i++)
730  {
731  if (alist[i] == INADDR_NONE || alist[i] == INADDR_ANY)
732  break;
733  h->h_address[i+1] = alist[i];
734  h->h_num_addr++;
735  }
736  if (cname) /* swap name with CNAME */
737  {
738  h->h_name = strdup (cname);
739  h->h_aliases[0] = strdup (name); /* !! only allow 1 alias */
740  }
741  else
742  h->h_name = strdup (name);
743  }
744  else
745  SOCK_DEBUGF ((" ENOMEM"));
746 
747 #if defined(TEST_PROG) /* test updated cache */
748  if (h)
749  {
750  printf ("new entry: name %-30.30s -> address %s ",
751  h->h_name, inet_ntoa(*(struct in_addr*)&h->h_address[0]));
752  for (i = 1; i < h->h_num_addr; i++)
753  printf (", %s",
754  inet_ntoa(*(struct in_addr*)&h->h_address[i]));
755  puts ("");
756  }
757  else
758  printf ("new entry: ENOMEM\n");
759 #endif
760 
761  ARGSUSED (windns);
762  return (h);
763 }
764 
765 #if defined(USE_DEBUG)
766 /*
767  * Reverse the 'host0' list before printing it. I.e. on same order
768  * the host-names where put in the list by add_hostent().
769  */
770 static BOOL ReverseHostsList (void)
771 {
772  struct _hostent *h, **list;
773  int i, num_total, num_dynamic;
774 
775  for (h = host0, num_total = num_dynamic = 0; h; h = h->h_next)
776  {
777  num_total++;
778  if (h->h_timeout > 0)
779  num_dynamic++;
780  }
781  if (num_total == 0 || num_dynamic == 0)
782  return (FALSE);
783 
784  list = malloc (num_total * sizeof(*list));
785  if (!list)
786  return (FALSE);
787 
788  for (h = host0, i = 0; h; h = h->h_next)
789  list[i++] = h;
790 
791  for (host0 = NULL, i = 0; i < num_total; i++)
792  {
793  h = list[i];
794  h->h_next = host0;
795  host0 = h;
796  }
797  free (list);
798  return (TRUE);
799 }
800 
801 void W32_CALL DumpHostsCache (void)
802 {
803  struct _hostent *h;
804  time_t now;
805 
806  if (!ReverseHostsList())
807  return;
808 
809  SOCK_DEBUGF ((" \n\nCached IPv4 hosts: "
810  "Address TTL Alias\n"));
811  now = time (NULL);
812 
813  for (h = host0; h; h = h->h_next)
814  {
815  const char *ip_str, *cache_time;
816  int i;
817 
818  if (h->h_real_ttl == 0) /* skip fixed hosts-file records */
819  continue;
820 
821  cache_time = ((long)(h->h_timeout - now) < 0) ? "timedout" :
822  hms_str(h->h_real_ttl);
823  ip_str = (h->h_address[0] == INADDR_NONE) ? "<none>" :
824  inet_ntoa(*(struct in_addr*)&h->h_address[0]);
825 
826  SOCK_DEBUGF ((" %-50s %-15s %9s ", h->h_name, ip_str, cache_time));
827  for (i = 0; h->h_aliases[i]; i++)
828  SOCK_DEBUGF (("%s ", h->h_aliases[i]));
829  if (i == 0)
830  SOCK_DEBUGF (("<none>\n"));
831  else SOCK_DEBUGF ((" \n"));
832 
833  for (i = 1; i < h->h_num_addr; i++)
834  SOCK_DEBUGF (("%52s %-15s\n", "", inet_ntoa(*(struct in_addr*)&h->h_address[i])));
835  }
836 }
837 #endif
838 
839 
840 #if defined(TEST_PROG)
841 
842 #if !defined(__CYGWIN__)
843 #include <conio.h>
844 #endif
845 
846 #if !defined(_MSC_VER)
847 #include <unistd.h>
848 #endif
849 
850 #include "pcdbug.h"
851 #include "sock_ini.h"
852 
853 /*
854  * Print list of hosts unsorted.
855  */
856 static void print_hosts (void)
857 {
858  const struct _hostent *h;
859 
860  for (h = host0; h; h = h->h_next)
861  {
862  int i;
863 
864  printf ("address %-17.17s name %s;",
865  inet_ntoa(*(struct in_addr*)&h->h_address[0]), h->h_name);
866 
867  for (i = 0; h->h_aliases[i]; i++)
868  {
869  if (i == 0)
870  printf (" Aliases:");
871  printf (" %s,", h->h_aliases[i]);
872  }
873  puts ("");
874  }
875  fflush (stdout);
876 }
877 
878 void do_sleep (int time)
879 {
880  while (time)
881  {
882  if (kbhit())
883  {
884  int ch = getch();
885  if (ch == 27 || ch == 'q')
886  {
887  fputc ('\n', stderr);
888  return;
889  }
890  }
891  fprintf (stderr, "%4d", time--);
892 #ifdef WIN32
893  Sleep (1000);
894 #else
895  sleep (1);
896 #endif
897  tcp_tick (NULL); /* empty rx-buffers */
898  fprintf (stderr, "\b\b\b\b");
899  }
900 }
901 
902 int main (void)
903 {
904  const struct hostent *h;
905  const char *host_name = "test-host"; /* This doesn't exist in real life */
906  int wait_time;
907  DWORD addr_list [MAX_ADDRESSES+1];
908 
909  dbug_init();
910  sock_init();
911  print_hosts();
912 
913  wait_time = netdbCacheLife + 1;
914  memset (&addr_list, 0, sizeof(addr_list));
915  addr_list[0] = htonl (_inet_addr("80.22.33.45"));
916  addr_list[1] = htonl (_inet_addr("222.22.33.46"));
917  addr_list[2] = htonl (_inet_addr("217.22.33.47"));
918  addr_list[3] = htonl (_inet_addr("81.22.33.48"));
919  addr_list[4] = INADDR_NONE;
920 
921  SOCK_DEBUGF (("\nadd_hostent: `%s'", host_name));
922  add_hostent (NULL, host_name, "some.cname.org", &addr_list[1],
923  addr_list[0], netdbCacheLife, FALSE);
924  h = gethostbyname (host_name);
925  if (!h)
926  {
927  fprintf (stderr, "gethostbyname() failed!. h_errno = %d\n", h_errno);
928  return (1);
929  }
930  fprintf (stderr, "Waiting for cache-entry to timeout..");
931  do_sleep (wait_time);
932 
933  fprintf (stderr, "gethostbyname() should do a DNS lookup now.\n");
934 
935  /* Since "test-host" doesn't exist in real life, a new lookup should fail.
936  * If 'h != NULL', it should mean the cached entry didn't timeout.
937  */
938  h = gethostbyname (host_name);
939  if (h)
940  fprintf (stderr, "entry didn't timeout!.\n");
941 
942 #if defined(USE_FORTIFY)
943  Fortify_ListAllMemory();
944  Fortify_OutputStatistics();
945 #endif
946 
947  return (0);
948 }
949 #endif /* TEST_PROG */
950 #endif /* USE_BSD_API */
951 
struct hostent *W32_CALL gethostent(void)
Return the next (non-commented) line from the host-file.
Definition: gethost.c:218
const char *W32_CALL GetHostsFile(void)
Return name of hosts-file.
Definition: gethost.c:187
char * strltrim(const char *s)
Return pointer to first non-blank (space/tab) in a string.
Definition: strings.c:243
Definition: netdb.h:102
void W32_CALL ReopenHostFile(void)
Reopen hosts-file.
Definition: gethost.c:208
Core definitions.
char * _strlcpy(char *dst, const char *src, size_t len)
Similar to strncpy(), but always returns 'dst' with 0-termination.
Definition: strings.c:226
void W32_CALL CloseHostFile(void)
Close hosts-file.
Definition: gethost.c:197
DWORD sin_mask
our net-mask, 255.255.255.0
Definition: pctcp.c:71
Definition: in.h:153
Definition: ip.h:67
XHOSTID_RETV W32_CALL gethostid(void)
BSD style: returns local IPv4-address.
Definition: bsdname.c:68
Definition: in.h:146
BOOL W32_CALL isaddr(const char *str)
Check if 'str' is simply an ip address.
Definition: netaddr.c:128
static BOOL gethostbyname_internal(const char *name, const char **alias, struct _hostent *ret)
Definition: gethost.c:306
DWORD W32_CALL _inet_addr(const char *s)
Convert a string into an IP-address.
Definition: netaddr.c:69
char hostname[MAX_HOSTLEN+1]
Our configured hostname.
Definition: pctcp.c:59
BOOL called_from_resolve
Hacks to make gethostbyname() and resolve() cooperate.
Definition: pcdns.c:60
const char *W32_CALL dom_strerror(int err)
Return text for error code (dom_errno).
Definition: pcdns.c:746
BOOL _watt_fatal_error
Definition: misc.c:60
const char * _inet6_ntoa(const void *ip)
Convert an IPv6-address 'ip' into a string.
Definition: netaddr.c:401
int netdb_init(void)
Called from most <netdb.h> functions in case watt_sock_init() wasn't called first to initialise things...
Definition: pcconfig.c:1215
static BOOL gethostbyaddr_internal(const char *addr_name, int len, int type, struct _hostent *ret)
Definition: gethost.c:512
WORD W32_CALL tcp_tick(sock_type *s)
Must be called periodically by user application (or BSD socket API).
Definition: pctcp.c:1389
DWORD W32_CALL resolve(const char *name)
Convert host name to an address.
Definition: pcdns.c:775
int main(int argc, char **argv)
Definition: echo.c:223