#define I_MEMORY
#include "includes.h"

/* This intended to speedup hostname lookups by keeping a list of
 * already known hostnames.  The translations is:
 *   gethostbyaddr(addr,len,type) --> host_lookup(addr,len,type,0,NULL)
 *   gethostbyname(name)          --> host_lookup(name,0,AF_INET,0,NULL)
 *
 *    how -->  0 is for local network lookups, 1 is for special lookups.
 *    add_hp --> Only makes sense with "how=1".  This specifies that if
 *               the host isn't already listed, add this host lookup
 *		 to the table of hostnames.
 *
 * The main advantage of this routine is the lookup table avoids saves time
 * by avoiding networking calls to get addresses we already know.  The main
 * disadvantage is that if there is a problem with the named server, the
 * client program won't check again later to see if it has been resolved.
 */

struct hostent *host_lookup(char *addr,int length, int type, int how,
    struct hostent *add_hp) {
  int i, j, k;
  static int num_hosts = 0;
  struct hostent *hp = NULL;
  typedef struct {
	struct hostent hs;
	unsigned long ip_addr;
        int active, how, h_errno;
    } Hosts_type;
  static Hosts_type *Hosts = NULL;
  extern int h_errno;

  if (type != AF_INET || ! addr) {
    if (! length) 
      return hp = gethostbyname(addr);
    else
      return hp = gethostbyaddr(addr, length, type);
  }

  if (! length) {
    for(i=0;i < num_hosts; ++i) 
      if (Hosts[i].hs.h_name && how == Hosts[i].how) {
        if (! strcmp(addr,Hosts[i].hs.h_name)) break;
	if (! Hosts[i].hs.h_aliases) continue;
        for(j = 0; Hosts[i].hs.h_aliases[j]; j++) 
          if (! strcmp(addr,Hosts[i].hs.h_aliases[j]) ) break;
        if (Hosts[i].hs.h_aliases[j]) break;
      }
  }else  {
    for(i=0;i < num_hosts; ++i) 
      if (Hosts[i].ip_addr != ~0 && how == Hosts[i].how) {
        if (! memcmp(addr,&Hosts[i].ip_addr,length)) break;
	if (! Hosts[i].hs.h_addr_list) continue;
	for(j = 0; Hosts[i].hs.h_addr_list[j]; j++) 
          if (! memcmp(addr,Hosts[i].hs.h_addr_list[j],length)) break;
        if (Hosts[i].hs.h_addr_list[j]) break;
      }
  }

  if (i < num_hosts) {
    if (Hosts[i].active) return &Hosts[i].hs;
    h_errno = Hosts[i].h_errno;
    return NULL;
  }

  if (how && ! add_hp) return NULL;

  if (!Hosts) 
    Hosts = (Hosts_type *) malloc(sizeof(Hosts_type));
  else 
    Hosts = (Hosts_type *) realloc((char *) Hosts, (num_hosts + 1) *
                                   sizeof(Hosts_type)); 
  memset(&Hosts[(i = num_hosts++)],0,sizeof(Hosts_type));


  Hosts[i].hs.h_addrtype = AF_INET;
  Hosts[i].hs.h_name = NULL;
  Hosts[i].how = how;
  Hosts[i].ip_addr = ~0;
  Hosts[i].hs.h_aliases = NULL;
  if (! how) {
    if (! length) 
      hp = gethostbyname(addr);
    else
      hp = gethostbyaddr(addr, length, AF_INET);
  }else {
    hp = add_hp;
  }

  Hosts[i].active = 0;
  if (! hp) {
    char *s = NULL;
    Hosts[i].h_errno = h_errno;
    Hosts[i].hs.h_length = sizeof(unsigned long);
    if (! length) {
      if ((s = (char *)malloc(strlen(addr)+2))) {
        strcpy(s,addr);
        s[strlen(s)+1] = 0;
        Hosts[i].hs.h_name = s;
      }
    }else {
      memcpy(&Hosts[i].ip_addr,addr,length);
    }
    return NULL;
  }
  Hosts[i].h_errno = 0;
  Hosts[i].hs.h_length = hp->h_length;
  if (hp->h_addrtype != AF_INET) return hp;

	/* Copy the list of aliases */


  for(k=j=0; hp->h_aliases[j]; ++j)
    k += 1 + strlen(hp->h_aliases[j]);

  if ((Hosts[i].hs.h_aliases = (char **)malloc((j+1) * sizeof(char *)))) {
    char *s = NULL;
    if ((s = (char *)malloc(k))) {
      for(j=0; hp->h_aliases[j]; ++j) {
        strcpy(s,hp->h_aliases[j]);
        Hosts[i].hs.h_aliases[j] = s;
        s += strlen(s) + 1;
      }
      Hosts[i].hs.h_aliases[j] = NULL;
    }else {
      Hosts[i].hs.h_aliases[0] = NULL;
    }
  }
	/* Copy the list of addresses */

  for(k=j=0; hp->h_addr_list[j]; ++j)
    k += hp->h_length;

  if ((Hosts[i].hs.h_addr_list = (char **)malloc((j+1) * sizeof(char *)))) {
    char *s = NULL;
    if ((s = (char *)malloc(k))) {
      for(j=0; hp->h_addr_list[j]; ++j) {
        unsigned long l;
        memcpy(s,hp->h_addr_list[j],hp->h_length);
        Hosts[i].hs.h_addr_list[j] = s;
	memcpy(&l,s,hp->h_length);
        s += hp->h_length;
      }
      Hosts[i].hs.h_addr_list[j] = NULL;
    }else {
      Hosts[i].hs.h_addr_list[0] = NULL;
    }
  }

	/* Make sure the input is part of the stored entry */

  if (! length) {
    memcpy(&Hosts[i].ip_addr,Hosts[i].hs.h_addr,hp->h_length);
    Hosts[i].hs.h_name = (char *) malloc(strlen(addr)+1);
    strcpy((char *)Hosts[i].hs.h_name, addr);
  }else {
    memcpy(&Hosts[i].ip_addr,addr,sizeof(Hosts[i].ip_addr)); 
    Hosts[i].hs.h_name = (char *) malloc(strlen(hp->h_name)+1);
    strcpy((char *)Hosts[i].hs.h_name, hp->h_name);
  }
  Hosts[i].active = 1;
  return hp;
}




