Commit 0ce97f77 authored by Yang Tse's avatar Yang Tse
Browse files

Use our Curl_addrinfo definition even when an addrinfo struct is available.

Use a wrapper function to call system's getaddrinfo().
parent 197ad60d
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -9,7 +9,7 @@ CSOURCES = file.c timeval.c base64.c hostip.c progress.c formdata.c \
  http_negotiate.c http_ntlm.c inet_pton.c strtoofft.c strerror.c	\
  hostares.c hostasyn.c hostip4.c hostip6.c hostsyn.c hostthre.c	\
  inet_ntop.c parsedate.c select.c gtls.c sslgen.c tftp.c splay.c	\
  strdup.c socks.c ssh.c nss.c qssl.c rawstr.c
  strdup.c socks.c ssh.c nss.c qssl.c rawstr.c curl_addrinfo.c

HHEADERS = arpa_telnet.h netrc.h file.h timeval.h qssl.h hostip.h	\
  progress.h formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h	\
@@ -20,4 +20,4 @@ HHEADERS = arpa_telnet.h netrc.h file.h timeval.h qssl.h hostip.h \
  strtoofft.h strerror.h inet_ntop.h curlx.h memory.h setup.h		\
  transfer.h select.h easyif.h multiif.h parsedate.h sslgen.h gtls.h	\
  tftp.h sockaddr.h splay.h strdup.h setup_once.h socks.h ssh.h nssg.h	\
  curl_base64.h rawstr.h
  curl_base64.h rawstr.h curl_addrinfo.h

lib/curl_addrinfo.c

0 → 100644
+332 −0
Original line number Diff line number Diff line
/***************************************************************************
 *                                  _   _ ____  _
 *  Project                     ___| | | |  _ \| |
 *                             / __| | | | |_) | |
 *                            | (__| |_| |  _ <| |___
 *                             \___|\___/|_| \_\_____|
 *
 * Copyright (C) 1998 - 2008, Daniel Stenberg, <daniel@haxx.se>, et al.
 *
 * This software is licensed as described in the file COPYING, which
 * you should have received as part of this distribution. The terms
 * are also available at http://curl.haxx.se/docs/copyright.html.
 *
 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
 * copies of the Software, and permit persons to whom the Software is
 * furnished to do so, under the terms of the COPYING file.
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 * $Id$
 ***************************************************************************/

#include "setup.h"

#include <curl/curl.h>

#ifdef NEED_MALLOC_H
#  include <malloc.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
#  include <sys/socket.h>
#endif
#ifdef HAVE_NETINET_IN_H
#  include <netinet/in.h>
#endif
#ifdef HAVE_NETDB_H
#  include <netdb.h>
#endif
#ifdef HAVE_ARPA_INET_H
#  include <arpa/inet.h>
#endif

#ifdef  VMS
#  include <in.h>
#  include <inet.h>
#  include <stdlib.h>
#endif

#if defined(NETWARE) && defined(__NOVELL_LIBC__)
#  undef  in_addr_t
#  define in_addr_t unsigned long
#endif

#include "curl_addrinfo.h"

#define _MPRINTF_REPLACE /* use our functions only */
#include <curl/mprintf.h>

#include "memory.h"
/* The last #include file should be: */
#include "memdebug.h"


/*
 * Curl_freeaddrinfo()
 *
 * This is used to free a linked list of Curl_addrinfo structs along
 * with all its associated allocated storage. This function should be
 * called once for each successful call to Curl_getaddrinfo_ex() or to
 * any function call which actually allocates a Curl_addrinfo struct.
 */

void
Curl_freeaddrinfo(Curl_addrinfo *cahead)
{
  Curl_addrinfo *ca, *canext;

  for(ca = cahead; ca != NULL; ca = canext) {

    if(ca->ai_addr)
      free(ca->ai_addr);

    if(ca->ai_canonname)
      free(ca->ai_canonname);

    canext = ca->ai_next;

    free(ca);
  }
}


#ifdef HAVE_GETADDRINFO
/*
 * Curl_getaddrinfo_ex()
 *
 * This is a warapper function around system's getaddrinfo(), with
 * the only difference that instead of returning a linked list of
 * addrinfo structs this one returns a linked list of Curl_addrinfo
 * ones. The memory allocated by this function *MUST* be free'd with
 * Curl_freeaddrinfo().  For each successful call to this function
 * there must be an associated call later to Curl_freeaddrinfo().
 *
 * There should be no single call to system's getaddrinfo() in the
 * whole library, any such call should be 'routed' through this one.
 */

int
Curl_getaddrinfo_ex(const char *nodename,
                    const char *servname,
                    const struct addrinfo *hints,
                    Curl_addrinfo **result)
{
  const struct addrinfo *ainext;
  const struct addrinfo *ai;
  struct addrinfo *aihead;
  Curl_addrinfo *cafirst = NULL;
  Curl_addrinfo *calast = NULL;
  Curl_addrinfo *ca;
  int error;

  *result = NULL; /* assume failure */

  error = getaddrinfo(nodename, servname, hints, &aihead);
  if(error)
    return error;

  for(ai = aihead; ai != NULL; ai = ainext) {

    if((ca = malloc(sizeof(Curl_addrinfo))) == NULL) {
      error = EAI_MEMORY;
      break;
    }

    /* copy each structure member individually, member ordering, */
    /* size, or padding might be different for each structure.   */

    ca->ai_flags     = ai->ai_flags;
    ca->ai_family    = ai->ai_family;
    ca->ai_socktype  = ai->ai_socktype;
    ca->ai_protocol  = ai->ai_protocol;
    ca->ai_addrlen   = 0;
    ca->ai_addr      = NULL;
    ca->ai_canonname = NULL;
    ca->ai_next      = NULL;

    if((ai->ai_addrlen > 0) && (ai->ai_addr != NULL)) {
      ca->ai_addrlen  = ai->ai_addrlen;
      if((ca->ai_addr = malloc(ca->ai_addrlen)) == NULL) {
        error = EAI_MEMORY;
        free(ca);
        break;
      }
      memcpy(ca->ai_addr, ai->ai_addr, ca->ai_addrlen);
    }

    if(ai->ai_canonname != NULL) {
      if((ca->ai_canonname = strdup(ai->ai_canonname)) == NULL) {
        error = EAI_MEMORY;
        if(ca->ai_addr)
          free(ca->ai_addr);
        free(ca);
        break;
      }
    }

    /* if the return list is empty, this becomes the first element */
    if(!cafirst)
      cafirst = ca;

    /* add this element last in the return list */
    if(calast)
      calast->ai_next = ca;
    calast = ca;

    /* fetch next element fom the addrinfo list */
    ainext = ai->ai_next;
  }

  /* destroy the addrinfo list */
  if(aihead)
    freeaddrinfo(aihead);

  /* if we failed, also destroy the Curl_addrinfo list */
  if(error) {
    Curl_freeaddrinfo(cafirst);
    cafirst = NULL;
  }

  *result = cafirst;

  return error; /* This is not a CURLcode */
}
#endif /* HAVE_GETADDRINFO */


/*
 * Curl_he2ai()
 *
 * This function returns a pointer to the first element of a newly allocated
 * Curl_addrinfo struct linked list filled with the data of a given hostent.
 * Curl_addrinfo is meant to work like the addrinfo struct does for a IPv6
 * stack, but usable also for IPv4, all hosts and environments.
 *
 * The memory allocated by this function *MUST* be free'd later on calling
 * Curl_freeaddrinfo().  For each successful call to this function there
 * must be an associated call later to Curl_freeaddrinfo().
 *
 *   Curl_addrinfo defined in "lib/curl_addrinfo.h"
 *
 *     struct Curl_addrinfo {
 *       int                   ai_flags;
 *       int                   ai_family;
 *       int                   ai_socktype;
 *       int                   ai_protocol;
 *       socklen_t             ai_addrlen;   * Follow rfc3493 struct addrinfo *
 *       char                 *ai_canonname;
 *       struct sockaddr      *ai_addr;
 *       struct Curl_addrinfo *ai_next;
 *     };
 *     typedef struct Curl_addrinfo Curl_addrinfo;
 *
 *   hostent defined in <netdb.h>
 *
 *     struct hostent {
 *       char    *h_name;
 *       char    **h_aliases;
 *       int     h_addrtype;
 *       int     h_length;
 *       char    **h_addr_list;
 *     };
 *
 *   for backward compatibility:
 *
 *     #define h_addr  h_addr_list[0]
 */

Curl_addrinfo *
Curl_he2ai(const struct hostent *he, int port)
{
  Curl_addrinfo *ai;
  Curl_addrinfo *prevai = NULL;
  Curl_addrinfo *firstai = NULL;
  struct sockaddr_in *addr;
#ifdef ENABLE_IPV6
  struct sockaddr_in6 *addr6;
#endif
  CURLcode result = CURLE_OK;
  int i;
  char *curr;

  if(!he)
    /* no input == no output! */
    return NULL;

  for(i=0; (curr = he->h_addr_list[i]) != NULL; i++) {

    int ss_size;
#ifdef ENABLE_IPV6
    if (he->h_addrtype == AF_INET6)
      ss_size = sizeof (struct sockaddr_in6);
    else
#endif
      ss_size = sizeof (struct sockaddr_in);

    if((ai = calloc(1, sizeof(Curl_addrinfo))) == NULL) {
      result = CURLE_OUT_OF_MEMORY;
      break;
    }
    if((ai->ai_canonname = strdup(he->h_name)) == NULL) {
      result = CURLE_OUT_OF_MEMORY;
      free(ai);
      break;
    }
    if((ai->ai_addr = calloc(1, ss_size)) == NULL) {
      result = CURLE_OUT_OF_MEMORY;
      free(ai->ai_canonname);
      free(ai);
      break;
    }

    if(!firstai)
      /* store the pointer we want to return from this function */
      firstai = ai;

    if(prevai)
      /* make the previous entry point to this */
      prevai->ai_next = ai;

    ai->ai_family = he->h_addrtype;

    /* we return all names as STREAM, so when using this address for TFTP
       the type must be ignored and conn->socktype be used instead! */
    ai->ai_socktype = SOCK_STREAM;

    ai->ai_addrlen = ss_size;

    /* leave the rest of the struct filled with zero */

    switch (ai->ai_family) {
    case AF_INET:
      addr = (struct sockaddr_in *)ai->ai_addr; /* storage area for this info */

      memcpy(&addr->sin_addr, curr, sizeof(struct in_addr));
      addr->sin_family = (unsigned short)(he->h_addrtype);
      addr->sin_port = htons((unsigned short)port);
      break;

#ifdef ENABLE_IPV6
    case AF_INET6:
      addr6 = (struct sockaddr_in6 *)ai->ai_addr; /* storage area for this info */

      memcpy(&addr6->sin6_addr, curr, sizeof(struct in6_addr));
      addr6->sin6_family = (unsigned short)(he->h_addrtype);
      addr6->sin6_port = htons((unsigned short)port);
      break;
#endif
    }

    prevai = ai;
  }

  if(result != CURLE_OK) {
    /* Use parenthesis to prevent memdebug from replacing this */
    Curl_freeaddrinfo(firstai);
    firstai = NULL;
  }

  return firstai;
}

lib/curl_addrinfo.h

0 → 100644
+81 −0
Original line number Diff line number Diff line
#ifndef HEADER_CURL_ADDRINFO_H
#define HEADER_CURL_ADDRINFO_H
/***************************************************************************
 *                                  _   _ ____  _
 *  Project                     ___| | | |  _ \| |
 *                             / __| | | | |_) | |
 *                            | (__| |_| |  _ <| |___
 *                             \___|\___/|_| \_\_____|
 *
 * Copyright (C) 1998 - 2008, Daniel Stenberg, <daniel@haxx.se>, et al.
 *
 * This software is licensed as described in the file COPYING, which
 * you should have received as part of this distribution. The terms
 * are also available at http://curl.haxx.se/docs/copyright.html.
 *
 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
 * copies of the Software, and permit persons to whom the Software is
 * furnished to do so, under the terms of the COPYING file.
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 * $Id$
 ***************************************************************************/

#include "setup.h"

#ifdef HAVE_SYS_SOCKET_H
#  include <sys/socket.h>
#endif
#ifdef HAVE_NETINET_IN_H
#  include <netinet/in.h>
#endif
#ifdef HAVE_NETDB_H
#  include <netdb.h>
#endif
#ifdef HAVE_ARPA_INET_H
#  include <arpa/inet.h>
#endif

#ifdef  VMS
#  include <in.h>
#  include <inet.h>
#  include <stdlib.h>
#endif


/* 
 * Curl_addrinfo is our internal struct definition that we use to allow
 * consistent internal handling of this data. We use this even when the
 * system provides an addrinfo structure definition. And we use this for
 * all sorts of IPv4 and IPV6 builds.
 */

struct Curl_addrinfo {
  int                   ai_flags;
  int                   ai_family;
  int                   ai_socktype;
  int                   ai_protocol;
  socklen_t             ai_addrlen;   /* Follow rfc3493 struct addrinfo */
  char                 *ai_canonname;
  struct sockaddr      *ai_addr;
  struct Curl_addrinfo *ai_next;
};
typedef struct Curl_addrinfo Curl_addrinfo;

void
Curl_freeaddrinfo(Curl_addrinfo *cahead);

#ifdef HAVE_GETADDRINFO
int
Curl_getaddrinfo_ex(const char *nodename,
                    const char *servname,
                    const struct addrinfo *hints,
                    Curl_addrinfo **result);
#endif

Curl_addrinfo *
Curl_he2ai(const struct hostent *he, int port);

#endif /* HEADER_CURL_ADDRINFO_H */
+2 −2
Original line number Diff line number Diff line
@@ -5,7 +5,7 @@
 *                            | (__| |_| |  _ <| |___
 *                             \___|\___/|_| \_\_____|
 *
 * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
 * Copyright (C) 1998 - 2008, Daniel Stenberg, <daniel@haxx.se>, et al.
 *
 * This software is licensed as described in the file COPYING, which
 * you should have received as part of this distribution. The terms
@@ -160,7 +160,7 @@ CURLcode Curl_addrinfo6_callback(void *arg, /* "struct connectdata *" */
#ifdef HAVE_CARES_CALLBACK_TIMEOUTS
                                 int timeouts,
#endif
                                 struct addrinfo *ai)
                                 Curl_addrinfo *ai)
{
 /* NOTE: for CURLRES_ARES, the 'ai' argument is really a
  * 'struct hostent' pointer.
+4 −146
Original line number Diff line number Diff line
@@ -693,9 +693,11 @@ static void freednsentry(void *freethis)
{
  struct Curl_dns_entry *p = (struct Curl_dns_entry *) freethis;

  if(p) {
    Curl_freeaddrinfo(p->addr);
    free(p);
  }
}

/*
 * Curl_mk_dnscache() creates a new DNS cache and returns the handle for it.
@@ -729,25 +731,6 @@ Curl_addrinfo *Curl_addrinfo_copy(const void *org, int port)
 **********************************************************************/

#if defined(CURLRES_IPV4) || defined(CURLRES_ARES)
/*
 * This is a function for freeing name information in a protocol independent
 * way.
 */
void Curl_freeaddrinfo(Curl_addrinfo *ai)
{
  Curl_addrinfo *next;

  /* walk over the list and free all entries */
  while(ai) {
    next = ai->ai_next;
    if(ai->ai_addr)
      free(ai->ai_addr);
    if(ai->ai_canonname)
      free(ai->ai_canonname);
    free(ai);
    ai = next;
  }
}

struct namebuf4 {
  struct hostent hostentry;
@@ -825,129 +808,4 @@ Curl_addrinfo *Curl_ip2addr(in_addr_t num, const char *hostname, int port)
  return ai;
}

/*
 * Curl_he2ai() translates from a hostent struct to a Curl_addrinfo struct.
 * The Curl_addrinfo is meant to work like the addrinfo struct does for IPv6
 * stacks, but for all hosts and environments.
 *
 *   Curl_addrinfo defined in "lib/hostip.h"
 *
 *     struct Curl_addrinfo {
 *       int                   ai_flags;
 *       int                   ai_family;
 *       int                   ai_socktype;
 *       int                   ai_protocol;
 *       socklen_t             ai_addrlen;   * Follow rfc3493 struct addrinfo *
 *       char                 *ai_canonname;
 *       struct sockaddr      *ai_addr;
 *       struct Curl_addrinfo *ai_next;
 *     };
 *
 *   hostent defined in <netdb.h>
 *
 *     struct hostent {
 *       char    *h_name;
 *       char    **h_aliases;
 *       int     h_addrtype;
 *       int     h_length;
 *       char    **h_addr_list;
 *     };
 *
 *   for backward compatibility:
 *
 *     #define h_addr  h_addr_list[0]
 */

Curl_addrinfo *Curl_he2ai(const struct hostent *he, int port)
{
  Curl_addrinfo *ai;
  Curl_addrinfo *prevai = NULL;
  Curl_addrinfo *firstai = NULL;
  struct sockaddr_in *addr;
#ifdef CURLRES_IPV6
  struct sockaddr_in6 *addr6;
#endif /* CURLRES_IPV6 */
  CURLcode result = CURLE_OK;
  int i;
  char *curr;

  if(!he)
    /* no input == no output! */
    return NULL;

  for(i=0; (curr = he->h_addr_list[i]) != NULL; i++) {

    int ss_size;
#ifdef CURLRES_IPV6
    if (he->h_addrtype == AF_INET6)
      ss_size = sizeof (struct sockaddr_in6);
    else
#endif /* CURLRES_IPV6 */
      ss_size = sizeof (struct sockaddr_in);

    if((ai = calloc(1, sizeof(Curl_addrinfo))) == NULL) {
      result = CURLE_OUT_OF_MEMORY;
      break;
    }
    if((ai->ai_canonname = strdup(he->h_name)) == NULL) {
      result = CURLE_OUT_OF_MEMORY;
      free(ai);
      break;
    }
    if((ai->ai_addr = calloc(1, ss_size)) == NULL) {
      result = CURLE_OUT_OF_MEMORY;
      free(ai->ai_canonname);
      free(ai);
      break;
    }

    if(!firstai)
      /* store the pointer we want to return from this function */
      firstai = ai;

    if(prevai)
      /* make the previous entry point to this */
      prevai->ai_next = ai;

    ai->ai_family = he->h_addrtype;

    /* we return all names as STREAM, so when using this address for TFTP
       the type must be ignored and conn->socktype be used instead! */
    ai->ai_socktype = SOCK_STREAM;

    ai->ai_addrlen = ss_size;

    /* leave the rest of the struct filled with zero */

    switch (ai->ai_family) {
    case AF_INET:
      addr = (struct sockaddr_in *)ai->ai_addr; /* storage area for this info */

      memcpy(&addr->sin_addr, curr, sizeof(struct in_addr));
      addr->sin_family = (unsigned short)(he->h_addrtype);
      addr->sin_port = htons((unsigned short)port);
      break;

#ifdef CURLRES_IPV6
    case AF_INET6:
      addr6 = (struct sockaddr_in6 *)ai->ai_addr; /* storage area for this info */

      memcpy(&addr6->sin6_addr, curr, sizeof(struct in6_addr));
      addr6->sin6_family = (unsigned short)(he->h_addrtype);
      addr6->sin6_port = htons((unsigned short)port);
      break;
#endif /* CURLRES_IPV6 */
    }

    prevai = ai;
  }

  if(result != CURLE_OK) {
    Curl_freeaddrinfo(firstai);
    firstai = NULL;
  }

  return firstai;
}

#endif /* CURLRES_IPV4 || CURLRES_ARES */
Loading