moved the PORT and PASV code into separate smaller functions for readability

renamed all static ^_ftp_* functions to ^ftp_, prefixing with underscore is
not nice
This commit is contained in:
Daniel Stenberg 2001-09-28 08:58:18 +00:00
parent 4d13b2cc64
commit 8333644c84
1 changed files with 555 additions and 499 deletions

322
lib/ftp.c
View File

@ -92,8 +92,8 @@
#endif #endif
/* Local API functions */ /* Local API functions */
static CURLcode _ftp_sendquote(struct connectdata *conn, struct curl_slist *quote); static CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote);
static CURLcode _ftp_cwd(struct connectdata *conn, char *path); static CURLcode ftp_cwd(struct connectdata *conn, char *path);
/* easy-to-use macro: */ /* easy-to-use macro: */
#define ftpsendf Curl_ftpsendf #define ftpsendf Curl_ftpsendf
@ -590,7 +590,7 @@ CURLcode Curl_ftp_done(struct connectdata *conn)
/* Send any post-transfer QUOTE strings? */ /* Send any post-transfer QUOTE strings? */
if(data->set.postquote) { if(data->set.postquote) {
CURLcode result = _ftp_sendquote(conn, data->set.postquote); CURLcode result = ftp_sendquote(conn, data->set.postquote);
return result; return result;
} }
@ -599,7 +599,7 @@ CURLcode Curl_ftp_done(struct connectdata *conn)
static static
CURLcode _ftp_sendquote(struct connectdata *conn, struct curl_slist *quote) CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote)
{ {
struct curl_slist *item; struct curl_slist *item;
ssize_t nread; ssize_t nread;
@ -628,7 +628,7 @@ CURLcode _ftp_sendquote(struct connectdata *conn, struct curl_slist *quote)
} }
static static
CURLcode _ftp_cwd(struct connectdata *conn, char *path) CURLcode ftp_cwd(struct connectdata *conn, char *path)
{ {
ssize_t nread; ssize_t nread;
int ftpcode; int ftpcode;
@ -648,7 +648,7 @@ CURLcode _ftp_cwd(struct connectdata *conn, char *path)
} }
static static
CURLcode _ftp_getfiletime(struct connectdata *conn, char *file) CURLcode ftp_getfiletime(struct connectdata *conn, char *file)
{ {
CURLcode result=CURLE_OK; CURLcode result=CURLE_OK;
int ftpcode; /* for ftp status */ int ftpcode; /* for ftp status */
@ -683,7 +683,7 @@ CURLcode _ftp_getfiletime(struct connectdata *conn, char *file)
return result; return result;
} }
static CURLcode _ftp_transfertype(struct connectdata *conn, static CURLcode ftp_transfertype(struct connectdata *conn,
bool ascii) bool ascii)
{ {
struct SessionHandle *data = conn->data; struct SessionHandle *data = conn->data;
@ -707,7 +707,7 @@ static CURLcode _ftp_transfertype(struct connectdata *conn,
} }
static static
CURLcode _ftp_getsize(struct connectdata *conn, char *file, CURLcode ftp_getsize(struct connectdata *conn, char *file,
ssize_t *size) ssize_t *size)
{ {
struct SessionHandle *data = conn->data; struct SessionHandle *data = conn->data;
@ -741,12 +741,9 @@ CURLcode _ftp_getsize(struct connectdata *conn, char *file,
*/ */
static void static void
ftp_pasv_verbose(struct connectdata *conn, ftp_pasv_verbose(struct connectdata *conn,
#ifdef ENABLE_IPV6 Curl_addrinfo *addr,
struct addrinfo *newhost char *newhost, /* ascii version */
#else int port)
char *newhost /* ipv4 */
#endif
)
{ {
#ifndef ENABLE_IPV6 #ifndef ENABLE_IPV6
/***************************************************************** /*****************************************************************
@ -757,11 +754,10 @@ ftp_pasv_verbose(struct connectdata *conn,
struct in_addr in; struct in_addr in;
struct hostent * answer; struct hostent * answer;
#if defined (HAVE_INET_NTOA_R) #ifdef HAVE_INET_NTOA_R
char ntoa_buf[64]; char ntoa_buf[64];
#endif #endif
#ifndef ENABLE_IPV6 #ifndef ENABLE_IPV6
struct sockaddr_in serv_addr;
char hostent_buf[8192]; char hostent_buf[8192];
#endif #endif
@ -817,11 +813,11 @@ ftp_pasv_verbose(struct connectdata *conn,
infof(conn->data, "Connecting to %s (%s) port %u\n", infof(conn->data, "Connecting to %s (%s) port %u\n",
answer?answer->h_name:newhost, answer?answer->h_name:newhost,
#if defined(HAVE_INET_NTOA_R) #if defined(HAVE_INET_NTOA_R)
inet_ntoa_r(in, ip_addr=ntoa_buf, sizeof(ntoa_buf)), inet_ntoa_r(in, ntoa_buf, sizeof(ntoa_buf)),
#else #else
ip_addr = inet_ntoa(in), inet_ntoa(in),
#endif #endif
connectport); port);
#else #else
/***************************************************************** /*****************************************************************
@ -836,13 +832,13 @@ ftp_pasv_verbose(struct connectdata *conn,
#else #else
const int niflags = NI_NUMERICHOST | NI_NUMERICSERV; const int niflags = NI_NUMERICHOST | NI_NUMERICSERV;
#endif #endif
if (getnameinfo(newhost->ai_addr, newhost->ai_addrlen, if (getnameinfo(addr->ai_addr, addr->ai_addrlen,
nbuf, sizeof(nbuf), sbuf, sizeof(sbuf), niflags)) { nbuf, sizeof(nbuf), sbuf, sizeof(sbuf), niflags)) {
snprintf(nbuf, sizeof(nbuf), "?"); snprintf(nbuf, sizeof(nbuf), "?");
snprintf(sbuf, sizeof(sbuf), "?"); snprintf(sbuf, sizeof(sbuf), "?");
} }
if (getnameinfo(newhost->ai_addr, newhost->ai_addrlen, if (getnameinfo(addr->ai_addr, addr->ai_addrlen,
hbuf, sizeof(hbuf), NULL, 0, 0)) { hbuf, sizeof(hbuf), NULL, 0, 0)) {
infof(conn->data, "Connecting to %s port %s\n", nbuf, sbuf); infof(conn->data, "Connecting to %s port %s\n", nbuf, sbuf);
} }
@ -850,104 +846,30 @@ ftp_pasv_verbose(struct connectdata *conn,
infof(conn->data, "Connecting to %s (%s) port %s\n", hbuf, nbuf, sbuf); infof(conn->data, "Connecting to %s (%s) port %s\n", hbuf, nbuf, sbuf);
} }
#endif #endif
} }
/**********
* PORT is the ftp client's way of telling the server that *WE* open a port
* that we listen on an awaits the server to connect to. This is the opposite
* of PASV.
*/
static static
CURLcode _ftp(struct connectdata *conn) CURLcode ftp_use_port(struct connectdata *conn)
{ {
/* this is FTP and no proxy */
ssize_t nread;
CURLcode result;
struct SessionHandle *data=conn->data; struct SessionHandle *data=conn->data;
char *buf = data->state.buffer; /* this is our buffer */
/* for the ftp PORT mode */
int portsock=-1; int portsock=-1;
/* the ftp struct is already inited in ftp_connect() */ ssize_t nread;
struct FTP *ftp = conn->proto.ftp; char *buf = data->state.buffer; /* this is our buffer */
int ftpcode; /* receive FTP response codes in this */
long *bytecountp = ftp->bytecountp;
int ftpcode; /* for ftp status */
/* Send any QUOTE strings? */
if(data->set.quote) {
if ((result = _ftp_sendquote(conn, data->set.quote)) != CURLE_OK)
return result;
}
/* This is a re-used connection. Since we change directory to where the
transfer is taking place, we must now get back to the original dir
where we ended up after login: */
if (conn->bits.reuse) {
if ((result = _ftp_cwd(conn, ftp->entrypath)) != CURLE_OK)
return result;
}
/* change directory first! */
if(ftp->dir && ftp->dir[0]) {
if ((result = _ftp_cwd(conn, ftp->dir)) != CURLE_OK)
return result;
}
/* Requested time of file? */
if(data->set.get_filetime && ftp->file) {
result = _ftp_getfiletime(conn, ftp->file);
if(result)
return result;
}
/* If we have selected NOBODY, it means that we only want file information.
Which in FTP can't be much more than the file size! */
if(data->set.no_body) {
/* The SIZE command is _not_ RFC 959 specified, and therefor many servers
may not support it! It is however the only way we have to get a file's
size! */
ssize_t filesize;
/* Some servers return different sizes for different modes, and thus we
must set the proper type before we check the size */
result = _ftp_transfertype(conn, data->set.ftp_ascii);
if(result)
return result;
/* failing to get size is not a serious error */
result = _ftp_getsize(conn, ftp->file, &filesize);
if(CURLE_OK == result) {
sprintf(buf, "Content-Length: %d\r\n", filesize);
result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
if(result)
return result;
}
/* If we asked for a time of the file and we actually got one as
well, we "emulate" a HTTP-style header in our output. */
#ifdef HAVE_STRFTIME
if(data->set.get_filetime && data->info.filetime) {
struct tm *tm;
#ifdef HAVE_LOCALTIME_R
struct tm buffer;
tm = (struct tm *)localtime_r(&data->info.filetime, &buffer);
#else
tm = localtime(&data->info.filetime);
#endif
/* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
strftime(buf, BUFSIZE-1, "Last-Modified: %a, %d %b %Y %H:%M:%S %Z\r\n",
tm);
result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
if(result)
return result;
}
#endif
return CURLE_OK;
}
/* We have chosen to use the PORT command */
if(data->set.ftp_use_port) {
#ifdef ENABLE_IPV6 #ifdef ENABLE_IPV6
/******************************************************************
*
* Here's a piece of IPv6-specific code coming up
*
*/
struct addrinfo hints, *res, *ai; struct addrinfo hints, *res, *ai;
struct sockaddr_storage ss; struct sockaddr_storage ss;
socklen_t sslen; socklen_t sslen;
@ -1076,7 +998,8 @@ CURLcode _ftp(struct connectdata *conn)
portmsgbuf[0] = '\0'; portmsgbuf[0] = '\0';
if (strcmp(*modep, "LPRT") == 0) { if (strcmp(*modep, "LPRT") == 0) {
snprintf(tmp, sizeof(tmp), "%d,%d", lprtaf, alen); snprintf(tmp, sizeof(tmp), "%d,%d", lprtaf, alen);
if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >= sizeof(portmsgbuf)) { if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >=
sizeof(portmsgbuf)) {
continue; continue;
} }
} }
@ -1087,7 +1010,8 @@ CURLcode _ftp(struct connectdata *conn)
else else
snprintf(tmp, sizeof(tmp), "%u", ap[i]); snprintf(tmp, sizeof(tmp), "%u", ap[i]);
if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >= sizeof(portmsgbuf)) { if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >=
sizeof(portmsgbuf)) {
continue; continue;
} }
} }
@ -1102,7 +1026,8 @@ CURLcode _ftp(struct connectdata *conn)
for (i = 0; i < plen; i++) { for (i = 0; i < plen; i++) {
snprintf(tmp, sizeof(tmp), ",%u", pp[i]); snprintf(tmp, sizeof(tmp), ",%u", pp[i]);
if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >= sizeof(portmsgbuf)) { if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >=
sizeof(portmsgbuf)) {
continue; continue;
} }
} }
@ -1117,7 +1042,8 @@ CURLcode _ftp(struct connectdata *conn)
if (ftpcode != 200) { if (ftpcode != 200) {
failf(data, "Server does not grok %s", *modep); failf(data, "Server does not grok %s", *modep);
continue; continue;
} else }
else
break; break;
} }
@ -1132,6 +1058,11 @@ CURLcode _ftp(struct connectdata *conn)
conn->secondarysocket = portsock; conn->secondarysocket = portsock;
#else #else
/******************************************************************
*
* Here's a piece of IPv4-specific code coming up
*
*/
struct sockaddr_in sa; struct sockaddr_in sa;
struct hostent *h=NULL; struct hostent *h=NULL;
char *hostdataptr=NULL; char *hostdataptr=NULL;
@ -1212,10 +1143,13 @@ CURLcode _ftp(struct connectdata *conn)
return CURLE_FTP_PORT_FAILED; return CURLE_FTP_PORT_FAILED;
} }
{ {
#ifdef HAVE_INET_NTOA_R
char ntoa_buf[64];
#endif
struct in_addr in; struct in_addr in;
unsigned short ip[5]; unsigned short ip[5];
(void) memcpy(&in.s_addr, *h->h_addr_list, sizeof (in.s_addr)); (void) memcpy(&in.s_addr, *h->h_addr_list, sizeof (in.s_addr));
#if defined (HAVE_INET_NTOA_R) #ifdef HAVE_INET_NTOA_R
/* ignore the return code from inet_ntoa_r() as it is int or /* ignore the return code from inet_ntoa_r() as it is int or
char * depending on system */ char * depending on system */
inet_ntoa_r(in, ntoa_buf, sizeof(ntoa_buf)); inet_ntoa_r(in, ntoa_buf, sizeof(ntoa_buf));
@ -1239,9 +1173,26 @@ CURLcode _ftp(struct connectdata *conn)
failf(data, "Server does not grok PORT, try without it!"); failf(data, "Server does not grok PORT, try without it!");
return CURLE_FTP_PORT_FAILED; return CURLE_FTP_PORT_FAILED;
} }
#endif /* ENABLE_IPV6 */ #endif /* end of ipv4-specific code */
}
else { /* we use the PASV command */ return CURLE_OK;
}
/**********
* PASV is the ftp client's way of asking the server to open a second port
* that we can connect to (for the data transfer). This is the opposite of
* PORT.
*/
static
CURLcode ftp_use_pasv(struct connectdata *conn)
{
struct SessionHandle *data = conn->data;
ssize_t nread;
char *buf = data->state.buffer; /* this is our buffer */
int ftpcode; /* receive FTP response codes in this */
CURLcode result;
#if 0 #if 0
/* no support for IPv6 passive mode yet */ /* no support for IPv6 passive mode yet */
char *mode[] = { "EPSV", "LPSV", "PASV", NULL }; char *mode[] = { "EPSV", "LPSV", "PASV", NULL };
@ -1276,10 +1227,10 @@ CURLcode _ftp(struct connectdata *conn)
Curl_addrinfo *addr; Curl_addrinfo *addr;
char *hostdataptr=NULL; char *hostdataptr=NULL;
#ifndef ENABLE_IPV6 #ifdef ENABLE_IPV6
char *ip_addr;
#else
struct addrinfo *ai; struct addrinfo *ai;
#else
struct sockaddr_in serv_addr;
#endif #endif
char *str=buf; char *str=buf;
@ -1349,7 +1300,7 @@ CURLcode _ftp(struct connectdata *conn)
if(data->set.verbose) if(data->set.verbose)
/* this just dumps information about this second connection */ /* this just dumps information about this second connection */
ftp_pasv_verbose(conn, ai); ftp_pasv_verbose(conn, ai, newhost, 0 /* port not really known */);
break; break;
} }
@ -1369,7 +1320,7 @@ CURLcode _ftp(struct connectdata *conn)
if(data->set.verbose) if(data->set.verbose)
/* this just dumps information about this second connection */ /* this just dumps information about this second connection */
ftp_pasv_verbose(conn, newhost); ftp_pasv_verbose(conn, addr, newhost, connectport);
if(hostdataptr) if(hostdataptr)
free(hostdataptr); free(hostdataptr);
@ -1403,17 +1354,122 @@ CURLcode _ftp(struct connectdata *conn)
if(CURLE_OK != result) if(CURLE_OK != result)
return result; return result;
} }
} else { }
else
return CURLE_FTP_CANT_RECONNECT; return CURLE_FTP_CANT_RECONNECT;
return CURLE_OK;
}
static
CURLcode ftp_perform(struct connectdata *conn)
{
/* this is FTP and no proxy */
ssize_t nread;
CURLcode result;
struct SessionHandle *data=conn->data;
char *buf = data->state.buffer; /* this is our buffer */
/* the ftp struct is already inited in ftp_connect() */
struct FTP *ftp = conn->proto.ftp;
long *bytecountp = ftp->bytecountp;
int ftpcode; /* for ftp status */
/* Send any QUOTE strings? */
if(data->set.quote) {
if ((result = ftp_sendquote(conn, data->set.quote)) != CURLE_OK)
return result;
} }
/* This is a re-used connection. Since we change directory to where the
transfer is taking place, we must now get back to the original dir
where we ended up after login: */
if (conn->bits.reuse) {
if ((result = ftp_cwd(conn, ftp->entrypath)) != CURLE_OK)
return result;
} }
/* we have the (new) data connection ready */
/* change directory first! */
if(ftp->dir && ftp->dir[0]) {
if ((result = ftp_cwd(conn, ftp->dir)) != CURLE_OK)
return result;
}
/* Requested time of file? */
if(data->set.get_filetime && ftp->file) {
result = ftp_getfiletime(conn, ftp->file);
if(result)
return result;
}
/* If we have selected NOBODY, it means that we only want file information.
Which in FTP can't be much more than the file size! */
if(data->set.no_body) {
/* The SIZE command is _not_ RFC 959 specified, and therefor many servers
may not support it! It is however the only way we have to get a file's
size! */
ssize_t filesize;
/* Some servers return different sizes for different modes, and thus we
must set the proper type before we check the size */
result = ftp_transfertype(conn, data->set.ftp_ascii);
if(result)
return result;
/* failing to get size is not a serious error */
result = ftp_getsize(conn, ftp->file, &filesize);
if(CURLE_OK == result) {
sprintf(buf, "Content-Length: %d\r\n", filesize);
result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
if(result)
return result;
}
/* If we asked for a time of the file and we actually got one as
well, we "emulate" a HTTP-style header in our output. */
#ifdef HAVE_STRFTIME
if(data->set.get_filetime && data->info.filetime) {
struct tm *tm;
#ifdef HAVE_LOCALTIME_R
struct tm buffer;
tm = (struct tm *)localtime_r(&data->info.filetime, &buffer);
#else
tm = localtime(&data->info.filetime);
#endif
/* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
strftime(buf, BUFSIZE-1, "Last-Modified: %a, %d %b %Y %H:%M:%S %Z\r\n",
tm);
result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
if(result)
return result;
}
#endif
return CURLE_OK;
}
/* Get us a second connection up and connected */
if(data->set.ftp_use_port)
/* We have chosen to use the PORT command */
result = ftp_use_port(conn);
else
/* We have chosen (this is default) to use the PASV command */
result = ftp_use_pasv(conn);
if(result)
return result;
/* we have the data connection ready */
infof(data, "Connected the data stream!\n"); infof(data, "Connected the data stream!\n");
if(data->set.upload) { if(data->set.upload) {
/* Set type to binary (unless specified ASCII) */ /* Set type to binary (unless specified ASCII) */
result = _ftp_transfertype(conn, data->set.ftp_ascii); result = ftp_transfertype(conn, data->set.ftp_ascii);
if(result) if(result)
return result; return result;
@ -1435,7 +1491,7 @@ CURLcode _ftp(struct connectdata *conn)
/* we could've got a specified offset from the command line, /* we could've got a specified offset from the command line,
but now we know we didn't */ but now we know we didn't */
if(CURLE_OK != _ftp_getsize(conn, ftp->file, &conn->resume_from)) { if(CURLE_OK != ftp_getsize(conn, ftp->file, &conn->resume_from)) {
failf(data, "Couldn't get remote file size"); failf(data, "Couldn't get remote file size");
return CURLE_FTP_COULDNT_GET_SIZE; return CURLE_FTP_COULDNT_GET_SIZE;
} }
@ -1510,7 +1566,7 @@ CURLcode _ftp(struct connectdata *conn)
if(data->set.ftp_use_port) { if(data->set.ftp_use_port) {
/* PORT means we are now awaiting the server to connect to us. */ /* PORT means we are now awaiting the server to connect to us. */
result = AllowServerConnect(data, conn, portsock); result = AllowServerConnect(data, conn, conn->secondarysocket);
if( result ) if( result )
return result; return result;
} }
@ -1578,7 +1634,7 @@ CURLcode _ftp(struct connectdata *conn)
dirlist = TRUE; dirlist = TRUE;
/* Set type to ASCII */ /* Set type to ASCII */
result = _ftp_transfertype(conn, TRUE /* ASCII enforced */); result = ftp_transfertype(conn, TRUE /* ASCII enforced */);
if(result) if(result)
return result; return result;
@ -1592,7 +1648,7 @@ CURLcode _ftp(struct connectdata *conn)
} }
else { else {
/* Set type to binary (unless specified ASCII) */ /* Set type to binary (unless specified ASCII) */
result = _ftp_transfertype(conn, data->set.ftp_ascii); result = ftp_transfertype(conn, data->set.ftp_ascii);
if(result) if(result)
return result; return result;
@ -1605,7 +1661,7 @@ CURLcode _ftp(struct connectdata *conn)
* the best way to know if we're trying to resume beyond the EOF. */ * the best way to know if we're trying to resume beyond the EOF. */
int foundsize=-1; int foundsize=-1;
result = _ftp_getsize(conn, ftp->file, &foundsize); result = ftp_getsize(conn, ftp->file, &foundsize);
if(CURLE_OK != result) { if(CURLE_OK != result) {
infof(data, "ftp server doesn't support SIZE\n"); infof(data, "ftp server doesn't support SIZE\n");
@ -1736,7 +1792,7 @@ CURLcode _ftp(struct connectdata *conn)
size = downloadsize; size = downloadsize;
if(data->set.ftp_use_port) { if(data->set.ftp_use_port) {
result = AllowServerConnect(data, conn, portsock); result = AllowServerConnect(data, conn, conn->secondarysocket);
if( result ) if( result )
return result; return result;
} }
@ -1813,7 +1869,7 @@ CURLcode Curl_ftp(struct connectdata *conn)
else else
ftp->dir = NULL; ftp->dir = NULL;
retcode = _ftp(conn); retcode = ftp_perform(conn);
/* clean up here, success or error doesn't matter */ /* clean up here, success or error doesn't matter */
if(ftp->file) if(ftp->file)