Merge libfetch-2.30 from NetBSD's pkgsrc.

--HG--
extra : convert_revision : xtraeme%40gmail.com-20100124144753-ni487x8m7r05847b
This commit is contained in:
Juan RP
2010-01-24 15:47:53 +01:00
parent 489f6baaa6
commit 03e8fa53d9
5 changed files with 277 additions and 227 deletions

@@ -1,7 +1,7 @@
/* $NetBSD: common.c,v 1.21 2009/10/15 12:36:57 joerg Exp $ */
/* $NetBSD: common.c,v 1.24 2010/01/23 14:25:26 joerg Exp $ */
/*-
* Copyright (c) 1998-2004 Dag-Erling Coïdan Smørav
* Copyright (c) 2008 Joerg Sonnenberger <joerg@NetBSD.org>
* Copyright (c) 1998-2004 Dag-Erling Co<EFBFBD>dan Sm<EFBFBD>rgrav
* Copyright (c) 2008, 2010 Joerg Sonnenberger <joerg@NetBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -65,9 +65,6 @@
#include "fetch.h"
#include "common.h"
#define DECONST(x,y) ((x)(uintptr_t)(y))
/*** Local data **************************************************************/
/*
@@ -83,10 +80,6 @@ static struct fetcherr netdb_errlist[] = {
{ -1, FETCH_UNKNOWN, "Unknown resolver error" }
};
/* End-of-Line */
static const char ENDL[2] = "\r\n";
/*** Error-reporting functions ***********************************************/
/*
@@ -234,23 +227,10 @@ fetch_reopen(int sd)
/* allocate and fill connection structure */
if ((conn = calloc(1, sizeof(*conn))) == NULL)
return (NULL);
conn->cache_url = NULL;
conn->next_buf = NULL;
conn->next_len = 0;
conn->sd = sd;
conn->is_active = 0;
++conn->ref;
return (conn);
}
/*
* Bump a connection's reference count.
*/
conn_t *
fetch_ref(conn_t *conn)
{
++conn->ref;
return (conn);
}
@@ -281,7 +261,7 @@ fetch_bind(int sd, int af, const char *addr)
* Establish a TCP connection to the specified port on the specified host.
*/
conn_t *
fetch_connect(const char *host, int port, int af, int verbose)
fetch_connect(struct url *url, int af, int verbose)
{
conn_t *conn;
char pbuf[10];
@@ -290,22 +270,22 @@ fetch_connect(const char *host, int port, int af, int verbose)
int sd, error;
if (verbose)
fetch_info("looking up %s", host);
fetch_info("looking up %s", url->host);
/* look up host name and set up socket address structure */
snprintf(pbuf, sizeof(pbuf), "%d", port);
snprintf(pbuf, sizeof(pbuf), "%d", url->port);
memset(&hints, 0, sizeof(hints));
hints.ai_family = af;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = 0;
if ((error = getaddrinfo(host, pbuf, &hints, &res0)) != 0) {
if ((error = getaddrinfo(url->host, pbuf, &hints, &res0)) != 0) {
netdb_seterr(error);
return (NULL);
}
bindaddr = getenv("FETCH_BIND_ADDRESS");
if (verbose)
fetch_info("connecting to %s:%d", host, port);
fetch_info("connecting to %s:%d", url->host, url->port);
/* try to connect */
for (sd = -1, res = res0; res; sd = -1, res = res->ai_next) {
@@ -332,9 +312,114 @@ fetch_connect(const char *host, int port, int af, int verbose)
fetch_syserr();
close(sd);
}
conn->cache_url = fetchCopyURL(url);
conn->cache_af = af;
return (conn);
}
static conn_t *connection_cache;
static int cache_global_limit = 0;
static int cache_per_host_limit = 0;
/*
* Initialise cache with the given limits.
*/
void
fetchConnectionCacheInit(int global_limit, int per_host_limit)
{
if (global_limit < 0)
cache_global_limit = INT_MAX;
else if (per_host_limit > global_limit)
cache_global_limit = per_host_limit;
else
cache_global_limit = global_limit;
if (per_host_limit < 0)
cache_per_host_limit = INT_MAX;
else
cache_per_host_limit = per_host_limit;
}
/*
* Flush cache and free all associated resources.
*/
void
fetchConnectionCacheClose(void)
{
conn_t *conn;
while ((conn = connection_cache) != NULL) {
connection_cache = conn->next_cached;
(*conn->cache_close)(conn);
}
}
/*
* Check connection cache for an existing entry matching
* protocol/host/port/user/password/family.
*/
conn_t *
fetch_cache_get(const struct url *url, int af)
{
conn_t *conn, *last_conn = NULL;
for (conn = connection_cache; conn; conn = conn->next_cached) {
if (conn->cache_url->port == url->port &&
strcmp(conn->cache_url->scheme, url->scheme) == 0 &&
strcmp(conn->cache_url->host, url->host) == 0 &&
strcmp(conn->cache_url->user, url->user) == 0 &&
strcmp(conn->cache_url->pwd, url->pwd) == 0 &&
(conn->cache_af == AF_UNSPEC || af == AF_UNSPEC ||
conn->cache_af == af)) {
if (last_conn != NULL)
last_conn->next_cached = conn->next_cached;
else
connection_cache = conn->next_cached;
return conn;
}
}
return NULL;
}
/*
* Put the connection back into the cache for reuse.
* If the connection is freed due to LRU or if the cache
* is explicitly closed, the given callback is called.
*/
void
fetch_cache_put(conn_t *conn, int (*closecb)(conn_t *))
{
conn_t *iter, *last;
int global_count, host_count;
if (conn->cache_url == NULL || cache_global_limit == 0) {
(*closecb)(conn);
return;
}
global_count = host_count = 0;
last = NULL;
for (iter = connection_cache; iter;
last = iter, iter = iter->next_cached) {
++global_count;
if (strcmp(conn->cache_url->host, iter->cache_url->host) == 0)
++host_count;
if (global_count < cache_global_limit &&
host_count < cache_per_host_limit)
continue;
--global_count;
if (last != NULL)
last->next_cached = iter->next_cached;
else
connection_cache = iter->next_cached;
(*iter->cache_close)(iter);
}
conn->cache_close = closecb;
conn->next_cached = connection_cache;
connection_cache = conn;
}
/*
* Enable SSL on a connection.
@@ -528,26 +613,12 @@ fetch_getln(conn_t *conn)
return (0);
}
/*
* Write to a connection w/ timeout
*/
ssize_t
fetch_write(conn_t *conn, const char *buf, size_t len)
{
struct iovec iov;
iov.iov_base = DECONST(char *, buf);
iov.iov_len = len;
return fetch_writev(conn, &iov, 1);
}
/*
* Write a vector to a connection w/ timeout
* Note: can modify the iovec.
*/
ssize_t
fetch_writev(conn_t *conn, struct iovec *iov, int iovcnt)
fetch_write(conn_t *conn, const void *buf, size_t len)
{
struct timeval now, timeout, waittv;
fd_set writefds;
@@ -561,7 +632,7 @@ fetch_writev(conn_t *conn, struct iovec *iov, int iovcnt)
}
total = 0;
while (iovcnt > 0) {
while (len) {
while (fetchTimeout && !FD_ISSET(conn->sd, &writefds)) {
FD_SET(conn->sd, &writefds);
gettimeofday(&now, NULL);
@@ -587,11 +658,10 @@ fetch_writev(conn_t *conn, struct iovec *iov, int iovcnt)
errno = 0;
#ifdef WITH_SSL
if (conn->ssl != NULL)
wlen = SSL_write(conn->ssl,
iov->iov_base, iov->iov_len);
wlen = SSL_write(conn->ssl, buf, len);
else
#endif
wlen = writev(conn->sd, iov, iovcnt);
wlen = send(conn->sd, buf, len, MSG_NOSIGNAL);
if (wlen == 0) {
/* we consider a short write a failure */
errno = EPIPE;
@@ -604,43 +674,13 @@ fetch_writev(conn_t *conn, struct iovec *iov, int iovcnt)
return (-1);
}
total += wlen;
while (iovcnt > 0 && wlen >= (ssize_t)iov->iov_len) {
wlen -= iov->iov_len;
iov++;
iovcnt--;
}
if (iovcnt > 0) {
iov->iov_len -= wlen;
iov->iov_base = DECONST(char *, iov->iov_base) + wlen;
}
buf = (const char *)buf + wlen;
len -= wlen;
}
return (total);
}
/*
* Write a line of text to a connection w/ timeout
*/
int
fetch_putln(conn_t *conn, const char *str, size_t len)
{
struct iovec iov[2];
ssize_t ret;
iov[0].iov_base = DECONST(char *, str);
iov[0].iov_len = len;
iov[1].iov_base = DECONST(char *, ENDL);
iov[1].iov_len = sizeof(ENDL);
if (len == 0)
ret = fetch_writev(conn, &iov[1], 1);
else
ret = fetch_writev(conn, iov, 2);
if (ret == -1)
return (-1);
return (0);
}
/*
* Close connection
*/
@@ -649,9 +689,9 @@ fetch_close(conn_t *conn)
{
int ret;
if (--conn->ref > 0)
return (0);
ret = close(conn->sd);
if (conn->cache_url)
fetchFreeURL(conn->cache_url);
free(conn->buf);
free(conn);
return (ret);