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; - (nreaduse_ssl) { - read_rc = SSL_read(data->ssl, ptr, 1); - } - else { -#endif - read_rc = sread(sockfd, ptr, 1); -#ifdef USE_SSLEAY - } -#endif /* USE_SSLEAY */ - if (*ptr == '\n') + nread=0; + keepon=TRUE; + while((nreaduse_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 */ - 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--) {