aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDag-Erling Smørgrav <des@FreeBSD.org>2002-06-05 10:05:03 +0000
committerDag-Erling Smørgrav <des@FreeBSD.org>2002-06-05 10:05:03 +0000
commitdea29ca1d5850eb6fd7771a1ad8f41ce46665995 (patch)
tree2d0745a2b622f4f25fdcff8a8d2ce1eeea0b7447
parent09dbd0701c7afa1777170ab990fac8df61b789e6 (diff)
downloadsrc-dea29ca1d5850eb6fd7771a1ad8f41ce46665995.tar.gz
src-dea29ca1d5850eb6fd7771a1ad8f41ce46665995.zip
First step towards SSL support: wrap connections in a 'struct connection'
which contains the socket descriptor, the input buffer and (yet unused) SSL state variables. This has the neat side effect of greatly improving reentrance (though we're not *quite* there yet) and opening the door to HTTP connection caching. This commit is inspired by email conversations with and patches from Henry Whincup <henry@techiebod.com> last fall.
Notes
Notes: svn path=/head/; revision=97856
-rw-r--r--lib/libfetch/common.c80
-rw-r--r--lib/libfetch/common.h29
-rw-r--r--lib/libfetch/ftp.c181
-rw-r--r--lib/libfetch/http.c161
4 files changed, 255 insertions, 196 deletions
diff --git a/lib/libfetch/common.c b/lib/libfetch/common.c
index 559c665e0031..18b3a09febc8 100644
--- a/lib/libfetch/common.c
+++ b/lib/libfetch/common.c
@@ -198,9 +198,10 @@ _fetch_default_proxy_port(const char *scheme)
/*
* Establish a TCP connection to the specified port on the specified host.
*/
-int
+conn_t *
_fetch_connect(const char *host, int port, int af, int verbose)
{
+ conn_t *conn;
char pbuf[10];
struct addrinfo hints, *res, *res0;
int sd, err;
@@ -218,7 +219,7 @@ _fetch_connect(const char *host, int port, int af, int verbose)
hints.ai_protocol = 0;
if ((err = getaddrinfo(host, pbuf, &hints, &res0)) != 0) {
_netdb_seterr(err);
- return (-1);
+ return (NULL);
}
if (verbose)
@@ -237,10 +238,23 @@ _fetch_connect(const char *host, int port, int af, int verbose)
freeaddrinfo(res0);
if (sd == -1) {
_fetch_syserr();
- return (-1);
+ return (NULL);
}
- return (sd);
+ /* allocate and fill connection structure */
+ if ((conn = calloc(1, sizeof *conn)) == NULL) {
+ close(sd);
+ return (NULL);
+ }
+ if ((conn->host = strdup(host)) == NULL) {
+ free(conn);
+ close(sd);
+ return (NULL);
+ }
+ conn->port = port;
+ conn->af = af;
+ conn->sd = sd;
+ return (conn);
}
@@ -250,23 +264,23 @@ _fetch_connect(const char *host, int port, int af, int verbose)
#define MIN_BUF_SIZE 1024
int
-_fetch_getln(int fd, char **buf, size_t *size, size_t *len)
+_fetch_getln(conn_t *conn)
{
struct timeval now, timeout, wait;
fd_set readfds;
int r;
char c;
- if (*buf == NULL) {
- if ((*buf = malloc(MIN_BUF_SIZE)) == NULL) {
+ if (conn->buf == NULL) {
+ if ((conn->buf = malloc(MIN_BUF_SIZE)) == NULL) {
errno = ENOMEM;
return (-1);
}
- *size = MIN_BUF_SIZE;
+ conn->bufsize = MIN_BUF_SIZE;
}
- **buf = '\0';
- *len = 0;
+ conn->buf[0] = '\0';
+ conn->buflen = 0;
if (fetchTimeout) {
gettimeofday(&timeout, NULL);
@@ -276,7 +290,7 @@ _fetch_getln(int fd, char **buf, size_t *size, size_t *len)
do {
if (fetchTimeout) {
- FD_SET(fd, &readfds);
+ FD_SET(conn->sd, &readfds);
gettimeofday(&now, NULL);
wait.tv_sec = timeout.tv_sec - now.tv_sec;
wait.tv_usec = timeout.tv_usec - now.tv_usec;
@@ -288,17 +302,17 @@ _fetch_getln(int fd, char **buf, size_t *size, size_t *len)
errno = ETIMEDOUT;
return (-1);
}
- r = select(fd+1, &readfds, NULL, NULL, &wait);
+ r = select(conn->sd + 1, &readfds, NULL, NULL, &wait);
if (r == -1) {
if (errno == EINTR && fetchRestartCalls)
continue;
/* EBADF or EINVAL: shouldn't happen */
return (-1);
}
- if (!FD_ISSET(fd, &readfds))
+ if (!FD_ISSET(conn->sd, &readfds))
continue;
}
- r = read(fd, &c, 1);
+ r = read(conn->sd, &c, 1);
if (r == 0)
break;
if (r == -1) {
@@ -307,21 +321,24 @@ _fetch_getln(int fd, char **buf, size_t *size, size_t *len)
/* any other error is bad news */
return (-1);
}
- (*buf)[*len] = c;
- *len += 1;
- if (*len == *size) {
+ conn->buf[conn->buflen++] = c;
+ if (conn->buflen == conn->bufsize) {
char *tmp;
+ size_t tmpsize;
- if ((tmp = realloc(*buf, *size * 2 + 1)) == NULL) {
+ tmp = conn->buf;
+ tmpsize = conn->bufsize * 2 + 1;
+ if ((tmp = realloc(tmp, tmpsize)) == NULL) {
errno = ENOMEM;
return (-1);
}
- *buf = tmp;
- *size = *size * 2 + 1;
+ conn->buf = tmp;
+ conn->bufsize = tmpsize;
}
} while (c != '\n');
- DEBUG(fprintf(stderr, "<<< %.*s", (int)*len, *buf));
+ conn->buf[conn->buflen] = '\0';
+ DEBUG(fprintf(stderr, "<<< %s", conn->buf));
return (0);
}
@@ -331,7 +348,7 @@ _fetch_getln(int fd, char **buf, size_t *size, size_t *len)
* XXX currently does not enforce timeout
*/
int
-_fetch_putln(int fd, const char *str, size_t len)
+_fetch_putln(conn_t *conn, const char *str, size_t len)
{
struct iovec iov[2];
ssize_t wlen;
@@ -342,14 +359,29 @@ _fetch_putln(int fd, const char *str, size_t len)
iov[1].iov_base = (char *)ENDL;
iov[1].iov_len = sizeof ENDL;
len += sizeof ENDL;
- wlen = writev(fd, iov, 2);
+ wlen = writev(conn->sd, iov, 2);
if (wlen < 0 || (size_t)wlen != len)
return (-1);
- DEBUG(fprintf(stderr, ">>> %s\n", str));
+ DEBUG(fprintf(stderr, ">>> %.*s\n", (int)len, str));
return (0);
}
+/*
+ * Close connection
+ */
+int
+_fetch_close(conn_t *conn)
+{
+ int ret;
+
+ ret = close(conn->sd);
+ free(conn->host);
+ free(conn);
+ return (ret);
+}
+
+
/*** Directory-related utility functions *************************************/
int
diff --git a/lib/libfetch/common.h b/lib/libfetch/common.h
index 7d93d9668e94..45c90bc58487 100644
--- a/lib/libfetch/common.h
+++ b/lib/libfetch/common.h
@@ -36,6 +36,28 @@
#define FTP_DEFAULT_PROXY_PORT 21
#define HTTP_DEFAULT_PROXY_PORT 3128
+#include <openssl/crypto.h>
+#include <openssl/x509.h>
+#include <openssl/pem.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+
+/* Connection */
+typedef struct fetchconn conn_t;
+struct fetchconn {
+ char *host; /* host name */
+ int port; /* port */
+ int af; /* address family */
+ int sd; /* socket descriptor */
+ char *buf; /* buffer */
+ size_t bufsize; /* buffer size */
+ size_t buflen; /* length of buffer contents */
+ int err; /* last protocol reply code */
+ SSL *ssl_ctx; /* SSL context if needed */
+ X509 *ssl_cert; /* server certificate */
+ SSL_METHOD *ssl_meth; /* SSL method */
+};
+
/* Structure used for error message lists */
struct fetcherr {
const int num;
@@ -48,9 +70,10 @@ void _fetch_syserr(void);
void _fetch_info(const char *, ...);
int _fetch_default_port(const char *);
int _fetch_default_proxy_port(const char *);
-int _fetch_connect(const char *, int, int, int);
-int _fetch_getln(int, char **, size_t *, size_t *);
-int _fetch_putln(int, const char *, size_t);
+conn_t *_fetch_connect(const char *, int, int, int);
+int _fetch_getln(conn_t *);
+int _fetch_putln(conn_t *, const char *, size_t);
+int _fetch_close(conn_t *);
int _fetch_add_entry(struct url_ent **, int *, int *,
const char *, struct url_stat *);
diff --git a/lib/libfetch/ftp.c b/lib/libfetch/ftp.c
index 489c52d230ee..734ec091d1f4 100644
--- a/lib/libfetch/ftp.c
+++ b/lib/libfetch/ftp.c
@@ -66,6 +66,7 @@ __FBSDID("$FreeBSD$");
#include <fcntl.h>
#include <netdb.h>
#include <stdarg.h>
+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -96,12 +97,7 @@ __FBSDID("$FreeBSD$");
#define FTP_PROTOCOL_ERROR 999
static struct url cached_host;
-static int cached_socket;
-
-static char *last_reply;
-static size_t lr_size;
-static size_t lr_length;
-static int last_code;
+static conn_t *cached_connection;
#define isftpreply(foo) (isdigit(foo[0]) && isdigit(foo[1]) \
&& isdigit(foo[2]) \
@@ -136,43 +132,42 @@ unmappedaddr(struct sockaddr_in6 *sin6)
* Get server response
*/
static int
-_ftp_chkerr(int cd)
+_ftp_chkerr(conn_t *conn)
{
- if (_fetch_getln(cd, &last_reply, &lr_size, &lr_length) == -1) {
+ if (_fetch_getln(conn) == -1) {
_fetch_syserr();
return (-1);
}
- if (isftpinfo(last_reply)) {
- while (lr_length && !isftpreply(last_reply)) {
- if (_fetch_getln(cd, &last_reply,
- &lr_size, &lr_length) == -1) {
+ if (isftpinfo(conn->buf)) {
+ while (conn->buflen && !isftpreply(conn->buf)) {
+ if (_fetch_getln(conn) == -1) {
_fetch_syserr();
return (-1);
}
}
}
- while (lr_length && isspace(last_reply[lr_length-1]))
- lr_length--;
- last_reply[lr_length] = 0;
+ while (conn->buflen && isspace(conn->buf[conn->buflen - 1]))
+ conn->buflen--;
+ conn->buf[conn->buflen] = '\0';
- if (!isftpreply(last_reply)) {
+ if (!isftpreply(conn->buf)) {
_ftp_seterr(FTP_PROTOCOL_ERROR);
return (-1);
}
- last_code = (last_reply[0] - '0') * 100
- + (last_reply[1] - '0') * 10
- + (last_reply[2] - '0');
+ conn->err = (conn->buf[0] - '0') * 100
+ + (conn->buf[1] - '0') * 10
+ + (conn->buf[2] - '0');
- return (last_code);
+ return (conn->err);
}
/*
* Send a command and check reply
*/
static int
-_ftp_cmd(int cd, const char *fmt, ...)
+_ftp_cmd(conn_t *conn, const char *fmt, ...)
{
va_list ap;
size_t len;
@@ -189,7 +184,7 @@ _ftp_cmd(int cd, const char *fmt, ...)
return (-1);
}
- r = _fetch_putln(cd, msg, len);
+ r = _fetch_putln(conn, msg, len);
free(msg);
if (r == -1) {
@@ -197,7 +192,7 @@ _ftp_cmd(int cd, const char *fmt, ...)
return (-1);
}
- return (_ftp_chkerr(cd));
+ return (_ftp_chkerr(conn));
}
/*
@@ -219,15 +214,15 @@ _ftp_filename(const char *file)
* file.
*/
static int
-_ftp_cwd(int cd, const char *file)
+_ftp_cwd(conn_t *conn, const char *file)
{
char *s;
int e;
if ((s = strrchr(file, '/')) == NULL || s == file) {
- e = _ftp_cmd(cd, "CWD /");
+ e = _ftp_cmd(conn, "CWD /");
} else {
- e = _ftp_cmd(cd, "CWD %.*s", s - file, file);
+ e = _ftp_cmd(conn, "CWD %.*s", s - file, file);
}
if (e != FTP_FILE_ACTION_OK) {
_ftp_seterr(e);
@@ -240,7 +235,7 @@ _ftp_cwd(int cd, const char *file)
* Request and parse file stats
*/
static int
-_ftp_stat(int cd, const char *file, struct url_stat *us)
+_ftp_stat(conn_t *conn, const char *file, struct url_stat *us)
{
char *ln;
const char *s;
@@ -256,11 +251,11 @@ _ftp_stat(int cd, const char *file, struct url_stat *us)
else
++s;
- if ((e = _ftp_cmd(cd, "SIZE %s", s)) != FTP_FILE_STATUS) {
+ if ((e = _ftp_cmd(conn, "SIZE %s", s)) != FTP_FILE_STATUS) {
_ftp_seterr(e);
return (-1);
}
- for (ln = last_reply + 4; *ln && isspace(*ln); ln++)
+ for (ln = conn->buf + 4; *ln && isspace(*ln); ln++)
/* nothing */ ;
for (us->size = 0; *ln && isdigit(*ln); ln++)
us->size = us->size * 10 + *ln - '0';
@@ -273,11 +268,11 @@ _ftp_stat(int cd, const char *file, struct url_stat *us)
us->size = -1;
DEBUG(fprintf(stderr, "size: [%lld]\n", (long long)us->size));
- if ((e = _ftp_cmd(cd, "MDTM %s", s)) != FTP_FILE_STATUS) {
+ if ((e = _ftp_cmd(conn, "MDTM %s", s)) != FTP_FILE_STATUS) {
_ftp_seterr(e);
return (-1);
}
- for (ln = last_reply + 4; *ln && isspace(*ln); ln++)
+ for (ln = conn->buf + 4; *ln && isspace(*ln); ln++)
/* nothing */ ;
switch (strspn(ln, "0123456789")) {
case 14:
@@ -316,7 +311,7 @@ _ftp_stat(int cd, const char *file, struct url_stat *us)
* I/O functions for FTP
*/
struct ftpio {
- int csd; /* Control socket descriptor */
+ conn_t *conn; /* Control connection */
int dsd; /* Data socket descriptor */
int dir; /* Direction */
int eof; /* EOF reached */
@@ -339,7 +334,7 @@ _ftp_readfn(void *v, char *buf, int len)
errno = EBADF;
return (-1);
}
- if (io->csd == -1 || io->dsd == -1 || io->dir == O_WRONLY) {
+ if (io->conn == NULL || io->dsd == -1 || io->dir == O_WRONLY) {
errno = EBADF;
return (-1);
}
@@ -372,7 +367,7 @@ _ftp_writefn(void *v, const char *buf, int len)
errno = EBADF;
return (-1);
}
- if (io->csd == -1 || io->dsd == -1 || io->dir == O_RDONLY) {
+ if (io->conn == NULL || io->dsd == -1 || io->dir == O_RDONLY) {
errno = EBADF;
return (-1);
}
@@ -415,7 +410,7 @@ _ftp_closefn(void *v)
}
if (io->dir == -1)
return (0);
- if (io->csd == -1 || io->dsd == -1) {
+ if (io->conn == NULL || io->dsd == -1) {
errno = EBADF;
return (-1);
}
@@ -423,21 +418,21 @@ _ftp_closefn(void *v)
io->dir = -1;
io->dsd = -1;
DEBUG(fprintf(stderr, "Waiting for final status\n"));
- r = _ftp_chkerr(io->csd);
- close(io->csd);
+ r = _ftp_chkerr(io->conn);
+ _fetch_close(io->conn);
free(io);
return (r == FTP_TRANSFER_COMPLETE) ? 0 : -1;
}
static FILE *
-_ftp_setup(int csd, int dsd, int mode)
+_ftp_setup(conn_t *conn, int dsd, int mode)
{
struct ftpio *io;
FILE *f;
if ((io = malloc(sizeof *io)) == NULL)
return (NULL);
- io->csd = dup(csd);
+ io->conn = conn;
io->dsd = dsd;
io->dir = mode;
io->eof = io->err = 0;
@@ -451,7 +446,7 @@ _ftp_setup(int csd, int dsd, int mode)
* Transfer file
*/
static FILE *
-_ftp_transfer(int cd, const char *oper, const char *file,
+_ftp_transfer(conn_t *conn, const char *oper, const char *file,
int mode, off_t offset, const char *flags)
{
struct sockaddr_storage sa;
@@ -475,7 +470,7 @@ _ftp_transfer(int cd, const char *oper, const char *file,
/* find our own address, bind, and listen */
l = sizeof sa;
- if (getsockname(cd, (struct sockaddr *)&sa, &l) == -1)
+ if (getsockname(conn->sd, (struct sockaddr *)&sa, &l) == -1)
goto sysouch;
if (sa.ss_family == AF_INET6)
unmappedaddr((struct sockaddr_in6 *)&sa);
@@ -497,14 +492,15 @@ _ftp_transfer(int cd, const char *oper, const char *file,
_fetch_info("setting passive mode");
switch (sa.ss_family) {
case AF_INET:
- if ((e = _ftp_cmd(cd, "PASV")) != FTP_PASSIVE_MODE)
+ if ((e = _ftp_cmd(conn, "PASV")) != FTP_PASSIVE_MODE)
goto ouch;
break;
case AF_INET6:
- if ((e = _ftp_cmd(cd, "EPSV")) != FTP_EPASSIVE_MODE) {
+ if ((e = _ftp_cmd(conn, "EPSV")) != FTP_EPASSIVE_MODE) {
if (e == -1)
goto ouch;
- if ((e = _ftp_cmd(cd, "LPSV")) != FTP_LPASSIVE_MODE)
+ if ((e = _ftp_cmd(conn, "LPSV")) !=
+ FTP_LPASSIVE_MODE)
goto ouch;
}
break;
@@ -517,7 +513,7 @@ _ftp_transfer(int cd, const char *oper, const char *file,
* Find address and port number. The reply to the PASV command
* is IMHO the one and only weak point in the FTP protocol.
*/
- ln = last_reply;
+ ln = conn->buf;
switch (e) {
case FTP_PASSIVE_MODE:
case FTP_LPASSIVE_MODE:
@@ -555,12 +551,12 @@ _ftp_transfer(int cd, const char *oper, const char *file,
/* seek to required offset */
if (offset)
- if (_ftp_cmd(cd, "REST %lu", (u_long)offset) != FTP_FILE_OK)
+ if (_ftp_cmd(conn, "REST %lu", (u_long)offset) != FTP_FILE_OK)
goto sysouch;
/* construct sockaddr for data socket */
l = sizeof sa;
- if (getpeername(cd, (struct sockaddr *)&sa, &l) == -1)
+ if (getpeername(conn->sd, (struct sockaddr *)&sa, &l) == -1)
goto sysouch;
if (sa.ss_family == AF_INET6)
unmappedaddr((struct sockaddr_in6 *)&sa);
@@ -597,7 +593,7 @@ _ftp_transfer(int cd, const char *oper, const char *file,
/* make the server initiate the transfer */
if (verbose)
_fetch_info("initiating transfer");
- e = _ftp_cmd(cd, "%s %s", oper, _ftp_filename(file));
+ e = _ftp_cmd(conn, "%s %s", oper, _ftp_filename(file));
if (e != FTP_CONNECTION_ALREADY_OPEN && e != FTP_OPEN_DATA_CONNECTION)
goto ouch;
@@ -641,7 +637,7 @@ _ftp_transfer(int cd, const char *oper, const char *file,
sin4 = (struct sockaddr_in *)&sa;
a = ntohl(sin4->sin_addr.s_addr);
p = ntohs(sin4->sin_port);
- e = _ftp_cmd(cd, "PORT %d,%d,%d,%d,%d,%d",
+ e = _ftp_cmd(conn, "PORT %d,%d,%d,%d,%d,%d",
(a >> 24) & 0xff, (a >> 16) & 0xff,
(a >> 8) & 0xff, a & 0xff,
(p >> 8) & 0xff, p & 0xff);
@@ -653,14 +649,14 @@ _ftp_transfer(int cd, const char *oper, const char *file,
if (getnameinfo((struct sockaddr *)&sa, sa.ss_len,
hname, sizeof(hname),
NULL, 0, NI_NUMERICHOST) == 0) {
- e = _ftp_cmd(cd, "EPRT |%d|%s|%d|", 2, hname,
+ e = _ftp_cmd(conn, "EPRT |%d|%s|%d|", 2, hname,
htons(sin6->sin6_port));
if (e == -1)
goto ouch;
}
if (e != FTP_OK) {
ap = (char *)&sin6->sin6_addr;
- e = _ftp_cmd(cd,
+ e = _ftp_cmd(conn,
"LPRT %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
6, 16,
UC(ap[0]), UC(ap[1]), UC(ap[2]), UC(ap[3]),
@@ -681,13 +677,13 @@ _ftp_transfer(int cd, const char *oper, const char *file,
/* seek to required offset */
if (offset)
- if (_ftp_cmd(cd, "REST %lu", (u_long)offset) != FTP_FILE_OK)
+ if (_ftp_cmd(conn, "REST %ju", (uintmax_t)offset) != FTP_FILE_OK)
goto sysouch;
/* make the server initiate the transfer */
if (verbose)
_fetch_info("initiating transfer");
- e = _ftp_cmd(cd, "%s %s", oper, _ftp_filename(file));
+ e = _ftp_cmd(conn, "%s %s", oper, _ftp_filename(file));
if (e != FTP_OPEN_DATA_CONNECTION)
goto ouch;
@@ -698,7 +694,7 @@ _ftp_transfer(int cd, const char *oper, const char *file,
sd = d;
}
- if ((df = _ftp_setup(cd, sd, mode)) == NULL)
+ if ((df = _ftp_setup(conn, sd, mode)) == NULL)
goto sysouch;
return (df);
@@ -720,7 +716,7 @@ ouch:
* Authenticate
*/
static int
-_ftp_authenticate(int cd, struct url *url, struct url *purl)
+_ftp_authenticate(conn_t *conn, struct url *url, struct url *purl)
{
const char *user, *pwd, *logname;
char pbuf[MAXHOSTNAMELEN + MAXLOGNAME + 1];
@@ -735,11 +731,11 @@ _ftp_authenticate(int cd, struct url *url, struct url *purl)
if (!user || !*user)
user = FTP_ANONYMOUS_USER;
if (purl && url->port == _fetch_default_port(url->scheme))
- e = _ftp_cmd(cd, "USER %s@%s", user, url->host);
+ e = _ftp_cmd(conn, "USER %s@%s", user, url->host);
else if (purl)
- e = _ftp_cmd(cd, "USER %s@%s@%d", user, url->host, url->port);
+ e = _ftp_cmd(conn, "USER %s@%s@%d", user, url->host, url->port);
else
- e = _ftp_cmd(cd, "USER %s", user);
+ e = _ftp_cmd(conn, "USER %s", user);
/* did the server request a password? */
if (e == FTP_NEED_PASSWORD) {
@@ -756,7 +752,7 @@ _ftp_authenticate(int cd, struct url *url, struct url *purl)
gethostname(pbuf + len, sizeof pbuf - len);
pwd = pbuf;
}
- e = _ftp_cmd(cd, "PASS %s", pwd);
+ e = _ftp_cmd(conn, "PASS %s", pwd);
}
return (e);
@@ -765,10 +761,11 @@ _ftp_authenticate(int cd, struct url *url, struct url *purl)
/*
* Log on to FTP server
*/
-static int
+static conn_t *
_ftp_connect(struct url *url, struct url *purl, const char *flags)
{
- int cd, e, direct, verbose;
+ conn_t *conn;
+ int e, direct, verbose;
#ifdef INET6
int af = AF_UNSPEC;
#else
@@ -788,42 +785,42 @@ _ftp_connect(struct url *url, struct url *purl, const char *flags)
/* check for proxy */
if (purl) {
/* XXX proxy authentication! */
- cd = _fetch_connect(purl->host, purl->port, af, verbose);
+ conn = _fetch_connect(purl->host, purl->port, af, verbose);
} else {
/* no proxy, go straight to target */
- cd = _fetch_connect(url->host, url->port, af, verbose);
+ conn = _fetch_connect(url->host, url->port, af, verbose);
purl = NULL;
}
/* check connection */
- if (cd == -1) {
+ if (conn == NULL) {
_fetch_syserr();
return (NULL);
}
/* expect welcome message */
- if ((e = _ftp_chkerr(cd)) != FTP_SERVICE_READY)
+ if ((e = _ftp_chkerr(conn)) != FTP_SERVICE_READY)
goto fouch;
/* authenticate */
- if ((e = _ftp_authenticate(cd, url, purl)) != FTP_LOGGED_IN)
+ if ((e = _ftp_authenticate(conn, url, purl)) != FTP_LOGGED_IN)
goto fouch;
/* might as well select mode and type at once */
#ifdef FTP_FORCE_STREAM_MODE
- if ((e = _ftp_cmd(cd, "MODE S")) != FTP_OK) /* default is S */
+ if ((e = _ftp_cmd(conn, "MODE S")) != FTP_OK) /* default is S */
goto fouch;
#endif
- if ((e = _ftp_cmd(cd, "TYPE I")) != FTP_OK) /* default is A */
+ if ((e = _ftp_cmd(conn, "TYPE I")) != FTP_OK) /* default is A */
goto fouch;
/* done */
- return (cd);
+ return (conn);
fouch:
if (e != -1)
_ftp_seterr(e);
- close(cd);
+ _fetch_close(conn);
return (NULL);
}
@@ -831,10 +828,10 @@ fouch:
* Disconnect from server
*/
static void
-_ftp_disconnect(int cd)
+_ftp_disconnect(conn_t *conn)
{
- (void)_ftp_cmd(cd, "QUIT");
- close(cd);
+ (void)_ftp_cmd(conn, "QUIT");
+ _fetch_close(conn);
}
/*
@@ -843,7 +840,7 @@ _ftp_disconnect(int cd)
static int
_ftp_isconnected(struct url *url)
{
- return (cached_socket
+ return (cached_connection
&& (strcmp(url->host, cached_host.host) == 0)
&& (strcmp(url->user, cached_host.user) == 0)
&& (strcmp(url->pwd, cached_host.pwd) == 0)
@@ -853,12 +850,11 @@ _ftp_isconnected(struct url *url)
/*
* Check the cache, reconnect if no luck
*/
-static int
+static conn_t *
_ftp_cached_connect(struct url *url, struct url *purl, const char *flags)
{
- int e, cd;
-
- cd = -1;
+ conn_t *conn;
+ int e;
/* set default port */
if (!url->port)
@@ -866,19 +862,19 @@ _ftp_cached_connect(struct url *url, struct url *purl, const char *flags)
/* try to use previously cached connection */
if (_ftp_isconnected(url)) {
- e = _ftp_cmd(cached_socket, "NOOP");
+ e = _ftp_cmd(cached_connection, "NOOP");
if (e == FTP_OK || e == FTP_SYNTAX_ERROR)
- return (cached_socket);
+ return (cached_connection);
}
/* connect to server */
- if ((cd = _ftp_connect(url, purl, flags)) == -1)
- return (-1);
- if (cached_socket)
- _ftp_disconnect(cached_socket);
- cached_socket = cd;
+ if ((conn = _ftp_connect(url, purl, flags)) == NULL)
+ return (NULL);
+ if (cached_connection)
+ _ftp_disconnect(cached_connection);
+ cached_connection = conn;
memcpy(&cached_host, url, sizeof *url);
- return (cd);
+ return (conn);
}
/*
@@ -916,7 +912,8 @@ FILE *
_ftp_request(struct url *url, const char *op, struct url_stat *us,
struct url *purl, const char *flags)
{
- int cd, oflag;
+ conn_t *conn;
+ int oflag;
/* check if we should use HTTP instead */
if (purl && strcasecmp(purl->scheme, SCHEME_HTTP) == 0) {
@@ -931,18 +928,18 @@ _ftp_request(struct url *url, const char *op, struct url_stat *us,
}
/* connect to server */
- cd = _ftp_cached_connect(url, purl, flags);
+ conn = _ftp_cached_connect(url, purl, flags);
if (purl)
fetchFreeURL(purl);
- if (cd == NULL)
+ if (conn == NULL)
return (NULL);
/* change directory */
- if (_ftp_cwd(cd, url->doc) == -1)
+ if (_ftp_cwd(conn, url->doc) == -1)
return (NULL);
/* stat file */
- if (us && _ftp_stat(cd, url->doc, us) == -1
+ if (us && _ftp_stat(conn, url->doc, us) == -1
&& fetchLastErrCode != FETCH_PROTO
&& fetchLastErrCode != FETCH_UNAVAIL)
return (NULL);
@@ -956,7 +953,7 @@ _ftp_request(struct url *url, const char *op, struct url_stat *us,
oflag = O_RDONLY;
/* initiate the transfer */
- return (_ftp_transfer(cd, op, url->doc, oflag, url->offset, flags));
+ return (_ftp_transfer(conn, op, url->doc, oflag, url->offset, flags));
}
/*
diff --git a/lib/libfetch/http.c b/lib/libfetch/http.c
index 8d040d075510..0505b0a63551 100644
--- a/lib/libfetch/http.c
+++ b/lib/libfetch/http.c
@@ -106,7 +106,7 @@ __FBSDID("$FreeBSD$");
struct cookie
{
- int fd;
+ conn_t *conn;
char *buf;
size_t b_size;
ssize_t b_len;
@@ -127,13 +127,13 @@ _http_new_chunk(struct cookie *c)
{
char *p;
- if (_fetch_getln(c->fd, &c->buf, &c->b_size, &c->b_len) == -1)
+ if (_fetch_getln(c->conn) == -1)
return (-1);
- if (c->b_len < 2 || !ishexnumber(*c->buf))
+ if (c->b_len < 2 || !ishexnumber(*c->conn->buf))
return (-1);
- for (p = c->buf; !isspace(*p) && p < c->buf + c->b_len; ++p) {
+ for (p = c->conn->buf; *p && !isspace(*p); ++p) {
if (*p == ';')
break;
if (!ishexnumber(*p))
@@ -194,14 +194,16 @@ _http_fillbuf(struct cookie *c)
c->b_size = c->chunksize;
}
- if ((c->b_len = read(c->fd, c->buf, c->chunksize)) == -1)
+ if ((c->b_len = read(c->conn->sd, c->buf, c->chunksize)) == -1)
return (-1);
c->chunksize -= c->b_len;
if (c->chunksize == 0) {
- char endl;
- if (read(c->fd, &endl, 1) == -1 ||
- read(c->fd, &endl, 1) == -1)
+ char endl[2];
+
+ if (read(c->conn->sd, &endl[0], 1) == -1 ||
+ read(c->conn->sd, &endl[1], 1) == -1 ||
+ endl[0] != '\r' || endl[1] != '\n')
return (-1);
}
@@ -249,7 +251,7 @@ _http_writefn(void *v, const char *buf, int len)
{
struct cookie *c = (struct cookie *)v;
- return (write(c->fd, buf, len));
+ return (write(c->conn->sd, buf, len));
}
/*
@@ -261,7 +263,7 @@ _http_closefn(void *v)
struct cookie *c = (struct cookie *)v;
int r;
- r = close(c->fd);
+ r = _fetch_close(c->conn);
if (c->buf)
free(c->buf);
free(c);
@@ -272,7 +274,7 @@ _http_closefn(void *v)
* Wrap a file descriptor up
*/
static FILE *
-_http_funopen(int fd)
+_http_funopen(conn_t *conn)
{
struct cookie *c;
FILE *f;
@@ -281,7 +283,7 @@ _http_funopen(int fd)
_fetch_syserr();
return (NULL);
}
- c->fd = fd;
+ c->conn = conn;
f = funopen(c, _http_readfn, _http_writefn, NULL, _http_closefn);
if (f == NULL) {
_fetch_syserr();
@@ -324,15 +326,11 @@ static struct {
{ hdr_unknown, NULL },
};
-static char *reply_buf;
-static size_t reply_size;
-static size_t reply_length;
-
/*
* Send a formatted line; optionally echo to terminal
*/
static int
-_http_cmd(int fd, const char *fmt, ...)
+_http_cmd(conn_t *conn, const char *fmt, ...)
{
va_list ap;
size_t len;
@@ -349,7 +347,7 @@ _http_cmd(int fd, const char *fmt, ...)
return (-1);
}
- r = _fetch_putln(fd, msg, len);
+ r = _fetch_putln(conn, msg, len);
free(msg);
if (r == -1) {
@@ -364,11 +362,11 @@ _http_cmd(int fd, const char *fmt, ...)
* Get and parse status line
*/
static int
-_http_get_reply(int fd)
+_http_get_reply(conn_t *conn)
{
char *p;
- if (_fetch_getln(fd, &reply_buf, &reply_size, &reply_length) == -1)
+ if (_fetch_getln(conn) == -1)
return (-1);
/*
* A valid status line looks like "HTTP/m.n xyz reason" where m
@@ -379,9 +377,9 @@ _http_get_reply(int fd)
* on finding one, but if we do, insist on it being 1.0 or 1.1.
* We don't care about the reason phrase.
*/
- if (strncmp(reply_buf, "HTTP", 4) != 0)
+ if (strncmp(conn->buf, "HTTP", 4) != 0)
return (HTTP_PROTOCOL_ERROR);
- p = reply_buf + 4;
+ p = conn->buf + 4;
if (*p == '/') {
if (p[1] != '1' || p[2] != '.' || (p[3] != '0' && p[3] != '1'))
return (HTTP_PROTOCOL_ERROR);
@@ -390,7 +388,8 @@ _http_get_reply(int fd)
if (*p != ' ' || !isdigit(p[1]) || !isdigit(p[2]) || !isdigit(p[3]))
return (HTTP_PROTOCOL_ERROR);
- return ((p[1] - '0') * 100 + (p[2] - '0') * 10 + (p[3] - '0'));
+ conn->err = (p[1] - '0') * 100 + (p[2] - '0') * 10 + (p[3] - '0');
+ return (conn->err);
}
/*
@@ -413,17 +412,17 @@ _http_match(const char *str, const char *hdr)
* Get the next header and return the appropriate symbolic code.
*/
static hdr_t
-_http_next_header(int fd, const char **p)
+_http_next_header(conn_t *conn, const char **p)
{
int i;
- if (_fetch_getln(fd, &reply_buf, &reply_size, &reply_length) == -1)
+ if (_fetch_getln(conn) == -1)
return (hdr_syserror);
- while (reply_length && isspace(reply_buf[reply_length-1]))
- reply_length--;
- reply_buf[reply_length] = 0;
- if (reply_length == 0)
- return (hdr_end);
+ while (conn->buflen && isspace(conn->buf[conn->buflen - 1]))
+ conn->buflen--;
+ conn->buf[conn->buflen] = '\0';
+ if (conn->buflen == 0)
+ return (hdr_end);
/*
* We could check for malformed headers but we don't really care.
* A valid header starts with a token immediately followed by a
@@ -431,7 +430,7 @@ _http_next_header(int fd, const char **p)
* characters except "()<>@,;:\\\"{}".
*/
for (i = 0; hdr_names[i].num != hdr_unknown; i++)
- if ((*p = _http_match(hdr_names[i].name, reply_buf)) != NULL)
+ if ((*p = _http_match(hdr_names[i].name, conn->buf)) != NULL)
return (hdr_names[i].num);
return (hdr_unknown);
}
@@ -573,7 +572,7 @@ _http_base64(const char *src)
* Encode username and password
*/
static int
-_http_basic_auth(int fd, const char *hdr, const char *usr, const char *pwd)
+_http_basic_auth(conn_t *conn, const char *hdr, const char *usr, const char *pwd)
{
char *upw, *auth;
int r;
@@ -586,7 +585,7 @@ _http_basic_auth(int fd, const char *hdr, const char *usr, const char *pwd)
free(upw);
if (auth == NULL)
return (-1);
- r = _http_cmd(fd, "%s: Basic %s", hdr, auth);
+ r = _http_cmd(conn, "%s: Basic %s", hdr, auth);
free(auth);
return (r);
}
@@ -595,7 +594,7 @@ _http_basic_auth(int fd, const char *hdr, const char *usr, const char *pwd)
* Send an authorization header
*/
static int
-_http_authorize(int fd, const char *hdr, const char *p)
+_http_authorize(conn_t *conn, const char *hdr, const char *p)
{
/* basic authorization */
if (strncasecmp(p, "basic:", 6) == 0) {
@@ -612,7 +611,7 @@ _http_authorize(int fd, const char *hdr, const char *p)
user = str;
pwd = strchr(str, ':');
*pwd++ = '\0';
- r = _http_basic_auth(fd, hdr, user, pwd);
+ r = _http_basic_auth(conn, hdr, user, pwd);
free(str);
return (r);
}
@@ -627,11 +626,12 @@ _http_authorize(int fd, const char *hdr, const char *p)
/*
* Connect to the correct HTTP server or proxy.
*/
-static int
+static conn_t *
_http_connect(struct url *URL, struct url *purl, const char *flags)
{
+ conn_t *conn;
int verbose;
- int af, fd;
+ int af;
#ifdef INET6
af = AF_UNSPEC;
@@ -652,13 +652,13 @@ _http_connect(struct url *URL, struct url *purl, const char *flags)
} else if (strcasecmp(URL->scheme, SCHEME_FTP) == 0) {
/* can't talk http to an ftp server */
/* XXX should set an error code */
- return (-1);
+ return (NULL);
}
- if ((fd = _fetch_connect(URL->host, URL->port, af, verbose)) == -1)
+ if ((conn = _fetch_connect(URL->host, URL->port, af, verbose)) == NULL)
/* _fetch_connect() has already set an error code */
- return (-1);
- return (fd);
+ return (NULL);
+ return (conn);
}
static struct url *
@@ -730,9 +730,10 @@ FILE *
_http_request(struct url *URL, const char *op, struct url_stat *us,
struct url *purl, const char *flags)
{
+ conn_t *conn;
struct url *url, *new;
int chunked, direct, need_auth, noredirect, verbose;
- int code, fd, i, n;
+ int i, n;
off_t offset, clength, length, size;
time_t mtime;
const char *p;
@@ -782,7 +783,7 @@ _http_request(struct url *URL, const char *op, struct url_stat *us,
}
/* connect to server or proxy */
- if ((fd = _http_connect(url, purl, flags)) == -1)
+ if ((conn = _http_connect(url, purl, flags)) == NULL)
goto ouch;
host = url->host;
@@ -798,36 +799,36 @@ _http_request(struct url *URL, const char *op, struct url_stat *us,
_fetch_info("requesting %s://%s:%d%s",
url->scheme, host, url->port, url->doc);
if (purl) {
- _http_cmd(fd, "%s %s://%s:%d%s HTTP/1.1",
+ _http_cmd(conn, "%s %s://%s:%d%s HTTP/1.1",
op, url->scheme, host, url->port, url->doc);
} else {
- _http_cmd(fd, "%s %s HTTP/1.1",
+ _http_cmd(conn, "%s %s HTTP/1.1",
op, url->doc);
}
/* virtual host */
if (url->port == _fetch_default_port(url->scheme))
- _http_cmd(fd, "Host: %s", host);
+ _http_cmd(conn, "Host: %s", host);
else
- _http_cmd(fd, "Host: %s:%d", host, url->port);
+ _http_cmd(conn, "Host: %s:%d", host, url->port);
/* proxy authorization */
if (purl) {
if (*purl->user || *purl->pwd)
- _http_basic_auth(fd, "Proxy-Authorization",
+ _http_basic_auth(conn, "Proxy-Authorization",
purl->user, purl->pwd);
else if ((p = getenv("HTTP_PROXY_AUTH")) != NULL && *p != '\0')
- _http_authorize(fd, "Proxy-Authorization", p);
+ _http_authorize(conn, "Proxy-Authorization", p);
}
/* server authorization */
if (need_auth || *url->user || *url->pwd) {
if (*url->user || *url->pwd)
- _http_basic_auth(fd, "Authorization", url->user, url->pwd);
+ _http_basic_auth(conn, "Authorization", url->user, url->pwd);
else if ((p = getenv("HTTP_AUTH")) != NULL && *p != '\0')
- _http_authorize(fd, "Authorization", p);
+ _http_authorize(conn, "Authorization", p);
else if (fetchAuthMethod && fetchAuthMethod(url) == 0) {
- _http_basic_auth(fd, "Authorization", url->user, url->pwd);
+ _http_basic_auth(conn, "Authorization", url->user, url->pwd);
} else {
_http_seterr(HTTP_NEED_AUTH);
goto ouch;
@@ -836,16 +837,16 @@ _http_request(struct url *URL, const char *op, struct url_stat *us,
/* other headers */
if ((p = getenv("HTTP_USER_AGENT")) != NULL && *p != '\0')
- _http_cmd(fd, "User-Agent: %s", p);
+ _http_cmd(conn, "User-Agent: %s", p);
else
- _http_cmd(fd, "User-Agent: %s " _LIBFETCH_VER, _getprogname());
+ _http_cmd(conn, "User-Agent: %s " _LIBFETCH_VER, getprogname());
if (url->offset)
- _http_cmd(fd, "Range: bytes=%lld-", (long long)url->offset);
- _http_cmd(fd, "Connection: close");
- _http_cmd(fd, "");
+ _http_cmd(conn, "Range: bytes=%lld-", (long long)url->offset);
+ _http_cmd(conn, "Connection: close");
+ _http_cmd(conn, "");
/* get reply */
- switch ((code = _http_get_reply(fd))) {
+ switch (_http_get_reply(conn)) {
case HTTP_OK:
case HTTP_PARTIAL:
/* fine */
@@ -864,7 +865,7 @@ _http_request(struct url *URL, const char *op, struct url_stat *us,
* We already sent out authorization code, so there's
* nothing more we can do.
*/
- _http_seterr(code);
+ _http_seterr(conn->err);
goto ouch;
}
/* try again, but send the password this time */
@@ -876,7 +877,7 @@ _http_request(struct url *URL, const char *op, struct url_stat *us,
* If we're talking to a proxy, we already sent our proxy
* authorization code, so there's nothing more we can do.
*/
- _http_seterr(code);
+ _http_seterr(conn->err);
goto ouch;
case HTTP_PROTOCOL_ERROR:
/* fall through */
@@ -884,7 +885,7 @@ _http_request(struct url *URL, const char *op, struct url_stat *us,
_fetch_syserr();
goto ouch;
default:
- _http_seterr(code);
+ _http_seterr(conn->err);
if (!verbose)
goto ouch;
/* fall through so we can get the full error message */
@@ -892,7 +893,7 @@ _http_request(struct url *URL, const char *op, struct url_stat *us,
/* get headers */
do {
- switch ((h = _http_next_header(fd, &p))) {
+ switch ((h = _http_next_header(conn, &p))) {
case hdr_syserror:
_fetch_syserr();
goto ouch;
@@ -909,12 +910,12 @@ _http_request(struct url *URL, const char *op, struct url_stat *us,
_http_parse_mtime(p, &mtime);
break;
case hdr_location:
- if (!HTTP_REDIRECT(code))
+ if (!HTTP_REDIRECT(conn->err))
break;
if (new)
free(new);
if (verbose)
- _fetch_info("%d redirect to %s", code, p);
+ _fetch_info("%d redirect to %s", conn->err, p);
if (*p == '/')
/* absolute path */
new = fetchMakeURL(url->scheme, url->host, url->port, p,
@@ -938,7 +939,7 @@ _http_request(struct url *URL, const char *op, struct url_stat *us,
chunked = (strcasecmp(p, "chunked") == 0);
break;
case hdr_www_authenticate:
- if (code != HTTP_NEED_AUTH)
+ if (conn->err != HTTP_NEED_AUTH)
break;
/* if we were smarter, we'd check the method and realm */
break;
@@ -951,21 +952,21 @@ _http_request(struct url *URL, const char *op, struct url_stat *us,
} while (h > hdr_end);
/* we have a hit or an error */
- if (code == HTTP_OK || code == HTTP_PARTIAL || HTTP_ERROR(code))
+ if (conn->err == HTTP_OK || conn->err == HTTP_PARTIAL || HTTP_ERROR(conn->err))
break;
/* we need to provide authentication */
- if (code == HTTP_NEED_AUTH) {
+ if (conn->err == HTTP_NEED_AUTH) {
need_auth = 1;
- close(fd);
- fd = -1;
+ _fetch_close(conn);
+ conn = NULL;
continue;
}
/* all other cases: we got a redirect */
need_auth = 0;
- close(fd);
- fd = -1;
+ _fetch_close(conn);
+ conn = NULL;
if (!new) {
DEBUG(fprintf(stderr, "redirect with no new location\n"));
break;
@@ -976,8 +977,8 @@ _http_request(struct url *URL, const char *op, struct url_stat *us,
} while (++i < n);
/* we failed, or ran out of retries */
- if (fd == -1) {
- _http_seterr(code);
+ if (conn == NULL) {
+ _http_seterr(conn->err);
goto ouch;
}
@@ -1019,7 +1020,13 @@ _http_request(struct url *URL, const char *op, struct url_stat *us,
URL->length = clength;
/* wrap it up in a FILE */
- if ((f = chunked ? _http_funopen(fd) : fdopen(fd, "r")) == NULL) {
+ if (chunked) {
+ f = _http_funopen(conn);
+ } else {
+ f = fdopen(dup(conn->sd), "r");
+ _fetch_close(conn);
+ }
+ if (f == NULL) {
_fetch_syserr();
goto ouch;
}
@@ -1029,7 +1036,7 @@ _http_request(struct url *URL, const char *op, struct url_stat *us,
if (purl)
fetchFreeURL(purl);
- if (HTTP_ERROR(code)) {
+ if (HTTP_ERROR(conn->err)) {
_http_print_html(stderr, f);
fclose(f);
f = NULL;
@@ -1042,8 +1049,8 @@ ouch:
fetchFreeURL(url);
if (purl)
fetchFreeURL(purl);
- if (fd != -1)
- close(fd);
+ if (conn != NULL)
+ _fetch_close(conn);
return (NULL);
}