summaryrefslogtreecommitdiffstats
path: root/lib/libfetch/ftp.c
diff options
context:
space:
mode:
authordes <des@FreeBSD.org>2002-06-05 10:05:03 +0000
committerdes <des@FreeBSD.org>2002-06-05 10:05:03 +0000
commite07ac3bab378d02dca475f92e0592bb4ecd5f018 (patch)
tree2d0745a2b622f4f25fdcff8a8d2ce1eeea0b7447 /lib/libfetch/ftp.c
parent306d84207e66a03a612bdc2511115dfd7c673ef3 (diff)
downloadFreeBSD-src-e07ac3bab378d02dca475f92e0592bb4ecd5f018.zip
FreeBSD-src-e07ac3bab378d02dca475f92e0592bb4ecd5f018.tar.gz
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.
Diffstat (limited to 'lib/libfetch/ftp.c')
-rw-r--r--lib/libfetch/ftp.c181
1 files changed, 89 insertions, 92 deletions
diff --git a/lib/libfetch/ftp.c b/lib/libfetch/ftp.c
index 489c52d..734ec09 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));
}
/*
OpenPOWER on IntegriCloud