mirror of
https://github.com/moparisthebest/curl
synced 2024-12-22 08:08:50 -05:00
FTP: perform active connections non-blocking
1- Two new error codes are introduced. CURLE_FTP_ACCEPT_FAILED to be set whenever ACCEPTing fails because of FTP server connected. CURLE_FTP_ACCEPT_TIMEOUT to be set whenever ACCEPTing timeouts. Neither of these errors are considered fatal and control connection remains OK because it could just be a firewall blocking server to connect to the client. 2- One new setopt option was introduced. CURLOPT_ACCEPTTIMEOUT_MS It sets the maximum amount of time FTP client is going to wait for a server to connect. Internal default accept timeout is 60 seconds.
This commit is contained in:
parent
5527417afa
commit
c834213ad5
@ -45,6 +45,8 @@ CURLE_COULDNT_RESOLVE_PROXY 7.1
|
|||||||
CURLE_FAILED_INIT 7.1
|
CURLE_FAILED_INIT 7.1
|
||||||
CURLE_FILESIZE_EXCEEDED 7.10.8
|
CURLE_FILESIZE_EXCEEDED 7.10.8
|
||||||
CURLE_FILE_COULDNT_READ_FILE 7.1
|
CURLE_FILE_COULDNT_READ_FILE 7.1
|
||||||
|
CURLE_FTP_ACCEPT_FAILED 7.24.0
|
||||||
|
CURLE_FTP_ACCEPT_TIMEOUT 7.24.0
|
||||||
CURLE_FTP_ACCESS_DENIED 7.1
|
CURLE_FTP_ACCESS_DENIED 7.1
|
||||||
CURLE_FTP_BAD_DOWNLOAD_RESUME 7.1 7.1
|
CURLE_FTP_BAD_DOWNLOAD_RESUME 7.1 7.1
|
||||||
CURLE_FTP_BAD_FILE_LIST 7.21.0
|
CURLE_FTP_BAD_FILE_LIST 7.21.0
|
||||||
@ -286,6 +288,7 @@ CURLOPTTYPE_FUNCTIONPOINT 7.1
|
|||||||
CURLOPTTYPE_LONG 7.1
|
CURLOPTTYPE_LONG 7.1
|
||||||
CURLOPTTYPE_OBJECTPOINT 7.1
|
CURLOPTTYPE_OBJECTPOINT 7.1
|
||||||
CURLOPTTYPE_OFF_T 7.11.0
|
CURLOPTTYPE_OFF_T 7.11.0
|
||||||
|
CURLOPT_ACCEPTTIMEOUT_MS 7.24.0
|
||||||
CURLOPT_ACCEPT_ENCODING 7.21.6
|
CURLOPT_ACCEPT_ENCODING 7.21.6
|
||||||
CURLOPT_ADDRESS_SCOPE 7.19.0
|
CURLOPT_ADDRESS_SCOPE 7.19.0
|
||||||
CURLOPT_APPEND 7.17.0
|
CURLOPT_APPEND 7.17.0
|
||||||
|
@ -411,9 +411,12 @@ typedef enum {
|
|||||||
CURLE_REMOTE_ACCESS_DENIED, /* 9 a service was denied by the server
|
CURLE_REMOTE_ACCESS_DENIED, /* 9 a service was denied by the server
|
||||||
due to lack of access - when login fails
|
due to lack of access - when login fails
|
||||||
this is not returned. */
|
this is not returned. */
|
||||||
CURLE_OBSOLETE10, /* 10 - NOT USED */
|
CURLE_FTP_ACCEPT_FAILED, /* 10 - [was obsoleted in April 2006 for
|
||||||
|
7.15.4, reused in Dec 2011 for 7.24.0]*/
|
||||||
CURLE_FTP_WEIRD_PASS_REPLY, /* 11 */
|
CURLE_FTP_WEIRD_PASS_REPLY, /* 11 */
|
||||||
CURLE_OBSOLETE12, /* 12 - NOT USED */
|
CURLE_FTP_ACCEPT_TIMEOUT, /* 12 - timeout occurred accepting server
|
||||||
|
[was obsoleted in August 2007 for 7.17.0,
|
||||||
|
reused in Dec 2011 for 7.24.0]*/
|
||||||
CURLE_FTP_WEIRD_PASV_REPLY, /* 13 */
|
CURLE_FTP_WEIRD_PASV_REPLY, /* 13 */
|
||||||
CURLE_FTP_WEIRD_227_FORMAT, /* 14 */
|
CURLE_FTP_WEIRD_227_FORMAT, /* 14 */
|
||||||
CURLE_FTP_CANT_GET_HOST, /* 15 */
|
CURLE_FTP_CANT_GET_HOST, /* 15 */
|
||||||
@ -511,7 +514,6 @@ typedef enum {
|
|||||||
CURLE_RTSP_SESSION_ERROR, /* 86 - mismatch of RTSP Session Ids */
|
CURLE_RTSP_SESSION_ERROR, /* 86 - mismatch of RTSP Session Ids */
|
||||||
CURLE_FTP_BAD_FILE_LIST, /* 87 - unable to parse FTP file list */
|
CURLE_FTP_BAD_FILE_LIST, /* 87 - unable to parse FTP file list */
|
||||||
CURLE_CHUNK_FAILED, /* 88 - chunk callback reported error */
|
CURLE_CHUNK_FAILED, /* 88 - chunk callback reported error */
|
||||||
|
|
||||||
CURL_LAST /* never use! */
|
CURL_LAST /* never use! */
|
||||||
} CURLcode;
|
} CURLcode;
|
||||||
|
|
||||||
@ -1489,6 +1491,10 @@ typedef enum {
|
|||||||
/* Set the name servers to use for DNS resolution */
|
/* Set the name servers to use for DNS resolution */
|
||||||
CINIT(DNS_SERVERS, OBJECTPOINT, 211),
|
CINIT(DNS_SERVERS, OBJECTPOINT, 211),
|
||||||
|
|
||||||
|
/* Time-out accept operations (currently for FTP only) after this amount
|
||||||
|
of miliseconds. */
|
||||||
|
CINIT(ACCEPTTIMEOUT_MS, LONG, 212),
|
||||||
|
|
||||||
CURLOPT_LASTENTRY /* the last unused */
|
CURLOPT_LASTENTRY /* the last unused */
|
||||||
} CURLoption;
|
} CURLoption;
|
||||||
|
|
||||||
|
@ -98,6 +98,34 @@ singleipconnect(struct connectdata *conn,
|
|||||||
curl_socket_t *sock,
|
curl_socket_t *sock,
|
||||||
bool *connected);
|
bool *connected);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Curl_timeleft_accept() returns the amount of milliseconds left allowed for
|
||||||
|
* waiting server to connect. If the value is negative, the timeout time has
|
||||||
|
* already elapsed.
|
||||||
|
*
|
||||||
|
* The start time is stored in progress.t_acceptdata - as set with
|
||||||
|
* Curl_pgrsTime(..., TIMER_STARTACCEPT);
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
long Curl_timeleft_accept(struct SessionHandle *data)
|
||||||
|
{
|
||||||
|
long timeout_ms = DEFAULT_ACCEPT_TIMEOUT;
|
||||||
|
struct timeval now;
|
||||||
|
|
||||||
|
if(data->set.accepttimeout > 0)
|
||||||
|
timeout_ms = data->set.accepttimeout;
|
||||||
|
|
||||||
|
now = Curl_tvnow();
|
||||||
|
|
||||||
|
/* subtract elapsed time */
|
||||||
|
timeout_ms -= Curl_tvdiff(now, data->progress.t_acceptdata);
|
||||||
|
if(!timeout_ms)
|
||||||
|
/* avoid returning 0 as that means no timeout! */
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return timeout_ms;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Curl_timeleft() returns the amount of milliseconds left allowed for the
|
* Curl_timeleft() returns the amount of milliseconds left allowed for the
|
||||||
* transfer/connection. If the value is negative, the timeout time has already
|
* transfer/connection. If the value is negative, the timeout time has already
|
||||||
|
@ -43,7 +43,12 @@ long Curl_timeleft(struct SessionHandle *data,
|
|||||||
struct timeval *nowp,
|
struct timeval *nowp,
|
||||||
bool duringconnect);
|
bool duringconnect);
|
||||||
|
|
||||||
|
/* function that returns how much time there's left to wait for incoming
|
||||||
|
server connect */
|
||||||
|
long Curl_timeleft_accept(struct SessionHandle *data);
|
||||||
|
|
||||||
#define DEFAULT_CONNECT_TIMEOUT 300000 /* milliseconds == five minutes */
|
#define DEFAULT_CONNECT_TIMEOUT 300000 /* milliseconds == five minutes */
|
||||||
|
#define DEFAULT_ACCEPT_TIMEOUT 60000 /* milliseconds == one minute */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Used to extract socket and connectdata struct for the most recent
|
* Used to extract socket and connectdata struct for the most recent
|
||||||
|
348
lib/ftp.c
348
lib/ftp.c
@ -108,6 +108,8 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Local API functions */
|
/* Local API functions */
|
||||||
|
static void state(struct connectdata *conn,
|
||||||
|
ftpstate newstate);
|
||||||
static CURLcode ftp_sendquote(struct connectdata *conn,
|
static CURLcode ftp_sendquote(struct connectdata *conn,
|
||||||
struct curl_slist *quote);
|
struct curl_slist *quote);
|
||||||
static CURLcode ftp_quit(struct connectdata *conn);
|
static CURLcode ftp_quit(struct connectdata *conn);
|
||||||
@ -150,6 +152,11 @@ static void wc_data_dtor(void *ptr);
|
|||||||
static CURLcode ftp_state_post_retr_size(struct connectdata *conn,
|
static CURLcode ftp_state_post_retr_size(struct connectdata *conn,
|
||||||
curl_off_t filesize);
|
curl_off_t filesize);
|
||||||
|
|
||||||
|
static CURLcode ftp_readresp(curl_socket_t sockfd,
|
||||||
|
struct pingpong *pp,
|
||||||
|
int *ftpcode,
|
||||||
|
size_t *size);
|
||||||
|
|
||||||
/* easy-to-use macro: */
|
/* easy-to-use macro: */
|
||||||
#define FTPSENDF(x,y,z) if((result = Curl_ftpsendf(x,y,z)) != CURLE_OK) \
|
#define FTPSENDF(x,y,z) if((result = Curl_ftpsendf(x,y,z)) != CURLE_OK) \
|
||||||
return result
|
return result
|
||||||
@ -310,19 +317,16 @@ static bool isBadFtpString(const char *string)
|
|||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
*
|
*
|
||||||
* AllowServerConnect()
|
* AcceptServerConnect()
|
||||||
*
|
*
|
||||||
* When we've issue the PORT command, we have told the server to connect
|
* After connection request is received from the server this function is
|
||||||
* to us. This function will sit and wait here until the server has
|
* called to accept the connection and close the listening socket
|
||||||
* connected.
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static CURLcode AllowServerConnect(struct connectdata *conn)
|
static CURLcode AcceptServerConnect(struct connectdata *conn)
|
||||||
{
|
{
|
||||||
struct SessionHandle *data = conn->data;
|
struct SessionHandle *data = conn->data;
|
||||||
curl_socket_t sock = conn->sock[SECONDARYSOCKET];
|
curl_socket_t sock = conn->sock[SECONDARYSOCKET];
|
||||||
long timeout_ms;
|
|
||||||
long interval_ms;
|
|
||||||
curl_socket_t s = CURL_SOCKET_BAD;
|
curl_socket_t s = CURL_SOCKET_BAD;
|
||||||
#ifdef ENABLE_IPV6
|
#ifdef ENABLE_IPV6
|
||||||
struct Curl_sockaddr_storage add;
|
struct Curl_sockaddr_storage add;
|
||||||
@ -331,28 +335,6 @@ static CURLcode AllowServerConnect(struct connectdata *conn)
|
|||||||
#endif
|
#endif
|
||||||
curl_socklen_t size = (curl_socklen_t) sizeof(add);
|
curl_socklen_t size = (curl_socklen_t) sizeof(add);
|
||||||
|
|
||||||
for(;;) {
|
|
||||||
timeout_ms = Curl_timeleft(data, NULL, TRUE);
|
|
||||||
|
|
||||||
if(timeout_ms < 0) {
|
|
||||||
/* if a timeout was already reached, bail out */
|
|
||||||
failf(data, "Timeout while waiting for server connect");
|
|
||||||
return CURLE_OPERATION_TIMEDOUT;
|
|
||||||
}
|
|
||||||
|
|
||||||
interval_ms = 1000; /* use 1 second timeout intervals */
|
|
||||||
if(timeout_ms < interval_ms)
|
|
||||||
interval_ms = timeout_ms;
|
|
||||||
|
|
||||||
switch (Curl_socket_ready(sock, CURL_SOCKET_BAD, interval_ms)) {
|
|
||||||
case -1: /* error */
|
|
||||||
/* let's die here */
|
|
||||||
failf(data, "Error while waiting for server connect");
|
|
||||||
return CURLE_FTP_PORT_FAILED;
|
|
||||||
case 0: /* timeout */
|
|
||||||
break; /* loop */
|
|
||||||
default:
|
|
||||||
/* we have received data here */
|
|
||||||
if(0 == getsockname(sock, (struct sockaddr *) &add, &size)) {
|
if(0 == getsockname(sock, (struct sockaddr *) &add, &size)) {
|
||||||
size = sizeof(add);
|
size = sizeof(add);
|
||||||
|
|
||||||
@ -370,9 +352,203 @@ static CURLcode AllowServerConnect(struct connectdata *conn)
|
|||||||
curlx_nonblock(s, TRUE); /* enable non-blocking */
|
curlx_nonblock(s, TRUE); /* enable non-blocking */
|
||||||
conn->sock_accepted[SECONDARYSOCKET] = TRUE;
|
conn->sock_accepted[SECONDARYSOCKET] = TRUE;
|
||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
} /* switch() */
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
*
|
||||||
|
* ReceivedServerConnect()
|
||||||
|
*
|
||||||
|
* After allowing server to connect to us from data port, this function
|
||||||
|
* checks both data connection for connection establishment and ctrl
|
||||||
|
* connection for a negative response regarding a failure in connecting
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static CURLcode ReceivedServerConnect(struct connectdata* conn, bool* received)
|
||||||
|
{
|
||||||
|
struct SessionHandle *data = conn->data;
|
||||||
|
curl_socket_t ctrl_sock = conn->sock[FIRSTSOCKET];
|
||||||
|
curl_socket_t data_sock = conn->sock[SECONDARYSOCKET];
|
||||||
|
struct ftp_conn *ftpc = &conn->proto.ftpc;
|
||||||
|
struct pingpong *pp = &ftpc->pp;
|
||||||
|
int result;
|
||||||
|
long timeout_ms;
|
||||||
|
ssize_t nread;
|
||||||
|
int ftpcode;
|
||||||
|
|
||||||
|
*received = FALSE;
|
||||||
|
|
||||||
|
timeout_ms = Curl_timeleft_accept(data);
|
||||||
|
infof(data, "Checking for server connect\n");
|
||||||
|
if(timeout_ms < 0) {
|
||||||
|
/* if a timeout was already reached, bail out */
|
||||||
|
failf(data, "Accept timeout occurred while waiting server connect");
|
||||||
|
return CURLE_FTP_ACCEPT_TIMEOUT;
|
||||||
}
|
}
|
||||||
/* never reaches this point */
|
|
||||||
|
/* First check whether there is a cached response from server */
|
||||||
|
if(pp->cache_size && pp->cache && pp->cache[0] > '3') {
|
||||||
|
/* Data connection could not be established, let's return */
|
||||||
|
infof(data, "There is negative response in cache while serv connect");
|
||||||
|
Curl_GetFTPResponse(&nread, conn, &ftpcode);
|
||||||
|
return CURLE_FTP_ACCEPT_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = Curl_socket_check(ctrl_sock, data_sock, CURL_SOCKET_BAD, 0);
|
||||||
|
|
||||||
|
/* see if the connection request is already here */
|
||||||
|
switch (result) {
|
||||||
|
case -1: /* error */
|
||||||
|
/* let's die here */
|
||||||
|
failf(data, "Error while waiting for server connect");
|
||||||
|
return CURLE_FTP_ACCEPT_FAILED;
|
||||||
|
case 0: /* Server connect is not received yet */
|
||||||
|
break; /* loop */
|
||||||
|
default:
|
||||||
|
|
||||||
|
if(result & CURL_CSELECT_IN2) {
|
||||||
|
infof(data, "Ready to accept data connection from server\n");
|
||||||
|
*received = TRUE;
|
||||||
|
}
|
||||||
|
else if(result & CURL_CSELECT_IN) {
|
||||||
|
infof(data, "Ctrl conn has data while waiting for data conn\n");
|
||||||
|
Curl_GetFTPResponse(&nread, conn, &ftpcode);
|
||||||
|
|
||||||
|
if(ftpcode/100 > 3)
|
||||||
|
return CURLE_FTP_ACCEPT_FAILED;
|
||||||
|
|
||||||
|
return CURLE_FTP_WEIRD_SERVER_REPLY;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
} /* switch() */
|
||||||
|
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
*
|
||||||
|
* InitiateTransfer()
|
||||||
|
*
|
||||||
|
* After connection from server is accepted this function is called to
|
||||||
|
* setup transfer parameters and initiate the data transfer.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static CURLcode InitiateTransfer(struct connectdata *conn)
|
||||||
|
{
|
||||||
|
struct SessionHandle *data = conn->data;
|
||||||
|
struct FTP *ftp = data->state.proto.ftp;
|
||||||
|
CURLcode result = CURLE_OK;
|
||||||
|
|
||||||
|
if(conn->ssl[SECONDARYSOCKET].use) {
|
||||||
|
/* since we only have a plaintext TCP connection here, we must now
|
||||||
|
* do the TLS stuff */
|
||||||
|
infof(data, "Doing the SSL/TLS handshake on the data stream\n");
|
||||||
|
result = Curl_ssl_connect(conn, SECONDARYSOCKET);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(conn->proto.ftpc.state_saved == FTP_STOR) {
|
||||||
|
*(ftp->bytecountp)=0;
|
||||||
|
|
||||||
|
/* When we know we're uploading a specified file, we can get the file
|
||||||
|
size prior to the actual upload. */
|
||||||
|
|
||||||
|
Curl_pgrsSetUploadSize(data, data->set.infilesize);
|
||||||
|
|
||||||
|
/* set the SO_SNDBUF for the secondary socket for those who need it */
|
||||||
|
Curl_sndbufset(conn->sock[SECONDARYSOCKET]);
|
||||||
|
|
||||||
|
Curl_setup_transfer(conn, -1, -1, FALSE, NULL, /* no download */
|
||||||
|
SECONDARYSOCKET, ftp->bytecountp);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* FTP download: */
|
||||||
|
Curl_setup_transfer(conn, SECONDARYSOCKET,
|
||||||
|
conn->proto.ftpc.retr_size_saved, FALSE,
|
||||||
|
ftp->bytecountp, -1, NULL); /* no upload here */
|
||||||
|
}
|
||||||
|
|
||||||
|
conn->proto.ftpc.pp.pending_resp = TRUE; /* expect server response */
|
||||||
|
state(conn, FTP_STOP);
|
||||||
|
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
*
|
||||||
|
* AllowServerConnect()
|
||||||
|
*
|
||||||
|
* When we've issue the PORT command, we have told the server to connect
|
||||||
|
* to us. This function
|
||||||
|
* - will sit and wait here until the server has connected for easy interface
|
||||||
|
* - will check whether data connection is established if so it is accepted
|
||||||
|
* for multi interface
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static CURLcode AllowServerConnect(struct connectdata *conn, bool *connected)
|
||||||
|
{
|
||||||
|
struct SessionHandle *data = conn->data;
|
||||||
|
long timeout_ms;
|
||||||
|
long interval_ms;
|
||||||
|
CURLcode ret = CURLE_OK;
|
||||||
|
|
||||||
|
*connected = FALSE;
|
||||||
|
infof(data, "Preparing for accepting server on data port\n");
|
||||||
|
|
||||||
|
/* Save the time we start accepting server connect */
|
||||||
|
Curl_pgrsTime(data, TIMER_STARTACCEPT);
|
||||||
|
|
||||||
|
for(;;) {
|
||||||
|
timeout_ms = Curl_timeleft_accept(data);
|
||||||
|
if(timeout_ms < 0) {
|
||||||
|
/* if a timeout was already reached, bail out */
|
||||||
|
failf(data, "Accept timeout occurred while waiting server connect");
|
||||||
|
return CURLE_FTP_ACCEPT_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* see if the connection request is already here */
|
||||||
|
ret = ReceivedServerConnect(conn, connected);
|
||||||
|
if(ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if(*connected) {
|
||||||
|
ret = AcceptServerConnect(conn);
|
||||||
|
if(ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = InitiateTransfer(conn);
|
||||||
|
if(ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
break; /* connection is accepted, break the loop */
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(data->state.used_interface == Curl_if_easy) {
|
||||||
|
interval_ms = 1000;
|
||||||
|
if(timeout_ms < interval_ms)
|
||||||
|
interval_ms = timeout_ms;
|
||||||
|
|
||||||
|
/* sleep for 1 second and then continue */
|
||||||
|
Curl_socket_ready(CURL_SOCKET_BAD, CURL_SOCKET_BAD, interval_ms);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* Add timeout to multi handle and break out of the loop */
|
||||||
|
if(ret == CURLE_OK && *connected == FALSE) {
|
||||||
|
if(data->set.accepttimeout > 0)
|
||||||
|
Curl_expire(data, data->set.accepttimeout);
|
||||||
|
else
|
||||||
|
Curl_expire(data, DEFAULT_ACCEPT_TIMEOUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
break; /* connection was not accepted immediately */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* macro to check for a three-digit ftp status code at the start of the
|
/* macro to check for a three-digit ftp status code at the start of the
|
||||||
@ -668,6 +844,10 @@ static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks,
|
|||||||
}
|
}
|
||||||
|
|
||||||
socks[0] = conn->sock[SECONDARYSOCKET];
|
socks[0] = conn->sock[SECONDARYSOCKET];
|
||||||
|
if(conn->bits.wait_data_conn) {
|
||||||
|
socks[1] = conn->sock[FIRSTSOCKET];
|
||||||
|
return GETSOCK_READSOCK(0) | GETSOCK_READSOCK(1);
|
||||||
|
}
|
||||||
|
|
||||||
return GETSOCK_READSOCK(0);
|
return GETSOCK_READSOCK(0);
|
||||||
}
|
}
|
||||||
@ -2153,11 +2333,10 @@ static CURLcode ftp_state_rest_resp(struct connectdata *conn,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static CURLcode ftp_state_stor_resp(struct connectdata *conn,
|
static CURLcode ftp_state_stor_resp(struct connectdata *conn,
|
||||||
int ftpcode)
|
int ftpcode, ftpstate instate)
|
||||||
{
|
{
|
||||||
CURLcode result = CURLE_OK;
|
CURLcode result = CURLE_OK;
|
||||||
struct SessionHandle *data = conn->data;
|
struct SessionHandle *data = conn->data;
|
||||||
struct FTP *ftp = data->state.proto.ftp;
|
|
||||||
|
|
||||||
if(ftpcode>=400) {
|
if(ftpcode>=400) {
|
||||||
failf(data, "Failed FTP upload: %0d", ftpcode);
|
failf(data, "Failed FTP upload: %0d", ftpcode);
|
||||||
@ -2165,41 +2344,26 @@ static CURLcode ftp_state_stor_resp(struct connectdata *conn,
|
|||||||
return CURLE_UPLOAD_FAILED;
|
return CURLE_UPLOAD_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(data->set.ftp_use_port) {
|
conn->proto.ftpc.state_saved = instate;
|
||||||
/* BLOCKING */
|
|
||||||
/* PORT means we are now awaiting the server to connect to us. */
|
/* PORT means we are now awaiting the server to connect to us. */
|
||||||
result = AllowServerConnect(conn);
|
if(data->set.ftp_use_port) {
|
||||||
|
bool connected;
|
||||||
|
|
||||||
|
result = AllowServerConnect(conn, &connected);
|
||||||
if(result)
|
if(result)
|
||||||
return result;
|
return result;
|
||||||
}
|
|
||||||
|
|
||||||
if(conn->ssl[SECONDARYSOCKET].use) {
|
if(!connected) {
|
||||||
/* since we only have a plaintext TCP connection here, we must now
|
infof(data, "Data conn was not available immediately\n");
|
||||||
do the TLS stuff */
|
|
||||||
infof(data, "Doing the SSL/TLS handshake on the data stream\n");
|
|
||||||
/* BLOCKING */
|
|
||||||
result = Curl_ssl_connect(conn, SECONDARYSOCKET);
|
|
||||||
if(result)
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
*(ftp->bytecountp)=0;
|
|
||||||
|
|
||||||
/* When we know we're uploading a specified file, we can get the file
|
|
||||||
size prior to the actual upload. */
|
|
||||||
|
|
||||||
Curl_pgrsSetUploadSize(data, data->set.infilesize);
|
|
||||||
|
|
||||||
/* set the SO_SNDBUF for the secondary socket for those who need it */
|
|
||||||
Curl_sndbufset(conn->sock[SECONDARYSOCKET]);
|
|
||||||
|
|
||||||
Curl_setup_transfer(conn, -1, -1, FALSE, NULL, /* no download */
|
|
||||||
SECONDARYSOCKET, ftp->bytecountp);
|
|
||||||
state(conn, FTP_STOP);
|
state(conn, FTP_STOP);
|
||||||
|
conn->bits.wait_data_conn = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
conn->proto.ftpc.pp.pending_resp = TRUE; /* expect a server response */
|
return CURLE_OK;
|
||||||
|
}
|
||||||
return result;
|
else
|
||||||
|
return InitiateTransfer(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* for LIST and RETR responses */
|
/* for LIST and RETR responses */
|
||||||
@ -2280,22 +2444,6 @@ static CURLcode ftp_state_get_resp(struct connectdata *conn,
|
|||||||
else if(ftp->downloadsize > -1)
|
else if(ftp->downloadsize > -1)
|
||||||
size = ftp->downloadsize;
|
size = ftp->downloadsize;
|
||||||
|
|
||||||
if(data->set.ftp_use_port) {
|
|
||||||
/* BLOCKING */
|
|
||||||
result = AllowServerConnect(conn);
|
|
||||||
if(result)
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(conn->ssl[SECONDARYSOCKET].use) {
|
|
||||||
/* since we only have a plaintext TCP connection here, we must now
|
|
||||||
do the TLS stuff */
|
|
||||||
infof(data, "Doing the SSL/TLS handshake on the data stream\n");
|
|
||||||
result = Curl_ssl_connect(conn, SECONDARYSOCKET);
|
|
||||||
if(result)
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(size > data->req.maxdownload && data->req.maxdownload > 0)
|
if(size > data->req.maxdownload && data->req.maxdownload > 0)
|
||||||
size = data->req.size = data->req.maxdownload;
|
size = data->req.size = data->req.maxdownload;
|
||||||
else if((instate != FTP_LIST) && (data->set.prefer_ascii))
|
else if((instate != FTP_LIST) && (data->set.prefer_ascii))
|
||||||
@ -2307,11 +2455,24 @@ static CURLcode ftp_state_get_resp(struct connectdata *conn,
|
|||||||
infof(data, "Getting file with size: %" FORMAT_OFF_T "\n", size);
|
infof(data, "Getting file with size: %" FORMAT_OFF_T "\n", size);
|
||||||
|
|
||||||
/* FTP download: */
|
/* FTP download: */
|
||||||
Curl_setup_transfer(conn, SECONDARYSOCKET, size, FALSE,
|
conn->proto.ftpc.state_saved = instate;
|
||||||
ftp->bytecountp, -1, NULL); /* no upload here */
|
conn->proto.ftpc.retr_size_saved = size;
|
||||||
|
|
||||||
conn->proto.ftpc.pp.pending_resp = TRUE; /* expect server response */
|
if(data->set.ftp_use_port) {
|
||||||
|
bool connected;
|
||||||
|
|
||||||
|
result = AllowServerConnect(conn, &connected);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
if(!connected) {
|
||||||
|
infof(data, "Data conn was not available immediately\n");
|
||||||
state(conn, FTP_STOP);
|
state(conn, FTP_STOP);
|
||||||
|
conn->bits.wait_data_conn = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return InitiateTransfer(conn);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if((instate == FTP_LIST) && (ftpcode == 450)) {
|
if((instate == FTP_LIST) && (ftpcode == 450)) {
|
||||||
@ -2459,7 +2620,6 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
|
|||||||
if(pp->sendleft)
|
if(pp->sendleft)
|
||||||
return Curl_pp_flushsend(pp);
|
return Curl_pp_flushsend(pp);
|
||||||
|
|
||||||
/* we read a piece of response */
|
|
||||||
result = ftp_readresp(sock, pp, &ftpcode, &nread);
|
result = ftp_readresp(sock, pp, &ftpcode, &nread);
|
||||||
if(result)
|
if(result)
|
||||||
return result;
|
return result;
|
||||||
@ -2865,7 +3025,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case FTP_STOR:
|
case FTP_STOR:
|
||||||
result = ftp_state_stor_resp(conn, ftpcode);
|
result = ftp_state_stor_resp(conn, ftpcode, ftpc->state);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FTP_QUIT:
|
case FTP_QUIT:
|
||||||
@ -3081,6 +3241,8 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
|
|||||||
case CURLE_BAD_DOWNLOAD_RESUME:
|
case CURLE_BAD_DOWNLOAD_RESUME:
|
||||||
case CURLE_FTP_WEIRD_PASV_REPLY:
|
case CURLE_FTP_WEIRD_PASV_REPLY:
|
||||||
case CURLE_FTP_PORT_FAILED:
|
case CURLE_FTP_PORT_FAILED:
|
||||||
|
case CURLE_FTP_ACCEPT_FAILED:
|
||||||
|
case CURLE_FTP_ACCEPT_TIMEOUT:
|
||||||
case CURLE_FTP_COULDNT_SET_TYPE:
|
case CURLE_FTP_COULDNT_SET_TYPE:
|
||||||
case CURLE_FTP_COULDNT_RETR_FILE:
|
case CURLE_FTP_COULDNT_RETR_FILE:
|
||||||
case CURLE_UPLOAD_FAILED:
|
case CURLE_UPLOAD_FAILED:
|
||||||
@ -3474,7 +3636,24 @@ static CURLcode ftp_nextconnect(struct connectdata *conn)
|
|||||||
/* a transfer is about to take place, or if not a file name was given
|
/* a transfer is about to take place, or if not a file name was given
|
||||||
so we'll do a SIZE on it later and then we need the right TYPE first */
|
so we'll do a SIZE on it later and then we need the right TYPE first */
|
||||||
|
|
||||||
if(data->set.upload) {
|
if(conn->bits.wait_data_conn == TRUE) {
|
||||||
|
bool serv_conned;
|
||||||
|
|
||||||
|
result = ReceivedServerConnect(conn, &serv_conned);
|
||||||
|
if(result)
|
||||||
|
return result; /* Failed to accept data connection */
|
||||||
|
|
||||||
|
if(serv_conned) {
|
||||||
|
/* It looks data connection is established */
|
||||||
|
result = AcceptServerConnect(conn);
|
||||||
|
conn->bits.wait_data_conn = FALSE;
|
||||||
|
if(result == CURLE_OK)
|
||||||
|
result = InitiateTransfer(conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
else if(data->set.upload) {
|
||||||
result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_STOR_TYPE);
|
result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_STOR_TYPE);
|
||||||
if(result)
|
if(result)
|
||||||
return result;
|
return result;
|
||||||
@ -3513,7 +3692,6 @@ static CURLcode ftp_nextconnect(struct connectdata *conn)
|
|||||||
too! */
|
too! */
|
||||||
Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
|
Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
|
||||||
|
|
||||||
/* end of transfer */
|
|
||||||
DEBUGF(infof(data, "DO-MORE phase ends with %d\n", (int)result));
|
DEBUGF(infof(data, "DO-MORE phase ends with %d\n", (int)result));
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -146,6 +146,9 @@ struct ftp_conn {
|
|||||||
int count2; /* general purpose counter for the state machine */
|
int count2; /* general purpose counter for the state machine */
|
||||||
int count3; /* general purpose counter for the state machine */
|
int count3; /* general purpose counter for the state machine */
|
||||||
ftpstate state; /* always use ftp.c:state() to change state! */
|
ftpstate state; /* always use ftp.c:state() to change state! */
|
||||||
|
ftpstate state_saved; /* transfer type saved to be reloaded after
|
||||||
|
data connection is established */
|
||||||
|
curl_off_t retr_size_saved; /* Size of retrieved file saved */
|
||||||
char * server_os; /* The target server operating system. */
|
char * server_os; /* The target server operating system. */
|
||||||
curl_off_t known_filesize; /* file size is different from -1, if wildcard
|
curl_off_t known_filesize; /* file size is different from -1, if wildcard
|
||||||
LIST parsing was done and wc_statemach set
|
LIST parsing was done and wc_statemach set
|
||||||
|
@ -1388,6 +1388,13 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case CURLM_STATE_DO_DONE:
|
case CURLM_STATE_DO_DONE:
|
||||||
|
|
||||||
|
if(easy->easy_conn->bits.wait_data_conn == TRUE) {
|
||||||
|
multistate(easy, CURLM_STATE_DO_MORE);
|
||||||
|
result = CURLM_OK;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* Move ourselves from the send to recv pipeline */
|
/* Move ourselves from the send to recv pipeline */
|
||||||
moveHandleFromSendToRecvPipeline(data, easy->easy_conn);
|
moveHandleFromSendToRecvPipeline(data, easy->easy_conn);
|
||||||
/* Check if we can move pending requests to send pipe */
|
/* Check if we can move pending requests to send pipe */
|
||||||
|
@ -169,6 +169,10 @@ void Curl_pgrsTime(struct SessionHandle *data, timerid timer)
|
|||||||
data->progress.t_startsingle = now;
|
data->progress.t_startsingle = now;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TIMER_STARTACCEPT:
|
||||||
|
data->progress.t_acceptdata = Curl_tvnow();
|
||||||
|
break;
|
||||||
|
|
||||||
case TIMER_NAMELOOKUP:
|
case TIMER_NAMELOOKUP:
|
||||||
data->progress.t_nslookup =
|
data->progress.t_nslookup =
|
||||||
Curl_tvdiff_secs(now, data->progress.t_startsingle);
|
Curl_tvdiff_secs(now, data->progress.t_startsingle);
|
||||||
|
@ -34,6 +34,7 @@ typedef enum {
|
|||||||
TIMER_STARTTRANSFER,
|
TIMER_STARTTRANSFER,
|
||||||
TIMER_POSTRANSFER,
|
TIMER_POSTRANSFER,
|
||||||
TIMER_STARTSINGLE,
|
TIMER_STARTSINGLE,
|
||||||
|
TIMER_STARTACCEPT,
|
||||||
TIMER_REDIRECT,
|
TIMER_REDIRECT,
|
||||||
TIMER_LAST /* must be last */
|
TIMER_LAST /* must be last */
|
||||||
} timerid;
|
} timerid;
|
||||||
|
@ -81,6 +81,12 @@ curl_easy_strerror(CURLcode error)
|
|||||||
case CURLE_REMOTE_ACCESS_DENIED:
|
case CURLE_REMOTE_ACCESS_DENIED:
|
||||||
return "Access denied to remote resource";
|
return "Access denied to remote resource";
|
||||||
|
|
||||||
|
case CURLE_FTP_ACCEPT_FAILED:
|
||||||
|
return "FTP: The server failed to connect to data port";
|
||||||
|
|
||||||
|
case CURLE_FTP_ACCEPT_TIMEOUT:
|
||||||
|
return "FTP: Accepting server connect has timed out";
|
||||||
|
|
||||||
case CURLE_FTP_PRET_FAILED:
|
case CURLE_FTP_PRET_FAILED:
|
||||||
return "FTP: The server did not accept the PRET command.";
|
return "FTP: The server did not accept the PRET command.";
|
||||||
|
|
||||||
@ -284,8 +290,6 @@ curl_easy_strerror(CURLcode error)
|
|||||||
return "Chunk callback failed";
|
return "Chunk callback failed";
|
||||||
|
|
||||||
/* error codes not used by current libcurl */
|
/* error codes not used by current libcurl */
|
||||||
case CURLE_OBSOLETE10:
|
|
||||||
case CURLE_OBSOLETE12:
|
|
||||||
case CURLE_OBSOLETE16:
|
case CURLE_OBSOLETE16:
|
||||||
case CURLE_OBSOLETE20:
|
case CURLE_OBSOLETE20:
|
||||||
case CURLE_OBSOLETE24:
|
case CURLE_OBSOLETE24:
|
||||||
|
@ -1677,6 +1677,13 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
|
|||||||
data->set.connecttimeout = va_arg(param, long);
|
data->set.connecttimeout = va_arg(param, long);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case CURLOPT_ACCEPTTIMEOUT_MS:
|
||||||
|
/*
|
||||||
|
* The maximum time you allow curl to wait for server connect
|
||||||
|
*/
|
||||||
|
data->set.accepttimeout = va_arg(param, long);
|
||||||
|
break;
|
||||||
|
|
||||||
case CURLOPT_USERPWD:
|
case CURLOPT_USERPWD:
|
||||||
/*
|
/*
|
||||||
* user:password to use in the operation
|
* user:password to use in the operation
|
||||||
@ -5457,7 +5464,7 @@ CURLcode Curl_do_more(struct connectdata *conn)
|
|||||||
if(conn->handler->do_more)
|
if(conn->handler->do_more)
|
||||||
result = conn->handler->do_more(conn);
|
result = conn->handler->do_more(conn);
|
||||||
|
|
||||||
if(result == CURLE_OK)
|
if(result == CURLE_OK && conn->bits.wait_data_conn == FALSE)
|
||||||
/* do_complete must be called after the protocol-specific DO function */
|
/* do_complete must be called after the protocol-specific DO function */
|
||||||
do_complete(conn);
|
do_complete(conn);
|
||||||
|
|
||||||
|
@ -412,6 +412,8 @@ struct ConnectBits {
|
|||||||
bool do_more; /* this is set TRUE if the ->curl_do_more() function is
|
bool do_more; /* this is set TRUE if the ->curl_do_more() function is
|
||||||
supposed to be called, after ->curl_do() */
|
supposed to be called, after ->curl_do() */
|
||||||
|
|
||||||
|
bool wait_data_conn; /* this is set TRUE if data connection is waited */
|
||||||
|
|
||||||
bool tcpconnect[2]; /* the TCP layer (or similar) is connected, this is set
|
bool tcpconnect[2]; /* the TCP layer (or similar) is connected, this is set
|
||||||
the first time on the first connect function call */
|
the first time on the first connect function call */
|
||||||
bool protoconnstart;/* the protocol layer has STARTED its operation after
|
bool protoconnstart;/* the protocol layer has STARTED its operation after
|
||||||
@ -1038,6 +1040,7 @@ struct Progress {
|
|||||||
|
|
||||||
struct timeval start;
|
struct timeval start;
|
||||||
struct timeval t_startsingle;
|
struct timeval t_startsingle;
|
||||||
|
struct timeval t_acceptdata;
|
||||||
#define CURR_TIME (5+1) /* 6 entries for 5 seconds */
|
#define CURR_TIME (5+1) /* 6 entries for 5 seconds */
|
||||||
|
|
||||||
curl_off_t speeder[ CURR_TIME ];
|
curl_off_t speeder[ CURR_TIME ];
|
||||||
@ -1407,6 +1410,7 @@ struct UserDefined {
|
|||||||
void *ioctl_client; /* pointer to pass to the ioctl callback */
|
void *ioctl_client; /* pointer to pass to the ioctl callback */
|
||||||
long timeout; /* in milliseconds, 0 means no timeout */
|
long timeout; /* in milliseconds, 0 means no timeout */
|
||||||
long connecttimeout; /* in milliseconds, 0 means no timeout */
|
long connecttimeout; /* in milliseconds, 0 means no timeout */
|
||||||
|
long accepttimeout; /* in milliseconds, 0 means no timeout */
|
||||||
long server_response_timeout; /* in milliseconds, 0 means no timeout */
|
long server_response_timeout; /* in milliseconds, 0 means no timeout */
|
||||||
long tftp_blksize ; /* in bytes, 0 means use default */
|
long tftp_blksize ; /* in bytes, 0 means use default */
|
||||||
curl_off_t infilesize; /* size of file to upload, -1 means unknown */
|
curl_off_t infilesize; /* size of file to upload, -1 means unknown */
|
||||||
|
@ -2,8 +2,6 @@
|
|||||||
# test cases are run by runtests.pl. Just add the plain test case numbers, one
|
# test cases are run by runtests.pl. Just add the plain test case numbers, one
|
||||||
# per line.
|
# per line.
|
||||||
# Lines starting with '#' letters are treated as comments.
|
# Lines starting with '#' letters are treated as comments.
|
||||||
591
|
|
||||||
592
|
|
||||||
593
|
|
||||||
594
|
594
|
||||||
|
1209
|
||||||
1211
|
1211
|
||||||
|
@ -36,12 +36,6 @@ FTP PORT and 425 on download
|
|||||||
<strippart>
|
<strippart>
|
||||||
s/^EPRT \|1\|(.*)/EPRT \|1\|/
|
s/^EPRT \|1\|(.*)/EPRT \|1\|/
|
||||||
</strippart>
|
</strippart>
|
||||||
|
|
||||||
# The protocol part does not include QUIT simply because the error is
|
|
||||||
# CURLE_OPERATION_TIMEDOUT (28) which is a generic timeout error without
|
|
||||||
# specificly saying for which connection it concerns, and for timeouts libcurl
|
|
||||||
# marks the control channel as "invalid". As this test case times out for the
|
|
||||||
# data connection it could still use the control channel.
|
|
||||||
<protocol>
|
<protocol>
|
||||||
USER anonymous
|
USER anonymous
|
||||||
PASS ftp@example.com
|
PASS ftp@example.com
|
||||||
@ -50,9 +44,10 @@ EPRT |1|
|
|||||||
TYPE I
|
TYPE I
|
||||||
SIZE 1206
|
SIZE 1206
|
||||||
RETR 1206
|
RETR 1206
|
||||||
|
QUIT
|
||||||
</protocol>
|
</protocol>
|
||||||
<errorcode>
|
<errorcode>
|
||||||
28
|
10
|
||||||
</errorcode>
|
</errorcode>
|
||||||
</verify>
|
</verify>
|
||||||
</testcase>
|
</testcase>
|
||||||
|
@ -36,12 +36,6 @@ FTP PORT and 421 on download
|
|||||||
<strippart>
|
<strippart>
|
||||||
s/^EPRT \|1\|(.*)/EPRT \|1\|/
|
s/^EPRT \|1\|(.*)/EPRT \|1\|/
|
||||||
</strippart>
|
</strippart>
|
||||||
|
|
||||||
# The protocol part does not include QUIT simply because the error is
|
|
||||||
# CURLE_OPERATION_TIMEDOUT (28) which is a generic timeout error without
|
|
||||||
# specificly saying for which connection it concerns, and for timeouts libcurl
|
|
||||||
# marks the control channel as "invalid". As this test case times out for the
|
|
||||||
# data connection it could still use the control channel.
|
|
||||||
<protocol>
|
<protocol>
|
||||||
USER anonymous
|
USER anonymous
|
||||||
PASS ftp@example.com
|
PASS ftp@example.com
|
||||||
@ -50,9 +44,10 @@ EPRT |1|
|
|||||||
TYPE I
|
TYPE I
|
||||||
SIZE 1207
|
SIZE 1207
|
||||||
RETR 1207
|
RETR 1207
|
||||||
|
QUIT
|
||||||
</protocol>
|
</protocol>
|
||||||
<errorcode>
|
<errorcode>
|
||||||
28
|
10
|
||||||
</errorcode>
|
</errorcode>
|
||||||
</verify>
|
</verify>
|
||||||
</testcase>
|
</testcase>
|
||||||
|
@ -36,12 +36,6 @@ FTP PORT download, no data conn and no transient negative reply
|
|||||||
<strippart>
|
<strippart>
|
||||||
s/^EPRT \|1\|(.*)/EPRT \|1\|/
|
s/^EPRT \|1\|(.*)/EPRT \|1\|/
|
||||||
</strippart>
|
</strippart>
|
||||||
|
|
||||||
# The protocol part does not include QUIT simply because the error is
|
|
||||||
# CURLE_OPERATION_TIMEDOUT (28) which is a generic timeout error without
|
|
||||||
# specificly saying for which connection it concerns, and for timeouts libcurl
|
|
||||||
# marks the control channel as "invalid". As this test case times out for the
|
|
||||||
# data connection it could still use the control channel.
|
|
||||||
<protocol>
|
<protocol>
|
||||||
USER anonymous
|
USER anonymous
|
||||||
PASS ftp@example.com
|
PASS ftp@example.com
|
||||||
@ -50,9 +44,10 @@ EPRT |1|
|
|||||||
TYPE I
|
TYPE I
|
||||||
SIZE 1208
|
SIZE 1208
|
||||||
RETR 1208
|
RETR 1208
|
||||||
|
QUIT
|
||||||
</protocol>
|
</protocol>
|
||||||
<errorcode>
|
<errorcode>
|
||||||
28
|
12
|
||||||
</errorcode>
|
</errorcode>
|
||||||
</verify>
|
</verify>
|
||||||
</testcase>
|
</testcase>
|
||||||
|
@ -64,7 +64,7 @@ STOR 591
|
|||||||
QUIT
|
QUIT
|
||||||
</protocol>
|
</protocol>
|
||||||
<errorcode>
|
<errorcode>
|
||||||
28
|
10
|
||||||
</errorcode>
|
</errorcode>
|
||||||
<upload>
|
<upload>
|
||||||
</upload>
|
</upload>
|
||||||
|
@ -64,7 +64,7 @@ STOR 592
|
|||||||
QUIT
|
QUIT
|
||||||
</protocol>
|
</protocol>
|
||||||
<errorcode>
|
<errorcode>
|
||||||
28
|
10
|
||||||
</errorcode>
|
</errorcode>
|
||||||
<upload>
|
<upload>
|
||||||
</upload>
|
</upload>
|
||||||
|
@ -64,7 +64,7 @@ STOR 593
|
|||||||
QUIT
|
QUIT
|
||||||
</protocol>
|
</protocol>
|
||||||
<errorcode>
|
<errorcode>
|
||||||
28
|
12
|
||||||
</errorcode>
|
</errorcode>
|
||||||
<upload>
|
<upload>
|
||||||
</upload>
|
</upload>
|
||||||
|
@ -77,7 +77,8 @@ int test(char *URL)
|
|||||||
easy_setopt(easy, CURLOPT_FTPPORT, "-");
|
easy_setopt(easy, CURLOPT_FTPPORT, "-");
|
||||||
|
|
||||||
/* server connection timeout */
|
/* server connection timeout */
|
||||||
easy_setopt(easy, CURLOPT_CONNECTTIMEOUT, strtol(libtest_arg2, NULL, 10));
|
easy_setopt(easy, CURLOPT_ACCEPTTIMEOUT_MS,
|
||||||
|
strtol(libtest_arg2, NULL, 10)*1000);
|
||||||
|
|
||||||
multi_init(multi);
|
multi_init(multi);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user