/*
 * getaddrinfo(2) emulation.
 * Copyright (C) 1988, 1989, 1992, 1993 Free Software Foundation, Inc.

This file is not part of any package.

GNU Emacs is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.

GNU Emacs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with GNU Emacs; see the file COPYING.  If not, write to
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
 */

#ifdef HAVE_CONFIG_H
#  include "config.h"
#endif

#ifndef HAVE_GETADDRINFO

#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>

#ifdef HAVE_NETINET6_IN6_H
# include <netinet6/in6.h>
#endif /* HAVE_NETINET6_IN6_H */

#include "getaddrinfo.h"

int getaddrinfo (hostname, servname, hints, res)
  const char *hostname;
  const char *servname;
  const struct addrinfo *hints;
  struct addrinfo **res;
{
  struct hostent *host = NULL;
  struct servent *serv = NULL;
  struct protoent *proto;
  int port = 0;

#if (defined (HAVE_SOCKADDR_IN6) && defined (INET6))
  struct sockaddr_in6 *sin =
    (struct sockaddr_in6 *) calloc (1, sizeof (struct sockaddr_in6));
#else /* (defined (HAVE_SOCKADDR_IN6) && defined (INET6)) */
  struct sockaddr_in *sin =
    (struct sockaddr_in *) calloc (1, sizeof (struct sockaddr_in));
#endif /* !(defined (HAVE_SOCKADDR_IN6) && defined (INET6)) */

  struct addrinfo *ai = *res = 
    (struct addrinfo *) calloc (1, sizeof (struct addrinfo));
  
  if ((~ hints->ai_flags & AI_PASSIVE) && hostname && 
      (host = gethostbyname (hostname)) == NULL) {
    perror ("gethostbyname");
    return EAI_NONAME;
  }

  if (hints->ai_protocol && 
      (proto = getprotobynumber (hints->ai_protocol)) == NULL) {
    perror ("getprotobynumber");
    return EAI_NONAME;
  }

  if (servname) 
    if (isdigit (servname[0]))
      port = atoi (servname);
    else {
      if ((serv = getservbyname (servname, proto->p_name)) == NULL) {
	perror ("getservbyname");
	return EAI_NONAME;
      }
      port = serv->s_port;
    }
  
#if (defined (HAVE_SOCKADDR_IN6) && defined (INET6))
  if (host)
    memcpy (&sin->sin6_addr, host->h_addr, host->h_length);
  sin->sin6_port = htons (port);
#else /* (defined (HAVE_SOCKADDR_IN6) && defined (INET6)) */
  if (host)
    memcpy (&sin->sin_addr, host->h_addr, host->h_length);
  sin->sin_port = htons (port);
#endif /* !(defined (HAVE_SOCKADDR_IN6) && defined (INET6)) */

  if (hints->ai_family == AF_UNSPEC)
    ai->ai_family = host->h_addrtype;
  else
    ai->ai_family = hints->ai_family;
#if (defined (HAVE_SOCKADDR_IN6) && defined (INET6))
  sin->sin6_family = ai->ai_family;
#else /* (defined (HAVE_SOCKADDR_IN6) && defined (INET6)) */
  sin->sin_family = ai->ai_family;
#endif /* !(defined (HAVE_SOCKADDR_IN6) && defined (INET6)) */

  ai->ai_protocol = hints->ai_protocol;
  ai->ai_socktype = hints->ai_socktype;
  ai->ai_addrlen = sizeof (*sin);
  ai->ai_addr = (struct sockaddr *)sin;

  return 0;
}

void freeaddrinfo (ai)
     struct addrinfo *ai;
{
  struct addrinfo *p;

  while (ai != NULL) {
    p = ai;
    ai = ai->ai_next;
    free (p);
  }
}

#endif /* HAVE_GETADDRINFO */


syntax highlighted by Code2HTML, v. 0.9.1