diff options
author | Dag-Erling Smørgrav <des@FreeBSD.org> | 2002-06-05 10:05:03 +0000 |
---|---|---|
committer | Dag-Erling Smørgrav <des@FreeBSD.org> | 2002-06-05 10:05:03 +0000 |
commit | dea29ca1d5850eb6fd7771a1ad8f41ce46665995 (patch) | |
tree | 2d0745a2b622f4f25fdcff8a8d2ce1eeea0b7447 | |
parent | 09dbd0701c7afa1777170ab990fac8df61b789e6 (diff) | |
download | src-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.c | 80 | ||||
-rw-r--r-- | lib/libfetch/common.h | 29 | ||||
-rw-r--r-- | lib/libfetch/ftp.c | 181 | ||||
-rw-r--r-- | lib/libfetch/http.c | 161 |
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); } |