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:
Daniel Stenberg 2000-07-25 12:12:29 +00:00
parent f836400094
commit 76f3498636

181
lib/ftp.c
View File

@ -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--) {