Curl_resolv() now returns a different struct, and it contains a reference

counter so that the caller needs to decrease that counter when done with
the returned data.

If compiled with MALLOCDEBUG I've added some extra checking that the counter
is decreased before a handle is closed etc.
This commit is contained in:
Daniel Stenberg 2002-11-05 10:51:41 +00:00
parent 73d996bf26
commit 2cff251863
10 changed files with 164 additions and 115 deletions

View File

@ -206,7 +206,7 @@ static CURLcode bindlocal(struct connectdata *conn,
*************************************************************/
if (strlen(data->set.device)<255) {
struct sockaddr_in sa;
Curl_addrinfo *h=NULL;
struct Curl_dns_entry *h=NULL;
size_t size;
char myhost[256] = "";
in_addr_t in;
@ -247,12 +247,17 @@ static CURLcode bindlocal(struct connectdata *conn,
if (INADDR_NONE != in) {
if ( h ) {
Curl_addrinfo *addr = h->addr;
h->inuse--; /* decrease the use-counter, we don't need it anymore
after this function has returned */
memset((char *)&sa, 0, sizeof(sa));
#ifdef ENABLE_IPV6
memcpy((char *)&sa.sin_addr, h->ai_addr, h->ai_addrlen);
sa.sin_family = h->ai_family;
memcpy((char *)&sa.sin_addr, addr->ai_addr, addr->ai_addrlen);
sa.sin_family = addr->ai_family;
#else
memcpy((char *)&sa.sin_addr, h->h_addr, h->h_length);
memcpy((char *)&sa.sin_addr, addr->h_addr, addr->h_length);
sa.sin_family = AF_INET;
#endif
sa.sin_addr.s_addr = in;
@ -410,7 +415,7 @@ CURLcode Curl_is_connected(struct connectdata *conn,
*/
CURLcode Curl_connecthost(struct connectdata *conn, /* context */
Curl_addrinfo *remotehost, /* use one in here */
struct Curl_dns_entry *remotehost, /* use this one */
int port, /* connect to this */
int *sockconn, /* the connected socket */
Curl_ipconnect **addr, /* the one we used */
@ -479,7 +484,7 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
struct addrinfo *ai;
port =0; /* prevent compiler warning */
for (ai = remotehost; ai; ai = ai->ai_next, aliasindex++) {
for (ai = remotehost->addr; ai; ai = ai->ai_next, aliasindex++) {
sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
if (sockfd < 0)
continue;

View File

@ -31,7 +31,7 @@ CURLcode Curl_is_connected(struct connectdata *conn,
bool *connected);
CURLcode Curl_connecthost(struct connectdata *conn,
Curl_addrinfo *host, /* connect to this */
struct Curl_dns_entry *host, /* connect to this */
int port, /* connect to this port number */
int *sockconn, /* not set if error is returned */
Curl_ipconnect **addr, /* the one we used */

View File

@ -1184,7 +1184,6 @@ CURLcode ftp_use_port(struct connectdata *conn)
*/
struct sockaddr_in sa;
struct hostent *h=NULL;
char *hostdataptr=NULL;
unsigned short porttouse;
char myhost[256] = "";
bool sa_filled_in = FALSE;
@ -1215,6 +1214,9 @@ CURLcode ftp_use_port(struct connectdata *conn)
sa_filled_in = TRUE; /* the sa struct is filled in */
}
if(h)
h->inuse--; /* when we return from here, we can forget about this */
if ( h || sa_filled_in) {
if( (portsock = socket(AF_INET, SOCK_STREAM, 0)) >= 0 ) {
int size;
@ -1250,19 +1252,16 @@ CURLcode ftp_use_port(struct connectdata *conn)
if ( listen(portsock, 1) < 0 ) {
failf(data, "listen(2) failed on socket");
free(hostdataptr);
return CURLE_FTP_PORT_FAILED;
}
}
else {
failf(data, "bind(2) failed on socket");
free(hostdataptr);
return CURLE_FTP_PORT_FAILED;
}
}
else {
failf(data, "socket(2) failed (%s)");
free(hostdataptr);
return CURLE_FTP_PORT_FAILED;
}
}
@ -1332,7 +1331,7 @@ CURLcode ftp_use_pasv(struct connectdata *conn,
char *buf = data->state.buffer; /* this is our buffer */
int ftpcode; /* receive FTP response codes in this */
CURLcode result;
Curl_addrinfo *addr=NULL;
struct Curl_dns_entry *addr=NULL;
Curl_ipconnect *conninfo;
/*
@ -1480,6 +1479,8 @@ CURLcode ftp_use_pasv(struct connectdata *conn,
&conninfo,
connected);
addr->inuse--; /* we're done using this address */
/*
* When this is used from the multi interface, this might've returned with
* the 'connected' set to FALSE and thus we are now awaiting a non-blocking

View File

@ -25,6 +25,7 @@
#include <string.h>
#include <stdlib.h>
#include "hash.h"
#include "llist.h"
@ -128,7 +129,6 @@ _mk_hash_element (curl_hash_element **e, char *key, size_t key_len, const void *
(*e)->key = strdup(key);
(*e)->key_len = key_len;
(*e)->ptr = (void *) p;
return 0;
}
/* }}} */
@ -195,10 +195,10 @@ Curl_hash_delete(curl_hash *h, char *key, size_t key_len)
}
/* }}} */
/* {{{ int curl_hash_find (curl_hash *, char *, size_t, void **)
/* {{{ int curl_hash_pick (curl_hash *, char *, size_t, void **)
*/
int
Curl_hash_find(curl_hash *h, char *key, size_t key_len, void **p)
void *
Curl_hash_pick(curl_hash *h, char *key, size_t key_len)
{
curl_llist_element *le;
curl_hash_element *he;
@ -209,12 +209,11 @@ Curl_hash_find(curl_hash *h, char *key, size_t key_len, void **p)
le = CURL_LLIST_NEXT(le)) {
he = CURL_LLIST_VALP(le);
if (_hash_key_compare(he->key, he->key_len, key, key_len)) {
*p = he->ptr;
return 1;
return he->ptr;
}
}
return 0;
return NULL;
}
/* }}} */
@ -222,7 +221,7 @@ Curl_hash_find(curl_hash *h, char *key, size_t key_len, void **p)
*/
void
Curl_hash_apply(curl_hash *h, void *user,
void (*cb)(void *, curl_hash_element *))
void (*cb)(void *user, void *ptr))
{
curl_llist_element *le;
int i;
@ -231,7 +230,8 @@ Curl_hash_apply(curl_hash *h, void *user,
for (le = CURL_LLIST_HEAD(h->table[i]);
le != NULL;
le = CURL_LLIST_NEXT(le)) {
cb(user, (curl_hash_element *) CURL_LLIST_VALP(le));
curl_hash_element *el = CURL_LLIST_VALP(le);
cb(user, el->ptr);
}
}
}

View File

@ -41,7 +41,7 @@ typedef struct _curl_hash {
typedef struct _curl_hash_element {
void *ptr;
char *key;
size_t key_len;
size_t key_len;
} curl_hash_element;
@ -49,15 +49,14 @@ void Curl_hash_init(curl_hash *, int, curl_hash_dtor);
curl_hash *Curl_hash_alloc(int, curl_hash_dtor);
int Curl_hash_add(curl_hash *, char *, size_t, const void *);
int Curl_hash_delete(curl_hash *h, char *key, size_t key_len);
int Curl_hash_find(curl_hash *, char *, size_t, void **p);
void Curl_hash_apply(curl_hash *h, void *user, void (*cb)(void *, curl_hash_element *));
void *Curl_hash_pick(curl_hash *, char *, size_t);
void Curl_hash_apply(curl_hash *h, void *user,
void (*cb)(void *user, void *ptr));
int Curl_hash_count(curl_hash *h);
void Curl_hash_clean(curl_hash *h);
void Curl_hash_clean_with_criterium(curl_hash *h, void *user, int (*comp)(void *, void *));
void Curl_hash_destroy(curl_hash *h);
#define Curl_hash_update Curl_hash_add
#endif
/*

View File

@ -80,6 +80,11 @@
static curl_hash hostname_cache;
static int host_cache_initialized;
static Curl_addrinfo *my_getaddrinfo(struct SessionHandle *data,
char *hostname,
int port,
char **bufp);
void Curl_global_host_cache_init(void)
{
if (!host_cache_initialized) {
@ -101,11 +106,6 @@ void Curl_global_host_cache_dtor(void)
}
}
struct curl_dns_cache_entry {
Curl_addrinfo *addr;
time_t timestamp;
};
/* count the number of characters that an integer takes up */
static int _num_chars(int i)
{
@ -129,7 +129,7 @@ static int _num_chars(int i)
/* Create a hostcache id */
static char *
_create_hostcache_id(char *server, int port, ssize_t *entry_len)
create_hostcache_id(char *server, int port, ssize_t *entry_len)
{
char *id = NULL;
@ -162,16 +162,19 @@ struct hostcache_prune_data {
};
static int
_curl_hostcache_timestamp_remove(void *datap, void *hc)
hostcache_timestamp_remove(void *datap, void *hc)
{
struct hostcache_prune_data *data =
(struct hostcache_prune_data *) datap;
struct curl_dns_cache_entry *c = (struct curl_dns_cache_entry *) hc;
struct Curl_dns_entry *c = (struct Curl_dns_entry *) hc;
if (data->now - c->timestamp < data->cache_timeout) {
if ((data->now - c->timestamp < data->cache_timeout) ||
c->inuse) {
/* please don't remove */
return 0;
}
/* fine, remove */
return 1;
}
@ -185,14 +188,30 @@ hostcache_prune(curl_hash *hostcache, int cache_timeout, int now)
Curl_hash_clean_with_criterium(hostcache,
(void *) &user,
_curl_hostcache_timestamp_remove);
hostcache_timestamp_remove);
}
#ifdef MALLOCDEBUG
/* Called from Curl_done() to check that there's no DNS cache entry with
a non-zero counter left. */
void Curl_scan_cache_used(void *user, void *ptr)
{
struct Curl_dns_entry *e = ptr;
(void)user; /* prevent compiler warning */
if(e->inuse) {
fprintf(stderr, "*** WARNING: locked DNS cache entry detected: %s\n",
e->entry_id);
/* perform a segmentation fault to draw attention */
*(void **)0 = 0;
}
}
#endif
/* Macro to save redundant free'ing of entry_id */
#define _hostcache_return(__v) \
#define HOSTCACHE_RETURN(dns) \
{ \
free(entry_id); \
return (__v); \
return dns; \
}
#ifdef HAVE_SIGSETJMP
@ -200,72 +219,69 @@ hostcache_prune(curl_hash *hostcache, int cache_timeout, int now)
sigjmp_buf curl_jmpenv;
#endif
Curl_addrinfo *Curl_resolv(struct SessionHandle *data,
char *hostname,
int port)
struct Curl_dns_entry *Curl_resolv(struct SessionHandle *data,
char *hostname,
int port)
{
char *entry_id = NULL;
struct curl_dns_cache_entry *p = NULL;
struct Curl_dns_entry *dns = NULL;
ssize_t entry_len;
time_t now;
char *bufp;
#ifdef HAVE_SIGSETJMP
if(sigsetjmp(curl_jmpenv, 1) != 0) {
/* this allows us to time-out from the name resolver, as the timeout
will generate a signal and we will siglongjmp() from that here */
if(!data->set.no_signal && sigsetjmp(curl_jmpenv, 1)) {
/* this is coming from a siglongjmp() */
failf(data, "name lookup time-outed");
return NULL;
}
#endif
#if 0
/* If the host cache timeout is 0, we don't do DNS cach'ing
so fall through */
if (data->set.dns_cache_timeout == 0) {
return Curl_getaddrinfo(data, hostname, port, &bufp);
}
#endif
/* Create an entry id, based upon the hostname and port */
entry_len = strlen(hostname);
entry_id = create_hostcache_id(hostname, port, &entry_len);
/* If we can't create the entry id, fail */
if (!entry_id)
return NULL;
/* See if its already in our dns cache */
dns = Curl_hash_pick(data->hostcache, entry_id, entry_len+1);
if (!dns) {
Curl_addrinfo *addr = my_getaddrinfo(data, hostname, port, &bufp);
if (!addr) {
HOSTCACHE_RETURN(NULL);
}
/* Create a new cache entry */
dns = (struct Curl_dns_entry *) malloc(sizeof(struct Curl_dns_entry));
if (!dns) {
Curl_freeaddrinfo(addr);
HOSTCACHE_RETURN(NULL);
}
dns->inuse = 0;
dns->addr = addr;
/* Save it in our host cache */
Curl_hash_add(data->hostcache, entry_id, entry_len+1, (const void *) dns);
}
time(&now);
/* Remove outdated entries from the hostcache */
dns->timestamp = now;
dns->inuse++; /* mark entry as in-use */
#ifdef MALLOCDEBUG
dns->entry_id = entry_id;
#endif
/* Remove outdated and unused entries from the hostcache */
hostcache_prune(data->hostcache,
data->set.dns_cache_timeout,
now);
/* Create an entry id, based upon the hostname and port */
entry_len = strlen(hostname);
entry_id = _create_hostcache_id(hostname, port, &entry_len);
/* If we can't create the entry id, don't cache, just fall-through
to the plain Curl_getaddrinfo() */
if (!entry_id) {
return Curl_getaddrinfo(data, hostname, port, &bufp);
}
/* See if its already in our dns cache */
if (entry_id &&
Curl_hash_find(data->hostcache, entry_id, entry_len+1, (void **) &p)) {
_hostcache_return(p->addr);
}
/* Create a new cache entry */
p = (struct curl_dns_cache_entry *)
malloc(sizeof(struct curl_dns_cache_entry));
if (!p) {
_hostcache_return(NULL);
}
p->addr = Curl_getaddrinfo(data, hostname, port, &bufp);
if (!p->addr) {
free(p);
_hostcache_return(NULL);
}
p->timestamp = now;
/* Save it in our host cache */
Curl_hash_update(data->hostcache, entry_id, entry_len+1, (const void *) p);
_hostcache_return(p->addr);
HOSTCACHE_RETURN(dns);
}
/*
@ -275,7 +291,7 @@ Curl_addrinfo *Curl_resolv(struct SessionHandle *data,
*/
void Curl_freeaddrinfo(void *freethis)
{
struct curl_dns_cache_entry *p = (struct curl_dns_cache_entry *) freethis;
struct Curl_dns_entry *p = (struct Curl_dns_entry *) freethis;
#ifdef ENABLE_IPV6
freeaddrinfo(p->addr);
@ -333,10 +349,10 @@ void curl_freeaddrinfo(struct addrinfo *freethis,
* memory we need to free after use. That meory *MUST* be freed with
* Curl_freeaddrinfo(), nothing else.
*/
Curl_addrinfo *Curl_getaddrinfo(struct SessionHandle *data,
char *hostname,
int port,
char **bufp)
static Curl_addrinfo *my_getaddrinfo(struct SessionHandle *data,
char *hostname,
int port,
char **bufp)
{
struct addrinfo hints, *res;
int error;
@ -509,10 +525,10 @@ static void hostcache_fixoffset(struct hostent *h, int offset)
/* The original code to this function was once stolen from the Dancer source
code, written by Bjorn Reese, it has since been patched and modified
considerably. */
Curl_addrinfo *Curl_getaddrinfo(struct SessionHandle *data,
char *hostname,
int port,
char **bufp)
static Curl_addrinfo *my_getaddrinfo(struct SessionHandle *data,
char *hostname,
int port,
char **bufp)
{
struct hostent *h = NULL;
in_addr_t in;

View File

@ -23,6 +23,7 @@
* $Id$
***************************************************************************/
#include "setup.h"
#include "hash.h"
struct addrinfo;
@ -35,15 +36,23 @@ curl_hash *Curl_global_host_cache_get(void);
#define Curl_global_host_cache_use(__p) ((__p)->set.global_dns_cache)
Curl_addrinfo *Curl_resolv(struct SessionHandle *data,
char *hostname,
int port);
struct Curl_dns_entry {
Curl_addrinfo *addr;
time_t timestamp;
long inuse; /* use-counter, make very sure you decrease this
when you're done using the address you received */
#ifdef MALLOCDEBUG
char *entry_id;
#endif
};
struct Curl_dns_entry *Curl_resolv(struct SessionHandle *data,
char *hostname,
int port);
/* for debugging purposes only: */
void Curl_scan_cache_used(void *user, void *ptr);
/* Get name info */
Curl_addrinfo *Curl_getaddrinfo(struct SessionHandle *data,
char *hostname,
int port,
char **bufp);
/* free name info */
void Curl_freeaddrinfo(void *freethis);

View File

@ -1484,18 +1484,23 @@ static int handleSock5Proxy(
socksreq[3] = 1; /* IPv4 = 1 */
{
Curl_addrinfo *hp;
hp = Curl_resolv(conn->data, conn->hostname, conn->remote_port);
#ifndef ENABLE_IPV6
struct Curl_dns_entry *dns;
Curl_addrinfo *hp=NULL;
dns = Curl_resolv(conn->data, conn->hostname, conn->remote_port);
/*
* We cannot use 'hostent' as a struct that Curl_resolv() returns. It
* returns a Curl_addrinfo pointer that may not always look the same.
*/
#ifndef ENABLE_IPV6
if(dns)
hp=dns->addr;
if (hp && hp->h_addr_list[0]) {
socksreq[4] = ((char*)hp->h_addr_list[0])[0];
socksreq[5] = ((char*)hp->h_addr_list[0])[1];
socksreq[6] = ((char*)hp->h_addr_list[0])[2];
socksreq[7] = ((char*)hp->h_addr_list[0])[3];
dns->inuse--; /* not used anymore from now on */
}
else {
failf(conn->data, "Failed to resolve \"%s\" for SOCKS5 connect.",
@ -1548,7 +1553,7 @@ static int handleSock5Proxy(
}
static CURLcode ConnectPlease(struct connectdata *conn,
Curl_addrinfo *hostaddr,
struct Curl_dns_entry *hostaddr,
bool *connected)
{
CURLcode result;
@ -1567,6 +1572,8 @@ static CURLcode ConnectPlease(struct connectdata *conn,
/* All is cool, then we store the current information from the hostaddr
struct to the serv_addr, as it might be needed later. The address
returned from the function above is crucial here. */
conn->connect_addr = hostaddr;
#ifdef ENABLE_IPV6
conn->serv_addr = addr;
#else
@ -1597,7 +1604,7 @@ static CURLcode ConnectPlease(struct connectdata *conn,
}
static void verboseconnect(struct connectdata *conn,
Curl_addrinfo *hostaddr)
struct Curl_dns_entry *dns)
{
#ifdef HAVE_INET_NTOA_R
char ntoa_buf[64];
@ -1606,7 +1613,7 @@ static void verboseconnect(struct connectdata *conn,
/* Figure out the ip-number and display the first host name it shows: */
#ifdef ENABLE_IPV6
(void)hostaddr; /* not used in the IPv6 enabled version */
(void)dns; /* not used in the IPv6 enabled version */
{
char hbuf[NI_MAXHOST];
#ifdef NI_WITHSCOPEID
@ -1629,6 +1636,7 @@ static void verboseconnect(struct connectdata *conn,
}
#else
{
Curl_addrinfo *hostaddr=dns->addr;
struct in_addr in;
(void) memcpy(&in.s_addr, &conn->serv_addr.sin_addr, sizeof (in.s_addr));
infof(data, "Connected to %s (%s) port %d\n",
@ -1654,7 +1662,7 @@ static void verboseconnect(struct connectdata *conn,
* 'serv_addr' field in the connectdata struct for most of it.
*/
CURLcode Curl_protocol_connect(struct connectdata *conn,
Curl_addrinfo *hostaddr)
struct Curl_dns_entry *hostaddr)
{
struct SessionHandle *data = conn->data;
CURLcode result=CURLE_OK;
@ -1689,7 +1697,7 @@ static CURLcode CreateConnection(struct SessionHandle *data,
struct connectdata *conn;
struct connectdata *conn_temp;
int urllen;
Curl_addrinfo *hostaddr;
struct Curl_dns_entry *hostaddr;
#ifdef HAVE_ALARM
unsigned int prev_alarm=0;
#endif
@ -2811,7 +2819,6 @@ CURLcode Curl_connect(struct SessionHandle *data,
return code;
}
CURLcode Curl_done(struct connectdata *conn)
{
struct SessionHandle *data=conn->data;
@ -2829,7 +2836,16 @@ CURLcode Curl_done(struct connectdata *conn)
free(conn->newurl);
conn->newurl = NULL;
}
if(conn->connect_addr)
conn->connect_addr->inuse--; /* done with this */
#ifdef MALLOCDEBUG
/* scan for DNS cache entries still marked as in use */
Curl_hash_apply(data->hostcache,
NULL, Curl_scan_cache_used);
#endif
/* this calls the protocol-specific function pointer previously set */
if(conn->curl_done)
result = conn->curl_done(conn);

View File

@ -36,5 +36,5 @@ CURLcode Curl_do_more(struct connectdata *);
CURLcode Curl_done(struct connectdata *);
CURLcode Curl_disconnect(struct connectdata *);
CURLcode Curl_protocol_connect(struct connectdata *conn,
Curl_addrinfo *hostaddr);
struct Curl_dns_entry *dns);
#endif

View File

@ -26,8 +26,6 @@
/* This file is for lib internal stuff */
#include "setup.h"
#include "hostip.h"
#include "hash.h"
#define PORT_FTP 21
#define PORT_TELNET 23
@ -81,6 +79,8 @@
#include <curl/curl.h>
#include "http_chunks.h" /* for the structs and enum stuff */
#include "hostip.h"
#include "hash.h"
#ifdef HAVE_ZLIB_H
#include <zlib.h> /* for content-encoding 08/28/02 jhrg */
@ -311,8 +311,11 @@ struct connectdata {
#define PROT_FTPS (1<<9)
#define PROT_SSL (1<<10) /* protocol requires SSL */
/* the particular host we use, in two different ways */
struct Curl_dns_entry *connect_addr;
#ifdef ENABLE_IPV6
struct addrinfo *serv_addr; /* the particular host we use */
struct addrinfo *serv_addr;
#else
struct sockaddr_in serv_addr;
#endif