diff options
Diffstat (limited to 'Source/CTest/Curl/ftp.c')
-rw-r--r-- | Source/CTest/Curl/ftp.c | 247 |
1 files changed, 132 insertions, 115 deletions
diff --git a/Source/CTest/Curl/ftp.c b/Source/CTest/Curl/ftp.c index ac5f841..9d4af81 100644 --- a/Source/CTest/Curl/ftp.c +++ b/Source/CTest/Curl/ftp.c @@ -173,9 +173,9 @@ static CURLcode AllowServerConnect(struct SessionHandle *data, * response and extract the relevant return code for the invoking function. */ -int Curl_GetFTPResponse(char *buf, - struct connectdata *conn, - int *ftpcode) +CURLcode Curl_GetFTPResponse(int *nreadp, /* return number of bytes read */ + struct connectdata *conn, + int *ftpcode) /* return the ftp-code */ { /* Brand new implementation. * We cannot read just one byte per read() and then go back to select() @@ -185,28 +185,21 @@ int Curl_GetFTPResponse(char *buf, * line in a response or continue reading. */ int sockfd = conn->firstsocket; - int nread; /* total size read */ int perline; /* count bytes per line */ bool keepon=TRUE; ssize_t gotbytes; char *ptr; - int timeout = 3600; /* default timeout in seconds */ + int timeout; /* timeout in seconds */ struct timeval interval; fd_set rkeepfd; fd_set readfd; struct SessionHandle *data = conn->data; char *line_start; - int code=0; /* default "error code" to return */ - -#define SELECT_OK 0 -#define SELECT_ERROR 1 /* select() problems */ -#define SELECT_TIMEOUT 2 /* took too long */ -#define SELECT_MEMORY 3 /* no available memory */ -#define SELECT_CALLBACK 4 /* aborted by callback */ - - int error = SELECT_OK; - + int code=0; /* default ftp "error code" to return */ + char *buf = data->state.buffer; + CURLcode result = CURLE_OK; struct FTP *ftp = conn->proto.ftp; + struct timeval now = Curl_tvnow(); if (ftpcode) *ftpcode = 0; /* 0 for errors */ @@ -221,20 +214,25 @@ int Curl_GetFTPResponse(char *buf, ptr=buf; line_start = buf; - nread=0; + *nreadp=0; perline=0; keepon=TRUE; - while((nread<BUFSIZE) && (keepon && !error)) { + while((*nreadp<BUFSIZE) && (keepon && !result)) { /* check and reset timeout value every lap */ - if(data->set.timeout) { + if(data->set.timeout) /* if timeout is requested, find out how much remaining time we have */ timeout = data->set.timeout - /* timeout time */ Curl_tvdiff(Curl_tvnow(), conn->now)/1000; /* spent time */ - if(timeout <=0 ) { - failf(data, "Transfer aborted due to timeout"); - return -SELECT_TIMEOUT; /* already too little time */ - } + else + /* Even without a requested timeout, we only wait response_time + seconds for the full response to arrive before we bail out */ + timeout = ftp->response_time - + Curl_tvdiff(Curl_tvnow(), now)/1000; /* spent time */ + + if(timeout <=0 ) { + failf(data, "Transfer aborted due to timeout"); + return CURLE_OPERATION_TIMEDOUT; /* already too little time */ } if(!ftp->cache) { @@ -244,19 +242,18 @@ int Curl_GetFTPResponse(char *buf, 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"); + result = CURLE_RECV_ERROR; + failf(data, "Transfer aborted due to select() error: %d", errno); break; case 0: /* timeout */ - error = SELECT_TIMEOUT; + result = CURLE_OPERATION_TIMEDOUT; failf(data, "Transfer aborted due to timeout"); break; default: - error = SELECT_OK; break; } } - if(SELECT_OK == error) { + if(CURLE_OK == result) { /* * This code previously didn't use the kerberos sec_read() code * to read, but when we use Curl_read() it may do so. Do confirm @@ -272,8 +269,7 @@ int Curl_GetFTPResponse(char *buf, ftp->cache_size = 0; /* zero the size just in case */ } else { - int res = Curl_read(conn, sockfd, ptr, - BUFSIZE-nread, &gotbytes); + int res = Curl_read(conn, sockfd, ptr, BUFSIZE-*nreadp, &gotbytes); if(res < 0) /* EWOULDBLOCK */ continue; /* go looping again */ @@ -286,7 +282,7 @@ int Curl_GetFTPResponse(char *buf, ; else if(gotbytes <= 0) { keepon = FALSE; - error = SELECT_ERROR; + result = CURLE_RECV_ERROR; failf(data, "Connection aborted"); } else { @@ -295,7 +291,7 @@ int Curl_GetFTPResponse(char *buf, * line */ int i; - nread += gotbytes; + *nreadp += gotbytes; for(i = 0; i < gotbytes; ptr++, i++) { perline++; if(*ptr=='\n') { @@ -315,7 +311,7 @@ int Curl_GetFTPResponse(char *buf, result = Curl_client_write(data, CLIENTWRITE_HEADER, line_start, perline); if(result) - return -SELECT_CALLBACK; + return result; #define lastline(line) (isdigit((int)line[0]) && isdigit((int)line[1]) && \ isdigit((int)line[2]) && (' ' == line[3])) @@ -350,13 +346,13 @@ int Curl_GetFTPResponse(char *buf, if(ftp->cache) memcpy(ftp->cache, line_start, ftp->cache_size); else - return -SELECT_MEMORY; /**BANG**/ + return CURLE_OUT_OF_MEMORY; /**BANG**/ } } /* there was data */ } /* if(no error) */ } /* while there's buffer left and loop is requested */ - if(!error) + if(!result) code = atoi(buf); #ifdef KRB4 @@ -378,13 +374,10 @@ int Curl_GetFTPResponse(char *buf, } #endif - if(error) - return -error; - if(ftpcode) *ftpcode=code; /* return the initial number like this */ - return nread; /* total amount of bytes read */ + return result; } /* @@ -417,6 +410,7 @@ CURLcode Curl_ftp_connect(struct connectdata *conn) /* no need to duplicate them, the data struct won't change */ ftp->user = data->state.user; ftp->passwd = data->state.passwd; + ftp->response_time = 3600; /* set default response time-out */ if (data->set.tunnel_thru_httpproxy) { /* We want "seamless" FTP operations through HTTP proxy tunnel */ @@ -436,9 +430,9 @@ CURLcode Curl_ftp_connect(struct connectdata *conn) /* The first thing we do is wait for the "220*" line: */ - nread = Curl_GetFTPResponse(buf, conn, &ftpcode); - if(nread < 0) - return CURLE_OPERATION_TIMEOUTED; + result = Curl_GetFTPResponse(&nread, conn, &ftpcode); + if(result) + return result; if(ftpcode != 220) { failf(data, "This doesn't seem like a nice ftp-server response"); @@ -467,9 +461,9 @@ CURLcode Curl_ftp_connect(struct connectdata *conn) FTPSENDF(conn, "USER %s", ftp->user); /* wait for feedback */ - nread = Curl_GetFTPResponse(buf, conn, &ftpcode); - if(nread < 0) - return CURLE_OPERATION_TIMEOUTED; + result = Curl_GetFTPResponse(&nread, conn, &ftpcode); + if(result) + return result; if(ftpcode == 530) { /* 530 User ... access denied @@ -481,9 +475,9 @@ CURLcode Curl_ftp_connect(struct connectdata *conn) /* 331 Password required for ... (the server requires to send the user's password too) */ FTPSENDF(conn, "PASS %s", ftp->passwd); - nread = Curl_GetFTPResponse(buf, conn, &ftpcode); - if(nread < 0) - return CURLE_OPERATION_TIMEOUTED; + result = Curl_GetFTPResponse(&nread, conn, &ftpcode); + if(result) + return result; if(ftpcode == 530) { /* 530 Login incorrect. @@ -516,8 +510,11 @@ CURLcode Curl_ftp_connect(struct connectdata *conn) /* we may need to issue a KAUTH here to have access to the files * do it if user supplied a password */ - if(data->state.passwd && *data->state.passwd) - Curl_krb_kauth(conn); + if(data->state.passwd && *data->state.passwd) { + result = Curl_krb_kauth(conn); + if(result) + return result; + } #endif } else { @@ -529,9 +526,9 @@ CURLcode Curl_ftp_connect(struct connectdata *conn) FTPSENDF(conn, "PWD", NULL); /* wait for feedback */ - nread = Curl_GetFTPResponse(buf, conn, &ftpcode); - if(nread < 0) - return CURLE_OPERATION_TIMEOUTED; + result = Curl_GetFTPResponse(&nread, conn, &ftpcode); + if(result) + return result; if(ftpcode == 257) { char *dir = (char *)malloc(nread+1); @@ -544,7 +541,7 @@ CURLcode Curl_ftp_connect(struct connectdata *conn) The directory name can contain any character; embedded double-quotes should be escaped by double-quotes (the "quote-doubling" convention). */ - if('\"' == *ptr) { + if(dir && ('\"' == *ptr)) { /* it started good */ ptr++; while(ptr && *ptr) { @@ -570,6 +567,8 @@ CURLcode Curl_ftp_connect(struct connectdata *conn) } else { /* couldn't get the path */ + free(dir); + infof(data, "Failed to figure out path\n"); } } @@ -594,7 +593,6 @@ CURLcode Curl_ftp_done(struct connectdata *conn) struct SessionHandle *data = conn->data; struct FTP *ftp = conn->proto.ftp; ssize_t nread; - char *buf = data->state.buffer; /* this is our buffer */ int ftpcode; CURLcode result=CURLE_OK; @@ -633,11 +631,24 @@ CURLcode Curl_ftp_done(struct connectdata *conn) conn->secondarysocket = -1; if(!ftp->no_transfer) { - /* now let's see what the server says about the transfer we just - performed: */ - nread = Curl_GetFTPResponse(buf, conn, &ftpcode); - if(nread < 0) - return CURLE_OPERATION_TIMEOUTED; + /* Let's see what the server says about the transfer we just performed, + but lower the timeout as sometimes this connection has died while + the data has been transfered. This happens when doing through NATs + etc that abandon old silent connections. + */ + ftp->response_time = 60; /* give it only a minute for now */ + + result = Curl_GetFTPResponse(&nread, conn, &ftpcode); + + ftp->response_time = 3600; /* set this back to one hour waits */ + + if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) { + failf(data, "control connection looks dead"); + return result; + } + + if(result) + return result; if(!ftp->dont_check) { /* 226 Transfer complete, 250 Requested file action okay, completed. */ @@ -680,9 +691,9 @@ CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote) if (item->data) { FTPSENDF(conn, "%s", item->data); - nread = Curl_GetFTPResponse(conn->data->state.buffer, conn, &ftpcode); - if (nread < 0) - return CURLE_OPERATION_TIMEOUTED; + result = Curl_GetFTPResponse(&nread, conn, &ftpcode); + if (result) + return result; if (ftpcode >= 400) { failf(conn->data, "QUOT string not accepted: %s", item->data); @@ -711,9 +722,9 @@ CURLcode ftp_cwd(struct connectdata *conn, char *path) CURLcode result; FTPSENDF(conn, "CWD %s", path); - nread = Curl_GetFTPResponse(conn->data->state.buffer, conn, &ftpcode); - if (nread < 0) - return CURLE_OPERATION_TIMEOUTED; + result = Curl_GetFTPResponse(&nread, conn, &ftpcode); + if (result) + return result; if (ftpcode != 250) { failf(conn->data, "Couldn't cd to %s", path); @@ -741,26 +752,34 @@ CURLcode ftp_getfiletime(struct connectdata *conn, char *file) again a grey area as the MDTM is not kosher RFC959 */ FTPSENDF(conn, "MDTM %s", file); - nread = Curl_GetFTPResponse(buf, conn, &ftpcode); - if(nread < 0) - return CURLE_OPERATION_TIMEOUTED; + result = Curl_GetFTPResponse(&nread, conn, &ftpcode); + if(result) + return result; - if(ftpcode == 213) { - /* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the - last .sss part is optional and means fractions of a second */ - int year, month, day, hour, minute, second; - if(6 == sscanf(buf+4, "%04d%02d%02d%02d%02d%02d", - &year, &month, &day, &hour, &minute, &second)) { - /* we have a time, reformat it */ - time_t secs=time(NULL); - sprintf(buf, "%04d%02d%02d %02d:%02d:%02d", - year, month, day, hour, minute, second); - /* now, convert this into a time() value: */ - conn->data->info.filetime = curl_getdate(buf, &secs); - } - else { - infof(conn->data, "unsupported MDTM reply format\n"); + switch(ftpcode) { + case 213: + { + /* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the + last .sss part is optional and means fractions of a second */ + int year, month, day, hour, minute, second; + if(6 == sscanf(buf+4, "%04d%02d%02d%02d%02d%02d", + &year, &month, &day, &hour, &minute, &second)) { + /* we have a time, reformat it */ + time_t secs=time(NULL); + sprintf(buf, "%04d%02d%02d %02d:%02d:%02d", + year, month, day, hour, minute, second); + /* now, convert this into a time() value: */ + conn->data->info.filetime = curl_getdate(buf, &secs); + } } + break; + default: + infof(conn->data, "unsupported MDTM reply format\n"); + break; + case 550: /* "No such file or directory" */ + failf(conn->data, "Given file does not exist"); + result = CURLE_FTP_COULDNT_RETR_FILE; + break; } return result; } @@ -778,14 +797,13 @@ static CURLcode ftp_transfertype(struct connectdata *conn, struct SessionHandle *data = conn->data; int ftpcode; ssize_t nread; - char *buf=data->state.buffer; CURLcode result; FTPSENDF(conn, "TYPE %s", ascii?"A":"I"); - nread = Curl_GetFTPResponse(buf, conn, &ftpcode); - if(nread < 0) - return CURLE_OPERATION_TIMEOUTED; + result = Curl_GetFTPResponse(&nread, conn, &ftpcode); + if(result) + return result; if(ftpcode != 200) { failf(data, "Couldn't set %s mode", @@ -814,9 +832,9 @@ CURLcode ftp_getsize(struct connectdata *conn, char *file, CURLcode result; FTPSENDF(conn, "SIZE %s", file); - nread = Curl_GetFTPResponse(buf, conn, &ftpcode); - if(nread < 0) - return CURLE_OPERATION_TIMEOUTED; + result = Curl_GetFTPResponse(&nread, conn, &ftpcode); + if(result) + return result; if(ftpcode == 213) { /* get the size from the ascii string: */ @@ -975,7 +993,6 @@ CURLcode ftp_use_port(struct connectdata *conn) struct SessionHandle *data=conn->data; int portsock=-1; ssize_t nread; - char *buf = data->state.buffer; /* this is our buffer */ int ftpcode; /* receive FTP response codes in this */ CURLcode result; @@ -1155,9 +1172,9 @@ CURLcode ftp_use_port(struct connectdata *conn) return result; } - nread = Curl_GetFTPResponse(buf, conn, &ftpcode); - if(nread < 0) - return CURLE_OPERATION_TIMEOUTED; + result = Curl_GetFTPResponse(&nread, conn, &ftpcode); + if(result) + return result; if (ftpcode != 200) { failf(data, "Server does not grok %s", *modep); @@ -1301,9 +1318,9 @@ CURLcode ftp_use_port(struct connectdata *conn) return result; } - nread = Curl_GetFTPResponse(buf, conn, &ftpcode); - if(nread < 0) - return CURLE_OPERATION_TIMEOUTED; + result = Curl_GetFTPResponse(&nread, conn, &ftpcode); + if(result) + return result; if(ftpcode != 200) { failf(data, "Server does not grok PORT, try without it!"); @@ -1375,9 +1392,9 @@ CURLcode ftp_use_pasv(struct connectdata *conn, result = Curl_ftpsendf(conn, "%s", mode[modeoff]); if(result) return result; - nread = Curl_GetFTPResponse(buf, conn, &ftpcode); - if(nread < 0) - return CURLE_OPERATION_TIMEOUTED; + result = Curl_GetFTPResponse(&nread, conn, &ftpcode); + if(result) + return result; if (ftpcode == results[modeoff]) break; } @@ -1522,7 +1539,7 @@ CURLcode Curl_ftp_nextconnect(struct connectdata *conn) ssize_t nread; int ftpcode; /* for ftp status */ - /* the ftp struct is already inited in ftp_connect() */ + /* the ftp struct is already inited in Curl_ftp_connect() */ struct FTP *ftp = conn->proto.ftp; long *bytecountp = ftp->bytecountp; @@ -1582,8 +1599,8 @@ CURLcode Curl_ftp_nextconnect(struct connectdata *conn) readthisamountnow = BUFSIZE; actuallyread = - data->set.fread(data->state.buffer, 1, readthisamountnow, - data->set.in); + conn->fread(data->state.buffer, 1, readthisamountnow, + conn->fread_in); passed += actuallyread; if(actuallyread != readthisamountnow) { @@ -1614,7 +1631,7 @@ CURLcode Curl_ftp_nextconnect(struct connectdata *conn) } } - /* Send everything on data->set.in to the socket */ + /* Send everything on data->state.in to the socket */ if(data->set.ftp_append) { /* we append onto the file instead of rewriting it */ FTPSENDF(conn, "APPE %s", ftp->file); @@ -1623,9 +1640,9 @@ CURLcode Curl_ftp_nextconnect(struct connectdata *conn) FTPSENDF(conn, "STOR %s", ftp->file); } - nread = Curl_GetFTPResponse(buf, conn, &ftpcode); - if(nread < 0) - return CURLE_OPERATION_TIMEOUTED; + result = Curl_GetFTPResponse(&nread, conn, &ftpcode); + if(result) + return result; if(ftpcode>=400) { failf(data, "Failed FTP upload:%s", buf+3); @@ -1799,9 +1816,9 @@ CURLcode Curl_ftp_nextconnect(struct connectdata *conn) FTPSENDF(conn, "REST %d", conn->resume_from); - nread = Curl_GetFTPResponse(buf, conn, &ftpcode); - if(nread < 0) - return CURLE_OPERATION_TIMEOUTED; + result = Curl_GetFTPResponse(&nread, conn, &ftpcode); + if(result) + return result; if(ftpcode != 350) { failf(data, "Couldn't use REST: %s", buf+4); @@ -1812,9 +1829,9 @@ CURLcode Curl_ftp_nextconnect(struct connectdata *conn) FTPSENDF(conn, "RETR %s", ftp->file); } - nread = Curl_GetFTPResponse(buf, conn, &ftpcode); - if(nread < 0) - return CURLE_OPERATION_TIMEOUTED; + result = Curl_GetFTPResponse(&nread, conn, &ftpcode); + if(result) + return result; if((ftpcode == 150) || (ftpcode == 125)) { @@ -1919,7 +1936,7 @@ CURLcode ftp_perform(struct connectdata *conn, struct SessionHandle *data=conn->data; char *buf = data->state.buffer; /* this is our buffer */ - /* the ftp struct is already inited in ftp_connect() */ + /* the ftp struct is already inited in Curl_ftp_connect() */ struct FTP *ftp = conn->proto.ftp; /* Send any QUOTE strings? */ @@ -1980,7 +1997,7 @@ CURLcode ftp_perform(struct connectdata *conn, well, we "emulate" a HTTP-style header in our output. */ #ifdef HAVE_STRFTIME - if(data->set.get_filetime && data->info.filetime) { + if(data->set.get_filetime && (data->info.filetime>=0) ) { struct tm *tm; #ifdef HAVE_LOCALTIME_R struct tm buffer; |