aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2000-07-25 12:12:29 +0000
committerDaniel Stenberg <daniel@haxx.se>2000-07-25 12:12:29 +0000
commit76f34986362fa5a0c33a971e45d0747166605e70 (patch)
treeebc455d28be6cb9b1596e104d839818571aa0a3b /lib
parentf836400094463b0479103b7761375c4188dc7bb6 (diff)
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.
Diffstat (limited to 'lib')
-rw-r--r--lib/ftp.c175
1 files changed, 136 insertions, 39 deletions
diff --git a/lib/ftp.c b/lib/ftp.c
index b651048d5..39a0a64bf 100644
--- a/lib/ftp.c
+++ b/lib/ftp.c
@@ -209,40 +209,93 @@ static CURLcode AllowServerConnect(struct UrlData *data,
isdigit((int)line[2]) && (' ' == line[3]))
int GetLastResponse(int sockfd, char *buf,
- struct UrlData *data)
+ struct connectdata *conn)
{
int nread;
- int read_rc=1;
+ int keepon=TRUE;
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 {
ptr=buf;
/* get us a full line, terminated with a newline */
- for(nread=0;
- (nread<BUFSIZE) && read_rc;
- nread++, ptr++) {
+ nread=0;
+ keepon=TRUE;
+ while((nread<BUFSIZE) && (keepon && !error)) {
+ readfd = rkeepfd; /* set every lap */
+ interval.tv_sec = timeout;
+ interval.tv_usec = 0;
+
+ switch (select (sockfd+1, &readfd, NULL, NULL, &interval)) {
+ case -1: /* select() error, stop reading */
+ error = SELECT_ERROR;
+ failf(data, "Transfer aborted due to select() error");
+ 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) {
- read_rc = SSL_read(data->ssl, ptr, 1);
- }
- else {
+ if (data->use_ssl) {
+ keepon = SSL_read(data->ssl, ptr, 1);
+ }
+ else {
#endif
- read_rc = sread(sockfd, ptr, 1);
+ keepon = sread(sockfd, ptr, 1);
#ifdef USE_SSLEAY
- }
+ }
#endif /* USE_SSLEAY */
- if (*ptr == '\n')
- break;
+
+ if ((*ptr == '\n') || (*ptr == '\r'))
+ keepon = FALSE;
+ }
+ if(keepon) {
+ nread++;
+ ptr++;
+ }
}
*ptr=0; /* zero terminate */
- if(data->bits.verbose) {
+ if(data->bits.verbose && buf[0]) {
fputs("< ", data->err);
fwrite(buf, 1, nread, data->err);
fputs("\n", data->err);
}
- } while(read_rc &&
+ } while(!error &&
(nread<4 || !lastline(buf)) );
+
+ if(error)
+ return -error;
+
return nread;
}
@@ -315,11 +368,13 @@ static char *URLfix(char *string)
CURLcode ftp_connect(struct connectdata *conn)
{
/* this is FTP and no proxy */
- size_t nread;
+ int nread;
struct UrlData *data=conn->data;
char *buf = data->buffer; /* this is our buffer */
struct FTP *ftp;
+ myalarm(0); /* switch off the alarm stuff */
+
ftp = (struct FTP *)malloc(sizeof(struct FTP));
if(!ftp)
return CURLE_OUT_OF_MEMORY;
@@ -333,7 +388,9 @@ CURLcode ftp_connect(struct connectdata *conn)
ftp->passwd = data->passwd;
/* 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)) {
failf(data, "This doesn't seem like a nice ftp-server response");
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);
/* 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)) {
/* 530 User ... access denied
@@ -355,7 +414,9 @@ CURLcode ftp_connect(struct connectdata *conn)
/* 331 Password required for ...
(the server requires to send the user's password too) */
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)) {
/* 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
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. */
if(!strncmp(buf, "226", 3) && !strncmp(buf, "250", 3)) {
@@ -438,7 +501,9 @@ CURLcode ftp_done(struct connectdata *conn)
if (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') {
failf(data, "QUOT string not accepted: %s",
@@ -493,7 +558,9 @@ CURLcode _ftp(struct connectdata *conn)
if (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') {
failf(data, "QUOT string not accepted: %s",
@@ -514,7 +581,9 @@ CURLcode _ftp(struct connectdata *conn)
int filesize;
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)) {
failf(data, "Couldn't get file size: %s", buf+4);
@@ -623,7 +692,9 @@ CURLcode _ftp(struct connectdata *conn)
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)) {
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");
- nread = GetLastResponse(data->firstsocket, buf, data);
+ nread = GetLastResponse(data->firstsocket, buf, conn);
+ if(nread < 0)
+ return CURLE_OPERATION_TIMEOUTED;
if(strncmp(buf, "227", 3)) {
failf(data, "Odd return code after PASV");
@@ -764,7 +837,9 @@ CURLcode _ftp(struct connectdata *conn)
if(ftp->dir && ftp->dir[0]) {
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)) {
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",
(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)) {
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);
- nread = GetLastResponse(data->firstsocket, buf, data);
+ nread = GetLastResponse(data->firstsocket, buf, conn);
+ if(nread < 0)
+ return CURLE_OPERATION_TIMEOUTED;
if(strncmp(buf, "213", 3)) {
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);
- nread = GetLastResponse(data->firstsocket, buf, data);
+ nread = GetLastResponse(data->firstsocket, buf, conn);
+ if(nread < 0)
+ return CURLE_OPERATION_TIMEOUTED;
if(strncmp(buf, "350", 3)) {
failf(data, "Couldn't use REST: %s", buf+4);
@@ -880,7 +961,9 @@ CURLcode _ftp(struct connectdata *conn)
else
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) {
failf(data, "Failed FTP upload:%s", buf+3);
@@ -964,7 +1047,9 @@ CURLcode _ftp(struct connectdata *conn)
/* Set type to ASCII */
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)) {
failf(data, "Couldn't set ascii mode");
@@ -984,7 +1069,9 @@ CURLcode _ftp(struct connectdata *conn)
sendf(data->firstsocket, data, "TYPE %s\r\n",
(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)) {
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);
- nread = GetLastResponse(data->firstsocket, buf, data);
+ nread = GetLastResponse(data->firstsocket, buf, conn);
+ if(nread < 0)
+ return CURLE_OPERATION_TIMEOUTED;
if(strncmp(buf, "213", 3)) {
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);
- nread = GetLastResponse(data->firstsocket, buf, data);
+ nread = GetLastResponse(data->firstsocket, buf, conn);
+ if(nread < 0)
+ return CURLE_OPERATION_TIMEOUTED;
if(strncmp(buf, "350", 3)) {
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);
}
- 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)) {
@@ -1079,12 +1172,16 @@ CURLcode _ftp(struct connectdata *conn)
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
- * often uses size 0 anyway.
- * Example D above makes this parsing a little tricky
- */
+ * often uses size 0 anyway. ASCII transfers may very well turn out
+ * 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;
bytes=strstr(buf, " bytes");
if(bytes--) {