mirror of
https://github.com/curl/curl.git
synced 2024-11-27 05:50:21 +08:00
The "get ftp command response" function now uses select() on the socket and
thus enables timeout if the server doesn't respond within the proper time.
This commit is contained in:
parent
f836400094
commit
76f3498636
181
lib/ftp.c
181
lib/ftp.c
@ -209,40 +209,93 @@ static CURLcode AllowServerConnect(struct UrlData *data,
|
|||||||
isdigit((int)line[2]) && (' ' == line[3]))
|
isdigit((int)line[2]) && (' ' == line[3]))
|
||||||
|
|
||||||
int GetLastResponse(int sockfd, char *buf,
|
int GetLastResponse(int sockfd, char *buf,
|
||||||
struct UrlData *data)
|
struct connectdata *conn)
|
||||||
{
|
{
|
||||||
int nread;
|
int nread;
|
||||||
int read_rc=1;
|
int keepon=TRUE;
|
||||||
char *ptr;
|
char *ptr;
|
||||||
|
int timeout = 3600; /* in seconds */
|
||||||
|
struct timeval interval;
|
||||||
|
fd_set rkeepfd;
|
||||||
|
fd_set readfd;
|
||||||
|
struct UrlData *data = conn->data;
|
||||||
|
|
||||||
|
#define SELECT_OK 0
|
||||||
|
#define SELECT_ERROR 1
|
||||||
|
#define SELECT_TIMEOUT 2
|
||||||
|
int error = SELECT_OK;
|
||||||
|
|
||||||
|
if(data->timeout) {
|
||||||
|
/* if timeout is requested, find out how much remaining time we have */
|
||||||
|
timeout = data->timeout - /* timeout time */
|
||||||
|
(tvlong(tvnow()) - tvlong(conn->now)); /* spent time */
|
||||||
|
if(timeout <=0 ) {
|
||||||
|
failf(data, "Transfer aborted due to timeout");
|
||||||
|
return -SELECT_TIMEOUT; /* already too little time */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FD_ZERO (&readfd); /* clear it */
|
||||||
|
FD_SET (sockfd, &readfd); /* read socket */
|
||||||
|
|
||||||
|
/* get this in a backup variable to be able to restore it on each lap in the
|
||||||
|
select() loop */
|
||||||
|
rkeepfd = readfd;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
ptr=buf;
|
ptr=buf;
|
||||||
|
|
||||||
/* get us a full line, terminated with a newline */
|
/* get us a full line, terminated with a newline */
|
||||||
for(nread=0;
|
nread=0;
|
||||||
(nread<BUFSIZE) && read_rc;
|
keepon=TRUE;
|
||||||
nread++, ptr++) {
|
while((nread<BUFSIZE) && (keepon && !error)) {
|
||||||
#ifdef USE_SSLEAY
|
readfd = rkeepfd; /* set every lap */
|
||||||
if (data->use_ssl) {
|
interval.tv_sec = timeout;
|
||||||
read_rc = SSL_read(data->ssl, ptr, 1);
|
interval.tv_usec = 0;
|
||||||
}
|
|
||||||
else {
|
switch (select (sockfd+1, &readfd, NULL, NULL, &interval)) {
|
||||||
#endif
|
case -1: /* select() error, stop reading */
|
||||||
read_rc = sread(sockfd, ptr, 1);
|
error = SELECT_ERROR;
|
||||||
#ifdef USE_SSLEAY
|
failf(data, "Transfer aborted due to select() error");
|
||||||
}
|
|
||||||
#endif /* USE_SSLEAY */
|
|
||||||
if (*ptr == '\n')
|
|
||||||
break;
|
break;
|
||||||
|
case 0: /* timeout */
|
||||||
|
error = SELECT_TIMEOUT;
|
||||||
|
infof(data, "Transfer aborted due to timeout\n");
|
||||||
|
failf(data, "Transfer aborted due to timeout");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
#ifdef USE_SSLEAY
|
||||||
|
if (data->use_ssl) {
|
||||||
|
keepon = SSL_read(data->ssl, ptr, 1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
#endif
|
||||||
|
keepon = sread(sockfd, ptr, 1);
|
||||||
|
#ifdef USE_SSLEAY
|
||||||
|
}
|
||||||
|
#endif /* USE_SSLEAY */
|
||||||
|
|
||||||
|
if ((*ptr == '\n') || (*ptr == '\r'))
|
||||||
|
keepon = FALSE;
|
||||||
|
}
|
||||||
|
if(keepon) {
|
||||||
|
nread++;
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
*ptr=0; /* zero terminate */
|
*ptr=0; /* zero terminate */
|
||||||
|
|
||||||
if(data->bits.verbose) {
|
if(data->bits.verbose && buf[0]) {
|
||||||
fputs("< ", data->err);
|
fputs("< ", data->err);
|
||||||
fwrite(buf, 1, nread, data->err);
|
fwrite(buf, 1, nread, data->err);
|
||||||
fputs("\n", data->err);
|
fputs("\n", data->err);
|
||||||
}
|
}
|
||||||
} while(read_rc &&
|
} while(!error &&
|
||||||
(nread<4 || !lastline(buf)) );
|
(nread<4 || !lastline(buf)) );
|
||||||
|
|
||||||
|
if(error)
|
||||||
|
return -error;
|
||||||
|
|
||||||
return nread;
|
return nread;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -315,11 +368,13 @@ static char *URLfix(char *string)
|
|||||||
CURLcode ftp_connect(struct connectdata *conn)
|
CURLcode ftp_connect(struct connectdata *conn)
|
||||||
{
|
{
|
||||||
/* this is FTP and no proxy */
|
/* this is FTP and no proxy */
|
||||||
size_t nread;
|
int nread;
|
||||||
struct UrlData *data=conn->data;
|
struct UrlData *data=conn->data;
|
||||||
char *buf = data->buffer; /* this is our buffer */
|
char *buf = data->buffer; /* this is our buffer */
|
||||||
struct FTP *ftp;
|
struct FTP *ftp;
|
||||||
|
|
||||||
|
myalarm(0); /* switch off the alarm stuff */
|
||||||
|
|
||||||
ftp = (struct FTP *)malloc(sizeof(struct FTP));
|
ftp = (struct FTP *)malloc(sizeof(struct FTP));
|
||||||
if(!ftp)
|
if(!ftp)
|
||||||
return CURLE_OUT_OF_MEMORY;
|
return CURLE_OUT_OF_MEMORY;
|
||||||
@ -333,7 +388,9 @@ CURLcode ftp_connect(struct connectdata *conn)
|
|||||||
ftp->passwd = data->passwd;
|
ftp->passwd = data->passwd;
|
||||||
|
|
||||||
/* The first thing we do is wait for the "220*" line: */
|
/* The first thing we do is wait for the "220*" line: */
|
||||||
nread = GetLastResponse(data->firstsocket, buf, data);
|
nread = GetLastResponse(data->firstsocket, buf, conn);
|
||||||
|
if(nread < 0)
|
||||||
|
return CURLE_OPERATION_TIMEOUTED;
|
||||||
if(strncmp(buf, "220", 3)) {
|
if(strncmp(buf, "220", 3)) {
|
||||||
failf(data, "This doesn't seem like a nice ftp-server response");
|
failf(data, "This doesn't seem like a nice ftp-server response");
|
||||||
return CURLE_FTP_WEIRD_SERVER_REPLY;
|
return CURLE_FTP_WEIRD_SERVER_REPLY;
|
||||||
@ -343,7 +400,9 @@ CURLcode ftp_connect(struct connectdata *conn)
|
|||||||
sendf(data->firstsocket, data, "USER %s\r\n", ftp->user);
|
sendf(data->firstsocket, data, "USER %s\r\n", ftp->user);
|
||||||
|
|
||||||
/* wait for feedback */
|
/* wait for feedback */
|
||||||
nread = GetLastResponse(data->firstsocket, buf, data);
|
nread = GetLastResponse(data->firstsocket, buf, conn);
|
||||||
|
if(nread < 0)
|
||||||
|
return CURLE_OPERATION_TIMEOUTED;
|
||||||
|
|
||||||
if(!strncmp(buf, "530", 3)) {
|
if(!strncmp(buf, "530", 3)) {
|
||||||
/* 530 User ... access denied
|
/* 530 User ... access denied
|
||||||
@ -355,7 +414,9 @@ CURLcode ftp_connect(struct connectdata *conn)
|
|||||||
/* 331 Password required for ...
|
/* 331 Password required for ...
|
||||||
(the server requires to send the user's password too) */
|
(the server requires to send the user's password too) */
|
||||||
sendf(data->firstsocket, data, "PASS %s\r\n", ftp->passwd);
|
sendf(data->firstsocket, data, "PASS %s\r\n", ftp->passwd);
|
||||||
nread = GetLastResponse(data->firstsocket, buf, data);
|
nread = GetLastResponse(data->firstsocket, buf, conn);
|
||||||
|
if(nread < 0)
|
||||||
|
return CURLE_OPERATION_TIMEOUTED;
|
||||||
|
|
||||||
if(!strncmp(buf, "530", 3)) {
|
if(!strncmp(buf, "530", 3)) {
|
||||||
/* 530 Login incorrect.
|
/* 530 Login incorrect.
|
||||||
@ -421,7 +482,9 @@ CURLcode ftp_done(struct connectdata *conn)
|
|||||||
|
|
||||||
/* now let's see what the server says about the transfer we
|
/* now let's see what the server says about the transfer we
|
||||||
just performed: */
|
just performed: */
|
||||||
nread = GetLastResponse(data->firstsocket, buf, data);
|
nread = GetLastResponse(data->firstsocket, buf, conn);
|
||||||
|
if(nread < 0)
|
||||||
|
return CURLE_OPERATION_TIMEOUTED;
|
||||||
|
|
||||||
/* 226 Transfer complete, 250 Requested file action okay, completed. */
|
/* 226 Transfer complete, 250 Requested file action okay, completed. */
|
||||||
if(!strncmp(buf, "226", 3) && !strncmp(buf, "250", 3)) {
|
if(!strncmp(buf, "226", 3) && !strncmp(buf, "250", 3)) {
|
||||||
@ -438,7 +501,9 @@ CURLcode ftp_done(struct connectdata *conn)
|
|||||||
if (qitem->data) {
|
if (qitem->data) {
|
||||||
sendf(data->firstsocket, data, "%s\r\n", qitem->data);
|
sendf(data->firstsocket, data, "%s\r\n", qitem->data);
|
||||||
|
|
||||||
nread = GetLastResponse(data->firstsocket, buf, data);
|
nread = GetLastResponse(data->firstsocket, buf, conn);
|
||||||
|
if(nread < 0)
|
||||||
|
return CURLE_OPERATION_TIMEOUTED;
|
||||||
|
|
||||||
if (buf[0] != '2') {
|
if (buf[0] != '2') {
|
||||||
failf(data, "QUOT string not accepted: %s",
|
failf(data, "QUOT string not accepted: %s",
|
||||||
@ -493,7 +558,9 @@ CURLcode _ftp(struct connectdata *conn)
|
|||||||
if (qitem->data) {
|
if (qitem->data) {
|
||||||
sendf(data->firstsocket, data, "%s\r\n", qitem->data);
|
sendf(data->firstsocket, data, "%s\r\n", qitem->data);
|
||||||
|
|
||||||
nread = GetLastResponse(data->firstsocket, buf, data);
|
nread = GetLastResponse(data->firstsocket, buf, conn);
|
||||||
|
if(nread < 0)
|
||||||
|
return CURLE_OPERATION_TIMEOUTED;
|
||||||
|
|
||||||
if (buf[0] != '2') {
|
if (buf[0] != '2') {
|
||||||
failf(data, "QUOT string not accepted: %s",
|
failf(data, "QUOT string not accepted: %s",
|
||||||
@ -514,7 +581,9 @@ CURLcode _ftp(struct connectdata *conn)
|
|||||||
int filesize;
|
int filesize;
|
||||||
sendf(data->firstsocket, data, "SIZE %s\r\n", ftp->file);
|
sendf(data->firstsocket, data, "SIZE %s\r\n", ftp->file);
|
||||||
|
|
||||||
nread = GetLastResponse(data->firstsocket, buf, data);
|
nread = GetLastResponse(data->firstsocket, buf, conn);
|
||||||
|
if(nread < 0)
|
||||||
|
return CURLE_OPERATION_TIMEOUTED;
|
||||||
|
|
||||||
if(strncmp(buf, "213", 3)) {
|
if(strncmp(buf, "213", 3)) {
|
||||||
failf(data, "Couldn't get file size: %s", buf+4);
|
failf(data, "Couldn't get file size: %s", buf+4);
|
||||||
@ -623,7 +692,9 @@ CURLcode _ftp(struct connectdata *conn)
|
|||||||
porttouse & 255);
|
porttouse & 255);
|
||||||
}
|
}
|
||||||
|
|
||||||
nread = GetLastResponse(data->firstsocket, buf, data);
|
nread = GetLastResponse(data->firstsocket, buf, conn);
|
||||||
|
if(nread < 0)
|
||||||
|
return CURLE_OPERATION_TIMEOUTED;
|
||||||
|
|
||||||
if(strncmp(buf, "200", 3)) {
|
if(strncmp(buf, "200", 3)) {
|
||||||
failf(data, "Server does not grok PORT, try without it!");
|
failf(data, "Server does not grok PORT, try without it!");
|
||||||
@ -634,7 +705,9 @@ CURLcode _ftp(struct connectdata *conn)
|
|||||||
|
|
||||||
sendf(data->firstsocket, data, "PASV\r\n");
|
sendf(data->firstsocket, data, "PASV\r\n");
|
||||||
|
|
||||||
nread = GetLastResponse(data->firstsocket, buf, data);
|
nread = GetLastResponse(data->firstsocket, buf, conn);
|
||||||
|
if(nread < 0)
|
||||||
|
return CURLE_OPERATION_TIMEOUTED;
|
||||||
|
|
||||||
if(strncmp(buf, "227", 3)) {
|
if(strncmp(buf, "227", 3)) {
|
||||||
failf(data, "Odd return code after PASV");
|
failf(data, "Odd return code after PASV");
|
||||||
@ -764,7 +837,9 @@ CURLcode _ftp(struct connectdata *conn)
|
|||||||
|
|
||||||
if(ftp->dir && ftp->dir[0]) {
|
if(ftp->dir && ftp->dir[0]) {
|
||||||
sendf(data->firstsocket, data, "CWD %s\r\n", ftp->dir);
|
sendf(data->firstsocket, data, "CWD %s\r\n", ftp->dir);
|
||||||
nread = GetLastResponse(data->firstsocket, buf, data);
|
nread = GetLastResponse(data->firstsocket, buf, conn);
|
||||||
|
if(nread < 0)
|
||||||
|
return CURLE_OPERATION_TIMEOUTED;
|
||||||
|
|
||||||
if(strncmp(buf, "250", 3)) {
|
if(strncmp(buf, "250", 3)) {
|
||||||
failf(data, "Couldn't change to directory %s", ftp->dir);
|
failf(data, "Couldn't change to directory %s", ftp->dir);
|
||||||
@ -778,7 +853,9 @@ CURLcode _ftp(struct connectdata *conn)
|
|||||||
sendf(data->firstsocket, data, "TYPE %s\r\n",
|
sendf(data->firstsocket, data, "TYPE %s\r\n",
|
||||||
(data->bits.ftp_ascii)?"A":"I");
|
(data->bits.ftp_ascii)?"A":"I");
|
||||||
|
|
||||||
nread = GetLastResponse(data->firstsocket, buf, data);
|
nread = GetLastResponse(data->firstsocket, buf, conn);
|
||||||
|
if(nread < 0)
|
||||||
|
return CURLE_OPERATION_TIMEOUTED;
|
||||||
|
|
||||||
if(strncmp(buf, "200", 3)) {
|
if(strncmp(buf, "200", 3)) {
|
||||||
failf(data, "Couldn't set %s mode",
|
failf(data, "Couldn't set %s mode",
|
||||||
@ -807,7 +884,9 @@ CURLcode _ftp(struct connectdata *conn)
|
|||||||
|
|
||||||
sendf(data->firstsocket, data, "SIZE %s\r\n", ftp->file);
|
sendf(data->firstsocket, data, "SIZE %s\r\n", ftp->file);
|
||||||
|
|
||||||
nread = GetLastResponse(data->firstsocket, buf, data);
|
nread = GetLastResponse(data->firstsocket, buf, conn);
|
||||||
|
if(nread < 0)
|
||||||
|
return CURLE_OPERATION_TIMEOUTED;
|
||||||
|
|
||||||
if(strncmp(buf, "213", 3)) {
|
if(strncmp(buf, "213", 3)) {
|
||||||
failf(data, "Couldn't get file size: %s", buf+4);
|
failf(data, "Couldn't get file size: %s", buf+4);
|
||||||
@ -828,7 +907,9 @@ CURLcode _ftp(struct connectdata *conn)
|
|||||||
|
|
||||||
sendf(data->firstsocket, data, "REST %d\r\n", data->resume_from);
|
sendf(data->firstsocket, data, "REST %d\r\n", data->resume_from);
|
||||||
|
|
||||||
nread = GetLastResponse(data->firstsocket, buf, data);
|
nread = GetLastResponse(data->firstsocket, buf, conn);
|
||||||
|
if(nread < 0)
|
||||||
|
return CURLE_OPERATION_TIMEOUTED;
|
||||||
|
|
||||||
if(strncmp(buf, "350", 3)) {
|
if(strncmp(buf, "350", 3)) {
|
||||||
failf(data, "Couldn't use REST: %s", buf+4);
|
failf(data, "Couldn't use REST: %s", buf+4);
|
||||||
@ -880,7 +961,9 @@ CURLcode _ftp(struct connectdata *conn)
|
|||||||
else
|
else
|
||||||
sendf(data->firstsocket, data, "STOR %s\r\n", ftp->file);
|
sendf(data->firstsocket, data, "STOR %s\r\n", ftp->file);
|
||||||
|
|
||||||
nread = GetLastResponse(data->firstsocket, buf, data);
|
nread = GetLastResponse(data->firstsocket, buf, conn);
|
||||||
|
if(nread < 0)
|
||||||
|
return CURLE_OPERATION_TIMEOUTED;
|
||||||
|
|
||||||
if(atoi(buf)>=400) {
|
if(atoi(buf)>=400) {
|
||||||
failf(data, "Failed FTP upload:%s", buf+3);
|
failf(data, "Failed FTP upload:%s", buf+3);
|
||||||
@ -964,7 +1047,9 @@ CURLcode _ftp(struct connectdata *conn)
|
|||||||
/* Set type to ASCII */
|
/* Set type to ASCII */
|
||||||
sendf(data->firstsocket, data, "TYPE A\r\n");
|
sendf(data->firstsocket, data, "TYPE A\r\n");
|
||||||
|
|
||||||
nread = GetLastResponse(data->firstsocket, buf, data);
|
nread = GetLastResponse(data->firstsocket, buf, conn);
|
||||||
|
if(nread < 0)
|
||||||
|
return CURLE_OPERATION_TIMEOUTED;
|
||||||
|
|
||||||
if(strncmp(buf, "200", 3)) {
|
if(strncmp(buf, "200", 3)) {
|
||||||
failf(data, "Couldn't set ascii mode");
|
failf(data, "Couldn't set ascii mode");
|
||||||
@ -984,7 +1069,9 @@ CURLcode _ftp(struct connectdata *conn)
|
|||||||
sendf(data->firstsocket, data, "TYPE %s\r\n",
|
sendf(data->firstsocket, data, "TYPE %s\r\n",
|
||||||
(data->bits.ftp_list_only)?"A":"I");
|
(data->bits.ftp_list_only)?"A":"I");
|
||||||
|
|
||||||
nread = GetLastResponse(data->firstsocket, buf, data);
|
nread = GetLastResponse(data->firstsocket, buf, conn);
|
||||||
|
if(nread < 0)
|
||||||
|
return CURLE_OPERATION_TIMEOUTED;
|
||||||
|
|
||||||
if(strncmp(buf, "200", 3)) {
|
if(strncmp(buf, "200", 3)) {
|
||||||
failf(data, "Couldn't set %s mode",
|
failf(data, "Couldn't set %s mode",
|
||||||
@ -1003,7 +1090,9 @@ CURLcode _ftp(struct connectdata *conn)
|
|||||||
|
|
||||||
sendf(data->firstsocket, data, "SIZE %s\r\n", ftp->file);
|
sendf(data->firstsocket, data, "SIZE %s\r\n", ftp->file);
|
||||||
|
|
||||||
nread = GetLastResponse(data->firstsocket, buf, data);
|
nread = GetLastResponse(data->firstsocket, buf, conn);
|
||||||
|
if(nread < 0)
|
||||||
|
return CURLE_OPERATION_TIMEOUTED;
|
||||||
|
|
||||||
if(strncmp(buf, "213", 3)) {
|
if(strncmp(buf, "213", 3)) {
|
||||||
infof(data, "server doesn't support SIZE: %s", buf+4);
|
infof(data, "server doesn't support SIZE: %s", buf+4);
|
||||||
@ -1045,7 +1134,9 @@ CURLcode _ftp(struct connectdata *conn)
|
|||||||
|
|
||||||
sendf(data->firstsocket, data, "REST %d\r\n", data->resume_from);
|
sendf(data->firstsocket, data, "REST %d\r\n", data->resume_from);
|
||||||
|
|
||||||
nread = GetLastResponse(data->firstsocket, buf, data);
|
nread = GetLastResponse(data->firstsocket, buf, conn);
|
||||||
|
if(nread < 0)
|
||||||
|
return CURLE_OPERATION_TIMEOUTED;
|
||||||
|
|
||||||
if(strncmp(buf, "350", 3)) {
|
if(strncmp(buf, "350", 3)) {
|
||||||
failf(data, "Couldn't use REST: %s", buf+4);
|
failf(data, "Couldn't use REST: %s", buf+4);
|
||||||
@ -1056,7 +1147,9 @@ CURLcode _ftp(struct connectdata *conn)
|
|||||||
sendf(data->firstsocket, data, "RETR %s\r\n", ftp->file);
|
sendf(data->firstsocket, data, "RETR %s\r\n", ftp->file);
|
||||||
}
|
}
|
||||||
|
|
||||||
nread = GetLastResponse(data->firstsocket, buf, data);
|
nread = GetLastResponse(data->firstsocket, buf, conn);
|
||||||
|
if(nread < 0)
|
||||||
|
return CURLE_OPERATION_TIMEOUTED;
|
||||||
|
|
||||||
if(!strncmp(buf, "150", 3) || !strncmp(buf, "125", 3)) {
|
if(!strncmp(buf, "150", 3) || !strncmp(buf, "125", 3)) {
|
||||||
|
|
||||||
@ -1079,12 +1172,16 @@ CURLcode _ftp(struct connectdata *conn)
|
|||||||
|
|
||||||
int size=-1; /* default unknown size */
|
int size=-1; /* default unknown size */
|
||||||
|
|
||||||
if(!dirlist && (-1 == downloadsize)) {
|
if(!dirlist &&
|
||||||
|
!data->bits.ftp_ascii &&
|
||||||
|
(-1 == downloadsize)) {
|
||||||
/*
|
/*
|
||||||
* It seems directory listings either don't show the size or very
|
* It seems directory listings either don't show the size or very
|
||||||
* often uses size 0 anyway.
|
* often uses size 0 anyway. ASCII transfers may very well turn out
|
||||||
* Example D above makes this parsing a little tricky
|
* that the transfered amount of data is not the same as this line
|
||||||
*/
|
* tells, why using this number in those cases only confuses us.
|
||||||
|
*
|
||||||
|
* Example D above makes this parsing a little tricky */
|
||||||
char *bytes;
|
char *bytes;
|
||||||
bytes=strstr(buf, " bytes");
|
bytes=strstr(buf, " bytes");
|
||||||
if(bytes--) {
|
if(bytes--) {
|
||||||
|
Loading…
Reference in New Issue
Block a user