From ec3bb8f727405642a471b4b1b9eb0118fc003104 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 12 Dec 2009 21:54:01 +0000 Subject: introducing IMAP, POP3 and SMTP support (still lots of polish left to do) --- lib/ftp.c | 595 +++++++++++--------------------------------------------------- 1 file changed, 100 insertions(+), 495 deletions(-) (limited to 'lib/ftp.c') diff --git a/lib/ftp.c b/lib/ftp.c index 000670fb4..331d17e9d 100644 --- a/lib/ftp.c +++ b/lib/ftp.c @@ -106,14 +106,6 @@ #define INET_ADDRSTRLEN 16 #endif -#ifdef __SYMBIAN32__ -/* Symbian OS panics when given a timeout much greater than 1/2 hour */ -#define RESP_TIMEOUT (1800*1000) -#else -/* Default response timeout in milliseconds */ -#define RESP_TIMEOUT (3600*1000) -#endif - #ifdef CURL_DISABLE_VERBOSE_STRINGS #define ftp_pasv_verbose(a,b,c,d) do { } while(0) #endif @@ -155,7 +147,7 @@ static CURLcode ftp_setup_connection(struct connectdata * conn); /* easy-to-use macro: */ #define FTPSENDF(x,y,z) if((result = Curl_ftpsendf(x,y,z)) != CURLE_OK) \ return result -#define NBFTPSENDF(x,y,z) if((result = Curl_nbftpsendf(x,y,z)) != CURLE_OK) \ +#define PPSENDF(x,y,z) if((result = Curl_pp_sendf(x,y,z)) != CURLE_OK) \ return result @@ -164,7 +156,7 @@ static CURLcode ftp_setup_connection(struct connectdata * conn); */ const struct Curl_handler Curl_handler_ftp = { - "FTP", /* scheme */ + "FTP", /* scheme */ ftp_setup_connection, /* setup_connection */ ftp_do, /* do_it */ ftp_done, /* done */ @@ -187,7 +179,7 @@ const struct Curl_handler Curl_handler_ftp = { */ const struct Curl_handler Curl_handler_ftps = { - "FTPS", /* scheme */ + "FTPS", /* scheme */ ftp_setup_connection, /* setup_connection */ ftp_do, /* do_it */ ftp_done, /* done */ @@ -362,217 +354,39 @@ static CURLcode AllowServerConnect(struct connectdata *conn) /* never reaches this point */ } -/* initialize stuff to prepare for reading a fresh new response */ -static void ftp_respinit(struct connectdata *conn) -{ - struct ftp_conn *ftpc = &conn->proto.ftpc; - ftpc->nread_resp = 0; - ftpc->linestart_resp = conn->data->state.buffer; - ftpc->pending_resp = TRUE; -} - /* macro to check for a three-digit ftp status code at the start of the given string */ -#define STATUSCODE(line) (ISDIGIT(line[0]) && ISDIGIT(line[1]) && \ - ISDIGIT(line[2])) +#define STATUSCODE(line) (ISDIGIT(line[0]) && ISDIGIT(line[1]) && \ + ISDIGIT(line[2])) /* macro to check for the last line in an FTP server response */ #define LASTLINE(line) (STATUSCODE(line) && (' ' == line[3])) +static int ftp_endofresp(struct pingpong *pp, + int *code) +{ + char *line = pp->linestart_resp; + size_t len = pp->nread_resp; + + if((len > 3) && LASTLINE(line)) { + *code = atoi(line); + return 1; + } + return 0; +} + static CURLcode ftp_readresp(curl_socket_t sockfd, - struct connectdata *conn, + struct pingpong *pp, int *ftpcode, /* return the ftp-code if done */ size_t *size) /* size of the response */ { - ssize_t perline; /* count bytes per line */ - bool keepon=TRUE; - ssize_t gotbytes; - char *ptr; + struct connectdata *conn = pp->conn; struct SessionHandle *data = conn->data; char * const buf = data->state.buffer; CURLcode result = CURLE_OK; - struct ftp_conn *ftpc = &conn->proto.ftpc; - int code = 0; - - *ftpcode = 0; /* 0 for errors or not done */ - *size = 0; - - ptr=buf + ftpc->nread_resp; - - /* number of bytes in the current line, so far */ - perline = (ssize_t)(ptr-ftpc->linestart_resp); - - keepon=TRUE; - - while((ftpc->nread_respcache) { - /* we had data in the "cache", copy that instead of doing an actual - * read - * - * ftp->cache_size is cast to int here. This should be safe, - * because it would have been populated with something of size - * int to begin with, even though its datatype may be larger - * than an int. - */ - DEBUGASSERT((ptr+ftpc->cache_size) <= (buf+BUFSIZE+1)); - memcpy(ptr, ftpc->cache, (int)ftpc->cache_size); - gotbytes = (int)ftpc->cache_size; - free(ftpc->cache); /* free the cache */ - ftpc->cache = NULL; /* clear the pointer */ - ftpc->cache_size = 0; /* zero the size just in case */ - } - else { - int res; -#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI) - enum protection_level prot = conn->data_prot; - - conn->data_prot = 0; -#endif - DEBUGASSERT((ptr+BUFSIZE-ftpc->nread_resp) <= (buf+BUFSIZE+1)); - res = Curl_read(conn, sockfd, ptr, BUFSIZE-ftpc->nread_resp, - &gotbytes); -#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI) - conn->data_prot = prot; -#endif - if(res < 0) - /* EWOULDBLOCK */ - return CURLE_OK; /* return */ - -#ifdef CURL_DOES_CONVERSIONS - if((res == CURLE_OK) && (gotbytes > 0)) { - /* convert from the network encoding */ - res = Curl_convert_from_network(data, ptr, gotbytes); - /* Curl_convert_from_network calls failf if unsuccessful */ - } -#endif /* CURL_DOES_CONVERSIONS */ - - if(CURLE_OK != res) { - result = (CURLcode)res; /* Set outer result variable to this error. */ - keepon = FALSE; - } - } - - if(!keepon) - ; - else if(gotbytes <= 0) { - keepon = FALSE; - result = CURLE_RECV_ERROR; - failf(data, "FTP response reading failed"); - } - else { - /* we got a whole chunk of data, which can be anything from one - * byte to a set of lines and possible just a piece of the last - * line */ - ssize_t i; - ssize_t clipamount = 0; - bool restart = FALSE; - - data->req.headerbytecount += gotbytes; - - ftpc->nread_resp += gotbytes; - for(i = 0; i < gotbytes; ptr++, i++) { - perline++; - if(*ptr=='\n') { - /* a newline is CRLF in ftp-talk, so the CR is ignored as - the line isn't really terminated until the LF comes */ - - /* output debug output if that is requested */ -#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI) - if(!conn->sec_complete) -#endif - if(data->set.verbose) - Curl_debug(data, CURLINFO_HEADER_IN, - ftpc->linestart_resp, (size_t)perline, conn); - - /* - * We pass all response-lines to the callback function registered - * for "headers". The response lines can be seen as a kind of - * headers. - */ - result = Curl_client_write(conn, CLIENTWRITE_HEADER, - ftpc->linestart_resp, perline); - if(result) - return result; + int code; - if(perline>3 && LASTLINE(ftpc->linestart_resp)) { - /* This is the end of the last line, copy the last line to the - start of the buffer and zero terminate, for old times sake (and - krb4)! */ - char *meow; - int n; - for(meow=ftpc->linestart_resp, n=0; meowlinestart_resp = ptr+1; /* advance pointer */ - i++; /* skip this before getting out */ - - *size = ftpc->nread_resp; /* size of the response */ - ftpc->nread_resp = 0; /* restart */ - break; - } - perline=0; /* line starts over here */ - ftpc->linestart_resp = ptr+1; - } - } - - if(!keepon && (i != gotbytes)) { - /* We found the end of the response lines, but we didn't parse the - full chunk of data we have read from the server. We therefore need - to store the rest of the data to be checked on the next invoke as - it may actually contain another end of response already! */ - clipamount = gotbytes - i; - restart = TRUE; - } - else if(keepon) { - - if((perline == gotbytes) && (gotbytes > BUFSIZE/2)) { - /* We got an excessive line without newlines and we need to deal - with it. First, check if it seems to start with a valid status - code and then we keep just that in the line cache. Then throw - away the rest. */ - infof(data, "Excessive FTP response line length received, %zd bytes." - " Stripping\n", gotbytes); - restart = TRUE; - if(STATUSCODE(ftpc->linestart_resp)) - /* we copy 4 bytes since after the three-digit number there is a - dash or a space and it is significant */ - clipamount = 4; - } - else if(ftpc->nread_resp > BUFSIZE/2) { - /* We got a large chunk of data and there's potentially still trailing - data to take care of, so we put any such part in the "cache", clear - the buffer to make space and restart. */ - clipamount = perline; - restart = TRUE; - } - } - else if(i == gotbytes) - restart = TRUE; - - if(clipamount) { - ftpc->cache_size = clipamount; - ftpc->cache = malloc((int)ftpc->cache_size); - if(ftpc->cache) - memcpy(ftpc->cache, ftpc->linestart_resp, (int)ftpc->cache_size); - else - return CURLE_OUT_OF_MEMORY; - } - if(restart) { - /* now reset a few variables to start over nicely from the start of - the big buffer */ - ftpc->nread_resp = 0; /* start over from scratch in the buffer */ - ptr = ftpc->linestart_resp = buf; - perline = 0; - } - - } /* there was data */ - - } /* while there's buffer left and loop is requested */ - - if(!result) - code = atoi(buf); + result = Curl_pp_readresp(sockfd, pp, &code, size); #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI) /* handle the security-oriented responses 6xx ***/ @@ -593,12 +407,11 @@ static CURLcode ftp_readresp(curl_socket_t sockfd, } #endif - *ftpcode=code; /* return the initial number like this */ - /* store the latest code for later retrieval */ conn->data->info.httpcode=code; - ftpc->pending_resp = FALSE; + if(ftpcode) + *ftpcode = code; return result; } @@ -628,7 +441,7 @@ CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */ struct SessionHandle *data = conn->data; CURLcode result = CURLE_OK; struct ftp_conn *ftpc = &conn->proto.ftpc; - struct timeval now = Curl_tvnow(); + struct pingpong *pp = &ftpc->pp; size_t nread; int cache_skip=0; int value_to_be_ignored=0; @@ -643,23 +456,7 @@ CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */ while(!*ftpcode && !result) { /* check and reset timeout value every lap */ - if(data->set.ftp_response_timeout ) - /* if CURLOPT_FTP_RESPONSE_TIMEOUT is set, use that to determine - remaining time. Also, use "now" as opposed to "conn->now" - because ftp_response_timeout is only supposed to govern - the response for any given ftp response, not for the time - from connect to the given ftp response. */ - timeout = data->set.ftp_response_timeout - /* timeout time */ - Curl_tvdiff(Curl_tvnow(), now); /* spent time */ - else 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); /* spent time */ - else - /* Even without a requested timeout, we only wait response_time - seconds for the full response to arrive before we bail out */ - timeout = ftpc->response_time - - Curl_tvdiff(Curl_tvnow(), now); /* spent time */ + timeout = Curl_pp_state_timeout(pp); if(timeout <=0 ) { failf(data, "FTP response timeout"); @@ -684,7 +481,7 @@ CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */ * */ - if(ftpc->cache && (cache_skip < 2)) { + if(pp->cache && (cache_skip < 2)) { /* * There's a cache left since before. We then skipping the wait for * socket action, unless this is the same cache like the previous round @@ -708,11 +505,11 @@ CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */ break; } } - result = ftp_readresp(sockfd, conn, ftpcode, &nread); + result = ftp_readresp(sockfd, pp, ftpcode, &nread); if(result) break; - if(!nread && ftpc->cache) + if(!nread && pp->cache) /* bump cache skip counter as on repeated skips we must wait for more data */ cache_skip++; @@ -725,7 +522,7 @@ CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */ } /* while there's buffer left and loop is requested */ - ftpc->pending_resp = FALSE; + pp->pending_resp = FALSE; return result; } @@ -787,7 +584,7 @@ static CURLcode ftp_state_user(struct connectdata *conn) CURLcode result; struct FTP *ftp = conn->data->state.proto.ftp; /* send USER */ - NBFTPSENDF(conn, "USER %s", ftp->user?ftp->user:""); + PPSENDF(&conn->proto.ftpc.pp, "USER %s", ftp->user?ftp->user:""); state(conn, FTP_USER); conn->data->state.ftp_trying_alternative = FALSE; @@ -800,7 +597,7 @@ static CURLcode ftp_state_pwd(struct connectdata *conn) CURLcode result; /* send PWD to discover our entry point */ - NBFTPSENDF(conn, "PWD", NULL); + PPSENDF(&conn->proto.ftpc.pp, "PWD", NULL); state(conn, FTP_PWD); return CURLE_OK; @@ -808,23 +605,10 @@ static CURLcode ftp_state_pwd(struct connectdata *conn) /* For the FTP "protocol connect" and "doing" phases only */ static int ftp_getsock(struct connectdata *conn, - curl_socket_t *socks, - int numsocks) + curl_socket_t *socks, + int numsocks) { - struct ftp_conn *ftpc = &conn->proto.ftpc; - - if(!numsocks) - return GETSOCK_BLANK; - - socks[0] = conn->sock[FIRSTSOCKET]; - - if(ftpc->sendleft) { - /* write mode */ - return GETSOCK_WRITESOCK(0); - } - - /* read mode */ - return GETSOCK_READSOCK(0); + return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks); } /* This is called after the FTP_QUOTE state is passed. @@ -855,7 +639,7 @@ static CURLcode ftp_state_cwd(struct connectdata *conn) where we ended up after login: */ ftpc->count1 = 0; /* we count this as the first path, then we add one for all upcoming ones in the ftp->dirs[] array */ - NBFTPSENDF(conn, "CWD %s", ftpc->entrypath); + PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->entrypath); state(conn, FTP_CWD); } else { @@ -863,7 +647,7 @@ static CURLcode ftp_state_cwd(struct connectdata *conn) ftpc->count1 = 1; /* issue the first CWD, the rest is sent when the CWD responses are received... */ - NBFTPSENDF(conn, "CWD %s", ftpc->dirs[ftpc->count1 -1]); + PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->dirs[ftpc->count1 -1]); state(conn, FTP_CWD); } else { @@ -1190,9 +974,9 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, * EPRT |2|1080::8:800:200C:417A|5282| */ - result = Curl_nbftpsendf(conn, "%s |%d|%s|%d|", mode[fcmd], - sa->sa_family == AF_INET?1:2, - myhost, port); + result = Curl_pp_sendf(&ftpc->pp, "%s |%d|%s|%d|", mode[fcmd], + sa->sa_family == AF_INET?1:2, + myhost, port); if(result) return result; break; @@ -1213,7 +997,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, *dest = 0; snprintf(dest, 20, ",%d,%d", port>>8, port&0xff); - result = Curl_nbftpsendf(conn, "%s %s", mode[fcmd], tmp); + result = Curl_pp_sendf(&ftpc->pp, "%s %s", mode[fcmd], tmp); if(result) return result; break; @@ -1273,9 +1057,7 @@ static CURLcode ftp_state_use_pasv(struct connectdata *conn) modeoff = conn->bits.ftp_use_epsv?0:1; - result = Curl_nbftpsendf(conn, "%s", mode[modeoff]); - if(result) - return result; + PPSENDF(&ftpc->pp, "%s", mode[modeoff]); ftpc->count1 = modeoff; state(conn, FTP_PASV); @@ -1322,7 +1104,7 @@ static CURLcode ftp_state_post_size(struct connectdata *conn) /* Determine if server can respond to REST command and therefore whether it supports range */ - NBFTPSENDF(conn, "REST %d", 0); + PPSENDF(&conn->proto.ftpc.pp, "REST %d", 0); state(conn, FTP_REST); } @@ -1342,7 +1124,7 @@ static CURLcode ftp_state_post_type(struct connectdata *conn) /* if a "head"-like request is being made (on a file) */ /* we know ftpc->file is a valid pointer to a file name */ - NBFTPSENDF(conn, "SIZE %s", ftpc->file); + PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file); state(conn, FTP_SIZE); } @@ -1406,7 +1188,7 @@ static CURLcode ftp_state_post_listtype(struct connectdata *conn) return CURLE_OUT_OF_MEMORY; } - NBFTPSENDF(conn, "%s",cmd); + PPSENDF(&conn->proto.ftpc.pp, "%s",cmd); if(lstArg) free(lstArg); @@ -1484,7 +1266,7 @@ static CURLcode ftp_state_post_cwd(struct connectdata *conn) /* we have requested to get the modified-time of the file, this is a white spot as the MDTM is not mentioned in RFC959 */ - NBFTPSENDF(conn, "MDTM %s", ftpc->file); + PPSENDF(&ftpc->pp, "MDTM %s", ftpc->file); state(conn, FTP_MDTM); } @@ -1522,7 +1304,7 @@ static CURLcode ftp_state_ul_setup(struct connectdata *conn, if(data->state.resume_from < 0 ) { /* Got no given size to start from, figure it out */ - NBFTPSENDF(conn, "SIZE %s", ftpc->file); + PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file); state(conn, FTP_STOR_SIZE); return result; } @@ -1586,8 +1368,8 @@ static CURLcode ftp_state_ul_setup(struct connectdata *conn, /* we've passed, proceed as normal */ } /* resume_from */ - NBFTPSENDF(conn, data->set.ftp_append?"APPE %s":"STOR %s", - ftpc->file); + PPSENDF(&ftpc->pp, data->set.ftp_append?"APPE %s":"STOR %s", + ftpc->file); state(conn, FTP_STOR); @@ -1633,7 +1415,7 @@ static CURLcode ftp_state_quote(struct connectdata *conn, i++; } if(item) { - NBFTPSENDF(conn, "%s", item->data); + PPSENDF(&ftpc->pp, "%s", item->data); state(conn, instate); quote = TRUE; } @@ -1650,7 +1432,7 @@ static CURLcode ftp_state_quote(struct connectdata *conn, if(ftp->transfer != FTPTRANSFER_BODY) state(conn, FTP_STOP); else { - NBFTPSENDF(conn, "SIZE %s", ftpc->file); + PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file); state(conn, FTP_RETR_SIZE); } break; @@ -1791,7 +1573,7 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn, conn->bits.ftp_use_epsv = FALSE; infof(data, "disabling EPSV usage\n"); - NBFTPSENDF(conn, "PASV", NULL); + PPSENDF(&ftpc->pp, "PASV", NULL); ftpc->count1++; /* remain in the FTP_PASV state */ return result; @@ -1852,7 +1634,7 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn, /* disable it for next transfer */ conn->bits.ftp_use_epsv = FALSE; data->state.errorbuf = FALSE; /* allow error message to get rewritten */ - NBFTPSENDF(conn, "PASV", NULL); + PPSENDF(&ftpc->pp, "PASV", NULL); ftpc->count1++; /* remain in the FTP_PASV state */ return result; @@ -2168,14 +1950,14 @@ static CURLcode ftp_state_post_retr_size(struct connectdata *conn, infof(data, "Instructs server to resume from offset %" FORMAT_OFF_T "\n", data->state.resume_from); - NBFTPSENDF(conn, "REST %" FORMAT_OFF_T, data->state.resume_from); + PPSENDF(&ftpc->pp, "REST %" FORMAT_OFF_T, data->state.resume_from); state(conn, FTP_RETR_REST); } else { /* no resume */ - NBFTPSENDF(conn, "RETR %s", ftpc->file); + PPSENDF(&ftpc->pp, "RETR %s", ftpc->file); state(conn, FTP_RETR); } @@ -2246,7 +2028,7 @@ static CURLcode ftp_state_rest_resp(struct connectdata *conn, result = CURLE_FTP_COULDNT_USE_REST; } else { - NBFTPSENDF(conn, "RETR %s", ftpc->file); + PPSENDF(&ftpc->pp, "RETR %s", ftpc->file); state(conn, FTP_RETR); } break; @@ -2300,7 +2082,7 @@ static CURLcode ftp_state_stor_resp(struct connectdata *conn, SECONDARYSOCKET, ftp->bytecountp); state(conn, FTP_STOP); - conn->proto.ftpc.pending_resp = TRUE; /* we expect a server response more */ + conn->proto.ftpc.pp.pending_resp = TRUE; /* expect a server response */ return result; } @@ -2414,7 +2196,7 @@ static CURLcode ftp_state_get_resp(struct connectdata *conn, if(result) return result; - conn->proto.ftpc.pending_resp = TRUE; /* we expect a server response more */ + conn->proto.ftpc.pp.pending_resp = TRUE; /* expect server response */ state(conn, FTP_STOP); } else { @@ -2466,7 +2248,7 @@ static CURLcode ftp_state_loggedin(struct connectdata *conn) parameter of '0' to indicate that no buffering is taking place and the data connection should not be encapsulated. */ - NBFTPSENDF(conn, "PBSZ %d", 0); + PPSENDF(&conn->proto.ftpc.pp, "PBSZ %d", 0); state(conn, FTP_PBSZ); } else { @@ -2490,7 +2272,7 @@ static CURLcode ftp_state_user_resp(struct connectdata *conn, if((ftpcode == 331) && (ftpc->state == FTP_USER)) { /* 331 Password required for ... (the server requires to send the user's password too) */ - NBFTPSENDF(conn, "PASS %s", ftp->passwd?ftp->passwd:""); + PPSENDF(&ftpc->pp, "PASS %s", ftp->passwd?ftp->passwd:""); state(conn, FTP_PASS); } else if(ftpcode/100 == 2) { @@ -2500,7 +2282,7 @@ static CURLcode ftp_state_user_resp(struct connectdata *conn, } else if(ftpcode == 332) { if(data->set.str[STRING_FTP_ACCOUNT]) { - NBFTPSENDF(conn, "ACCT %s", data->set.str[STRING_FTP_ACCOUNT]); + PPSENDF(&ftpc->pp, "ACCT %s", data->set.str[STRING_FTP_ACCOUNT]); state(conn, FTP_ACCT); } else { @@ -2517,8 +2299,8 @@ static CURLcode ftp_state_user_resp(struct connectdata *conn, if(conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER] && !conn->data->state.ftp_trying_alternative) { /* Ok, USER failed. Let's try the supplied command. */ - NBFTPSENDF(conn, "%s", - conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]); + PPSENDF(&conn->proto.ftpc.pp, "%s", + conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]); conn->data->state.ftp_trying_alternative = TRUE; state(conn, FTP_USER); result = CURLE_OK; @@ -2555,32 +2337,15 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) struct SessionHandle *data=conn->data; int ftpcode; struct ftp_conn *ftpc = &conn->proto.ftpc; + struct pingpong *pp = &ftpc->pp; static const char ftpauth[][4] = { "SSL", "TLS" }; size_t nread = 0; - if(ftpc->sendleft) { - /* we have a piece of a command still left to send */ - ssize_t written; - result = Curl_write(conn, sock, ftpc->sendthis + ftpc->sendsize - - ftpc->sendleft, ftpc->sendleft, &written); - if(result) - return result; - - if(written != (ssize_t)ftpc->sendleft) { - /* only a fraction was sent */ - ftpc->sendleft -= written; - } - else { - free(ftpc->sendthis); - ftpc->sendthis=NULL; - ftpc->sendleft = ftpc->sendsize = 0; - ftpc->response = Curl_tvnow(); - } - return CURLE_OK; - } + if(pp->sendleft) + return Curl_pp_flushsend(pp); /* we read a piece of response */ - result = ftp_readresp(sock, conn, &ftpcode, &nread); + result = ftp_readresp(sock, pp, &ftpcode, &nread); if(result) return result; @@ -2632,7 +2397,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) data->set.ftpsslauth); return CURLE_FAILED_INIT; /* we don't know what to do */ } - NBFTPSENDF(conn, "AUTH %s", ftpauth[ftpc->count1]); + PPSENDF(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]); state(conn, FTP_AUTH); } else { @@ -2665,7 +2430,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) else if(ftpc->count3 < 1) { ftpc->count3++; ftpc->count1 += ftpc->count2; /* get next attempt */ - result = Curl_nbftpsendf(conn, "AUTH %s", ftpauth[ftpc->count1]); + result = Curl_pp_sendf(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]); /* remain in this same state */ } else { @@ -2691,8 +2456,8 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) break; case FTP_PBSZ: - NBFTPSENDF(conn, "PROT %c", - data->set.ftp_ssl == CURLUSESSL_CONTROL ? 'C' : 'P'); + PPSENDF(&ftpc->pp, "PROT %c", + data->set.ftp_ssl == CURLUSESSL_CONTROL ? 'C' : 'P'); state(conn, FTP_PROT); break; @@ -2711,7 +2476,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) if(data->set.ftp_ccc) { /* CCC - Clear Command Channel */ - NBFTPSENDF(conn, "CCC", NULL); + PPSENDF(&ftpc->pp, "CCC", NULL); state(conn, FTP_CCC); } else { @@ -2797,7 +2562,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) systems. */ if(!ftpc->server_os && ftpc->entrypath[0] != '/') { - NBFTPSENDF(conn, "SYST", NULL); + PPSENDF(&ftpc->pp, "SYST", NULL); state(conn, FTP_SYST); break; } @@ -2836,7 +2601,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) if(strequal(ftpc->server_os, "OS/400")) { /* Force OS400 name format 1. */ - NBFTPSENDF(conn, "SITE NAMEFMT 1", NULL); + PPSENDF(&ftpc->pp, "SITE NAMEFMT 1", NULL); state(conn, FTP_NAMEFMT); break; } @@ -2884,7 +2649,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) ftpc->count1 && !ftpc->count2) { /* try making it */ ftpc->count2++; /* counter to prevent CWD-MKD loops */ - NBFTPSENDF(conn, "MKD %s", ftpc->dirs[ftpc->count1 - 1]); + PPSENDF(&ftpc->pp, "MKD %s", ftpc->dirs[ftpc->count1 - 1]); state(conn, FTP_MKD); } else { @@ -2900,7 +2665,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) ftpc->count2=0; if(++ftpc->count1 <= ftpc->dirdepth) { /* send next CWD */ - NBFTPSENDF(conn, "CWD %s", ftpc->dirs[ftpc->count1 - 1]); + PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]); } else { result = ftp_state_post_cwd(conn); @@ -2918,7 +2683,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) } state(conn, FTP_CWD); /* send CWD */ - NBFTPSENDF(conn, "CWD %s", ftpc->dirs[ftpc->count1 - 1]); + PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]); break; case FTP_MDTM: @@ -2972,65 +2737,13 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) return result; } -/* Returns timeout in ms. 0 or negative number means the timeout has already - triggered */ -static long ftp_state_timeout(struct connectdata *conn) -{ - struct SessionHandle *data=conn->data; - struct ftp_conn *ftpc = &conn->proto.ftpc; - long timeout_ms=360000; /* in milliseconds */ - - if(data->set.ftp_response_timeout ) - /* if CURLOPT_FTP_RESPONSE_TIMEOUT is set, use that to determine remaining - time. Also, use ftp->response because FTP_RESPONSE_TIMEOUT is supposed - to govern the response for any given ftp response, not for the time - from connect to the given ftp response. */ - timeout_ms = data->set.ftp_response_timeout - /* timeout time */ - Curl_tvdiff(Curl_tvnow(), ftpc->response); /* spent time */ - else if(data->set.timeout) - /* if timeout is requested, find out how much remaining time we have */ - timeout_ms = data->set.timeout - /* timeout time */ - Curl_tvdiff(Curl_tvnow(), conn->now); /* spent time */ - else - /* Without a requested timeout, we only wait 'response_time' seconds for - the full response to arrive before we bail out */ - timeout_ms = ftpc->response_time - - Curl_tvdiff(Curl_tvnow(), ftpc->response); /* spent time */ - - return timeout_ms; -} - /* called repeatedly until done from multi.c */ static CURLcode ftp_multi_statemach(struct connectdata *conn, - bool *done) + bool *done) { - curl_socket_t sock = conn->sock[FIRSTSOCKET]; - int rc; - struct SessionHandle *data=conn->data; struct ftp_conn *ftpc = &conn->proto.ftpc; - CURLcode result = CURLE_OK; - long timeout_ms = ftp_state_timeout(conn); - - *done = FALSE; /* default to not done yet */ - - if(timeout_ms <= 0) { - failf(data, "FTP response timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - - rc = Curl_socket_ready(ftpc->sendleft?CURL_SOCKET_BAD:sock, /* reading */ - ftpc->sendleft?sock:CURL_SOCKET_BAD, /* writing */ - 0); - - if(rc == -1) { - failf(data, "select/poll error"); - return CURLE_OUT_OF_MEMORY; - } - else if(rc != 0) { - result = ftp_statemach_act(conn); - } - /* if rc == 0, then select() timed out */ + CURLcode result = Curl_pp_multi_statemach(&ftpc->pp); /* Check for the state outside of the Curl_socket_ready() return code checks since at times we are in fact already in this state when this function @@ -3042,44 +2755,12 @@ static CURLcode ftp_multi_statemach(struct connectdata *conn, static CURLcode ftp_easy_statemach(struct connectdata *conn) { - curl_socket_t sock = conn->sock[FIRSTSOCKET]; - int rc; - struct SessionHandle *data=conn->data; struct ftp_conn *ftpc = &conn->proto.ftpc; + struct pingpong *pp = &ftpc->pp; CURLcode result = CURLE_OK; while(ftpc->state != FTP_STOP) { - long interval_ms; - long timeout_ms = ftp_state_timeout(conn); - - if(timeout_ms <=0 ) { - failf(data, "FTP response timeout"); - return CURLE_OPERATION_TIMEDOUT; /* already too little time */ - } - - interval_ms = 1000; /* use 1 second timeout intervals */ - if(timeout_ms < interval_ms) - interval_ms = timeout_ms; - - rc = Curl_socket_ready(ftpc->sendleft?CURL_SOCKET_BAD:sock, /* reading */ - ftpc->sendleft?sock:CURL_SOCKET_BAD, /* writing */ - (int)interval_ms); - - if(Curl_pgrsUpdate(conn)) - result = CURLE_ABORTED_BY_CALLBACK; - else - result = Curl_speedcheck(data, Curl_tvnow()); - - if(result) - break; - - if(rc == -1) { - failf(data, "select/poll error"); - result = CURLE_OUT_OF_MEMORY; - } - else if(rc) - result = ftp_statemach_act(conn); - + result = Curl_pp_easy_statemach(pp); if(result) break; } @@ -3136,6 +2817,7 @@ static CURLcode ftp_connect(struct connectdata *conn, CURLcode result; struct ftp_conn *ftpc = &conn->proto.ftpc; struct SessionHandle *data=conn->data; + struct pingpong *pp = &ftpc->pp; *done = FALSE; /* default to not done yet */ @@ -3150,7 +2832,10 @@ static CURLcode ftp_connect(struct connectdata *conn, /* We always support persistant connections on ftp */ conn->bits.close = FALSE; - ftpc->response_time = RESP_TIMEOUT; /* set default response time-out */ + pp->response_time = RESP_TIMEOUT; /* set default response time-out */ + pp->statemach_act = ftp_statemach_act; + pp->endofresp = ftp_endofresp; + pp->conn = conn; #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_PROXY) if(conn->bits.tunnel_proxy && conn->bits.httpproxy) { @@ -3190,11 +2875,11 @@ static CURLcode ftp_connect(struct connectdata *conn, return result; } + Curl_pp_init(pp); /* init the generic pingpong data */ + /* When we connect, we start in the state where we await the 220 response */ - ftp_respinit(conn); /* init the response reader stuff */ state(conn, FTP_WAIT220); - ftpc->response = Curl_tvnow(); /* start response time-out now! */ if(data->state.used_interface == Curl_if_multi) result = ftp_multi_statemach(conn, done); @@ -3222,6 +2907,7 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status, struct SessionHandle *data = conn->data; struct FTP *ftp = data->state.proto.ftp; struct ftp_conn *ftpc = &conn->proto.ftpc; + struct pingpong *pp = &ftpc->pp; ssize_t nread; int ftpcode; CURLcode result=CURLE_OK; @@ -3330,20 +3016,20 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status, } if((ftp->transfer == FTPTRANSFER_BODY) && ftpc->ctl_valid && - ftpc->pending_resp && !premature) { + pp->pending_resp && !premature) { /* * 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. */ - long old_time = ftpc->response_time; + long old_time = pp->response_time; - ftpc->response_time = 60*1000; /* give it only a minute for now */ + pp->response_time = 60*1000; /* give it only a minute for now */ result = Curl_GetFTPResponse(&nread, conn, &ftpcode); - ftpc->response_time = old_time; /* set this back to previous value */ + pp->response_time = old_time; /* set this back to previous value */ if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) { failf(data, "control connection looks dead"); @@ -3497,7 +3183,7 @@ static CURLcode ftp_nb_type(struct connectdata *conn, return ftp_state_type_resp(conn, 200, newstate); } - NBFTPSENDF(conn, "TYPE %c", want); + PPSENDF(&ftpc->pp, "TYPE %c", want); state(conn, newstate); /* keep track of our current transfer type */ @@ -3735,93 +3421,12 @@ static CURLcode ftp_do(struct connectdata *conn, bool *done) return retcode; } -/*********************************************************************** - * - * Curl_(nb)ftpsendf() - * - * Sends the formated string as a ftp command to a ftp server - * - * NOTE: we build the command in a fixed-length buffer, which sets length - * restrictions on the command! - * - * The "nb" version is made to Never Block. - */ -CURLcode Curl_nbftpsendf(struct connectdata *conn, - const char *fmt, ...) -{ - ssize_t bytes_written; -/* may still not be big enough for some krb5 tokens */ -#define SBUF_SIZE 1024 - char s[SBUF_SIZE]; - size_t write_len; - char *sptr=s; - CURLcode res = CURLE_OK; - struct SessionHandle *data = conn->data; - struct ftp_conn *ftpc = &conn->proto.ftpc; -#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI) - enum protection_level data_sec = conn->data_prot; -#endif - - va_list ap; - va_start(ap, fmt); - vsnprintf(s, SBUF_SIZE-3, fmt, ap); - va_end(ap); - - strcat(s, "\r\n"); /* append a trailing CRLF */ - - bytes_written=0; - write_len = strlen(s); - - ftp_respinit(conn); - -#ifdef CURL_DOES_CONVERSIONS - res = Curl_convert_to_network(data, s, write_len); - /* Curl_convert_to_network calls failf if unsuccessful */ - if(res != CURLE_OK) { - return res; - } -#endif /* CURL_DOES_CONVERSIONS */ - -#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI) - conn->data_prot = prot_cmd; -#endif - res = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len, - &bytes_written); -#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI) - conn->data_prot = data_sec; -#endif - - if(CURLE_OK != res) - return res; - - if(conn->data->set.verbose) - Curl_debug(conn->data, CURLINFO_HEADER_OUT, - sptr, (size_t)bytes_written, conn); - - if(bytes_written != (ssize_t)write_len) { - /* the whole chunk was not sent, store the rest of the data */ - write_len -= bytes_written; - sptr += bytes_written; - ftpc->sendthis = malloc(write_len); - if(ftpc->sendthis) { - memcpy(ftpc->sendthis, sptr, write_len); - ftpc->sendsize = ftpc->sendleft = write_len; - } - else { - failf(data, "out of memory"); - res = CURLE_OUT_OF_MEMORY; - } - } - else - ftpc->response = Curl_tvnow(); - - return res; -} CURLcode Curl_ftpsendf(struct connectdata *conn, const char *fmt, ...) { ssize_t bytes_written; +#define SBUF_SIZE 1024 char s[SBUF_SIZE]; size_t write_len; char *sptr=s; @@ -3891,7 +3496,7 @@ static CURLcode ftp_quit(struct connectdata *conn) CURLcode result = CURLE_OK; if(conn->proto.ftpc.ctl_valid) { - NBFTPSENDF(conn, "QUIT", NULL); + PPSENDF(&conn->proto.ftpc.pp, "QUIT", NULL); state(conn, FTP_QUIT); result = ftp_easy_statemach(conn); @@ -3910,6 +3515,7 @@ static CURLcode ftp_quit(struct connectdata *conn) static CURLcode ftp_disconnect(struct connectdata *conn) { struct ftp_conn *ftpc= &conn->proto.ftpc; + struct pingpong *pp = &ftpc->pp; /* We cannot send quit unconditionally. If this connection is stale or bad in any way, sending quit and waiting around here will make the @@ -3930,10 +3536,7 @@ static CURLcode ftp_disconnect(struct connectdata *conn) free(ftpc->entrypath); ftpc->entrypath = NULL; } - if(ftpc->cache) { - free(ftpc->cache); - ftpc->cache = NULL; - } + freedirs(ftpc); if(ftpc->prevpath) { free(ftpc->prevpath); @@ -3944,6 +3547,8 @@ static CURLcode ftp_disconnect(struct connectdata *conn) ftpc->server_os = NULL; } + Curl_pp_disconnect(pp); + return CURLE_OK; } -- cgit v1.2.3