#if !defined(lint) && !defined(__INSIGHT__)
static char sos__rcsid[] = "gethbyfoo.c,v 1.1.1.1 1995/06/16 17:42:41 seth Exp";
static char sos__copyright[] = "Copyright (c) 1994, 1995 SOS Corporation";
static char sos__contact[] = "SOS Corporation <sos-info@soscorp.com> +1 800 SOS UNIX";
#endif /* not lint */

/*
 * ++Copyright Released Product++
 *
 * Copyright (c) 1994, 1995 Sources of Supply Corporation ("SOS").
 * All rights reserved.
 *
 * The SOS Released Product License Agreement specifies the terms and
 * conditions for redistribution.  You may find the License Agreement
 * in the file LICENSE.
 *
 * SOS Corporation
 * 461 5th Ave.; 16th floor
 * New York, NY 10017
 *
 * +1 800 SOS UNIX
 * <sos-info@soscorp.com>
 *
 * --Copyright Released Product--
 */

/*
 * SOS General routines to perform host/service lookups
 * given any form of host/service identification
 * (e.g. name, number, etc)
 */

#include "sos.h"


/*
 * Get a hostent no matter what we are passed
 *
 * Requires DNS
 *
 * (Use getmcbyfoo for !DNS version, sort of)
 */
struct hostent *sos_gethbyfoo(char *x)
{
  struct hostent *ret;

  if (!x) return(NULL);

  if (isdigit(*x))
    {				/* Might be a dotted quad */
      struct in_addr val;

      if (inet_aton(x, &val) == 1)
	{			/* Valid address */
	  ret = gethostbyaddr((char *)&(val.s_addr),sizeof(val.s_addr),AF_INET);
	  return(ret);
	}
    }

  /* It is not an address--might be a hostname */
  ret = gethostbyname(x);
  return(ret);
}



/*
 * Get a host address no matter what we are passed
 */
int sos_getabyfoo(char *x, struct in_addr *iaddr)
{
  struct hostent *ret;

  /* If it is a raw IP address, we return it immediately */
  if (isdigit(*x))
    {				/* Might be a dotted quad */
      struct in_addr val;

      if (inet_aton(x,&val) == 1)
	{			/* Valid address */
	  memcpy((char *)iaddr, (char *)&val, sizeof(val));
	  return(0);
	}
    }

  if ((ret = sos_gethbyfoo(x)) == NULL)
    {
      return(-1);
    }

  /* Should we verify this somehow? */
  iaddr->s_addr = **(unsigned long **)ret->h_addr_list;

  return(0);
}



/*
 * Get a make-conn type of hostent
 *
 * Like gethbyfoo, except that explicit IP addresses get
 * a fake hostent and do NOT go through DNS
 */
struct hostent *sos_getmcbyfoo(char *x)
{
  static struct hostent stat_host;
  static unsigned long stat_addr[2], *paddr[2];
  static char *halias[1];
  struct hostent *ret;

  if (!x) return(NULL);

  if (isdigit(*x))
    {				/* Might be a dotted quad */
      struct in_addr val;

      if (inet_aton(x, &val) == 1)
	{			/* Valid address */
	  stat_addr[0] = val.s_addr;
	  stat_addr[1] = 0;
	  paddr[0] = &(stat_addr[0]);
	  paddr[1] = &(stat_addr[1]);
	  halias[0] = NULL;
	  stat_host.h_name = x;
	  stat_host.h_aliases = halias;
	  stat_host.h_addrtype = AF_INET;
	  stat_host.h_length = sizeof(struct in_addr);
	  stat_host.h_addr_list = (char **)paddr;

	  return(&stat_host);
	}
    }

  /* It is not an address--might be a hostname */
  ret = gethostbyname(x);
  return(ret);
}



/*
 * Get a hostname no matter what we are passed
 */
char *sos_getnbyfoo(char *x, char *buf, int blen)
{
  struct hostent *ret;

  if ((ret = sos_gethbyfoo(x)) == NULL)
    {
      /* If it is a raw IP address without a PTR, we return that */
      if (isdigit(*x))
	{			/* might be a dotted quad */
	  struct in_addr val;

	  if (inet_aton(x, &val) == 1)
	    {			/* Valid address */
	      return(x);
	    }
	}
      return(NULL);
    }

  /* Should we verify this somehow? */
  if (!buf)
    return((char *)ret->h_name);

  strncpy(buf,ret->h_name,blen);
  return(buf);
}



/*
 * Generate an SOS-style hostname (FQDN [q.u.a.d]) from a in_addr into a static buffer
 */
char *sos_getnbyaddr(struct in_addr in)
{
  struct hostent *ret;
  char *quad = inet_ntoa(in);
  static char sspace[MAXHOSTNAMELEN + 18 + 1];

  if ((ret = sos_gethbyfoo(quad)) == NULL)
    {
      /* No reverse DNS (sigh) */
      sprintf(sspace,"[%s]",quad);
    }
  else
    {
      sprintf(sspace,"%s [%s]",ret->h_name,quad);
    }
  return(sspace);
}



/*
 * Get a service number no matter what we are passed
 */
int sos_getsbyfoo(char *x)
{
  struct servent *serv;
  int ret;

  /* check for numeric ID */
  if (isdigit(*x)) 
    {
      char *stop;

      ret = (int)strtol(x,&stop,10);

      if (stop && *stop == '\0')
	return(ret);
    }

  if (!(serv=getservbyname(x,"tcp")))
    return(-1);

  /* Getservbyname returns port in network order */
  ret = ntohs(serv->s_port);

  return(ret);
}



/*
 * Get hostname for peer
 *
 * Note:  sourceinfo.printhost is strdupped (mallocs memory)
 */
int sos_getpeername(int sourcefd, struct sos_conninfo *sourceinfo)
{
  struct sockaddr name;
  int namelen = sizeof(name);
  
  sourceinfo->fd = sourcefd;
  sourceinfo->port = -1;

  if (getpeername(sourcefd, &name, &namelen) < 0)
    {
      return(-1);
    }
  else
    {
      struct sockaddr_in inet_addr;

      if (name.sa_family != AF_INET)
	{
	  return(-1);
	}

      memcpy((char *)&inet_addr, (char *)&name, sizeof(inet_addr));

      sourceinfo->port = ntohs(inet_addr.sin_port);
      memcpy((char *)&(sourceinfo->addr),(char *)&(inet_addr.sin_addr),sizeof(struct in_addr));

      sourceinfo->printhost = strdup(sos_getnbyaddr(inet_addr.sin_addr));
    }

  return(0);
}



/*
 * Make a struct sos_conninfo from an arbitrary string (uses sos_gethbyfoo
 * as an intermediary. Returns *first* address in the list (UGGH!!!). 
 *
 * Mallocs memory (strdup)
 */
int 
sos_makeprinthost(int fd, 
		  int port, 
		  char *hoststr, 
		  struct sos_conninfo *conninfo)
{
  struct hostent *h;		/* Intermediary form of address. */

  if ( (h = sos_gethbyfoo(hoststr)) ==  (struct hostent *)NULL)
    {
      struct in_addr val;
      if (isdigit(*hoststr))
	{			/* Might be a dotted quad */
	  if (inet_aton(hoststr, &val) == 1)
	    {			/* Valid address */
	      memcpy((char *)&(conninfo->addr), 
		     (char *)&(val.s_addr),
		     sizeof(sizeof(struct in_addr)));
	    }
	  else
	    {			/* Not a valid dotted quad */
	      return -1;
	    }
	}
      else
	{			/* Not a dotted quad */
	  return -1;
	}
    }
  else
    {
      memcpy((char *)&(conninfo->addr), 
	     h->h_addr_list[0],
	     sizeof(struct in_addr));
    }

  memset(conninfo, (char)0, sizeof(conninfo));

  conninfo->fd = fd;
  conninfo->port = port;

  conninfo->printhost = strdup(sos_getnbyaddr(conninfo->addr));

  return 0;
}



/*
 * Make a struct sos_conninfo from a sockaddr
 *
 * Mallocs memory (strdup)
 */
int 
sos_makeprinthostfromaddr(int fd, 
		  int port, 
		  struct sockaddr_in *addr,
		  struct sos_conninfo *conninfo)
{
  memset(conninfo, (char)0, sizeof(conninfo));

  conninfo->fd = fd;
  conninfo->port = port;
  memcpy((char *)&(conninfo->addr), 
	 (char *)&(addr->sin_addr),
	 sizeof(addr->sin_addr));

  conninfo->printhost = strdup(sos_getnbyaddr(conninfo->addr));

  return 0;
}
