mirror of https://github.com/moparisthebest/curl
Initial fix to make the multi interface return control while waiting for
the initial connect to "come through". This should work fine for connect and for FTP-PASV connects. Needs massive testing.
This commit is contained in:
parent
2df4866cfa
commit
cb895ec335
|
@ -337,6 +337,70 @@ int socketerror(int sockfd)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Curl_is_connected() is used from the multi interface to check if the
|
||||||
|
* firstsocket has connected.
|
||||||
|
*/
|
||||||
|
|
||||||
|
CURLcode Curl_is_connected(struct connectdata *conn,
|
||||||
|
int sockfd,
|
||||||
|
bool *connected)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
struct SessionHandle *data = conn->data;
|
||||||
|
|
||||||
|
*connected = FALSE; /* a very negative world view is best */
|
||||||
|
|
||||||
|
if(data->set.timeout || data->set.connecttimeout) {
|
||||||
|
/* there is a timeout set */
|
||||||
|
|
||||||
|
/* Evaluate in milliseconds how much time that has passed */
|
||||||
|
long has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.start);
|
||||||
|
|
||||||
|
/* subtract the most strict timeout of the ones */
|
||||||
|
if(data->set.timeout && data->set.connecttimeout) {
|
||||||
|
if (data->set.timeout < data->set.connecttimeout)
|
||||||
|
has_passed -= data->set.timeout*1000;
|
||||||
|
else
|
||||||
|
has_passed -= data->set.connecttimeout*1000;
|
||||||
|
}
|
||||||
|
else if(data->set.timeout)
|
||||||
|
has_passed -= data->set.timeout*1000;
|
||||||
|
else
|
||||||
|
has_passed -= data->set.connecttimeout*1000;
|
||||||
|
|
||||||
|
if(has_passed > 0 ) {
|
||||||
|
/* time-out, bail out, go home */
|
||||||
|
failf(data, "Connection time-out");
|
||||||
|
return CURLE_OPERATION_TIMEOUTED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check for connect without timeout as we want to return immediately */
|
||||||
|
rc = waitconnect(sockfd, 0);
|
||||||
|
|
||||||
|
if(0 == rc) {
|
||||||
|
int err = socketerror(sockfd);
|
||||||
|
if ((0 == err) || (EISCONN == err)) {
|
||||||
|
/* we are connected, awesome! */
|
||||||
|
*connected = TRUE;
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
/* nope, not connected for real */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the connection phase is "done" here, we should attempt to connect
|
||||||
|
* to the "next address" in the Curl_hostaddr structure that we resolved
|
||||||
|
* before. But we don't have that struct around anymore and we can't just
|
||||||
|
* keep a pointer since the cache might in fact have gotten pruned by the
|
||||||
|
* time we want to read this... Alas, we don't do this yet.
|
||||||
|
*/
|
||||||
|
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TCP connect to the given host with timeout, proxy or remote doesn't matter.
|
* TCP connect to the given host with timeout, proxy or remote doesn't matter.
|
||||||
* There might be more than one IP address to try out. Fill in the passed
|
* There might be more than one IP address to try out. Fill in the passed
|
||||||
|
@ -347,7 +411,8 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
|
||||||
Curl_addrinfo *remotehost, /* use one in here */
|
Curl_addrinfo *remotehost, /* use one in here */
|
||||||
int port, /* connect to this */
|
int port, /* connect to this */
|
||||||
int *sockconn, /* the connected socket */
|
int *sockconn, /* the connected socket */
|
||||||
Curl_ipconnect **addr) /* the one we used */
|
Curl_ipconnect **addr, /* the one we used */
|
||||||
|
bool *connected) /* really connected? */
|
||||||
{
|
{
|
||||||
struct SessionHandle *data = conn->data;
|
struct SessionHandle *data = conn->data;
|
||||||
int rc;
|
int rc;
|
||||||
|
@ -437,8 +502,11 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
|
||||||
case EAGAIN:
|
case EAGAIN:
|
||||||
#endif
|
#endif
|
||||||
case EINTR:
|
case EINTR:
|
||||||
|
|
||||||
/* asynchronous connect, wait for connect or timeout */
|
/* asynchronous connect, wait for connect or timeout */
|
||||||
|
if(data->state.used_interface == Curl_if_multi)
|
||||||
|
/* don't hang when doing multi */
|
||||||
|
timeout_ms = 0;
|
||||||
|
|
||||||
rc = waitconnect(sockfd, timeout_ms);
|
rc = waitconnect(sockfd, timeout_ms);
|
||||||
break;
|
break;
|
||||||
case ECONNREFUSED: /* no one listening */
|
case ECONNREFUSED: /* no one listening */
|
||||||
|
@ -448,6 +516,7 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(0 == rc) {
|
if(0 == rc) {
|
||||||
/* we might be connected, if the socket says it is OK! Ask it! */
|
/* we might be connected, if the socket says it is OK! Ask it! */
|
||||||
int err;
|
int err;
|
||||||
|
@ -455,11 +524,17 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
|
||||||
err = socketerror(sockfd);
|
err = socketerror(sockfd);
|
||||||
if ((0 == err) || (EISCONN == err)) {
|
if ((0 == err) || (EISCONN == err)) {
|
||||||
/* we are connected, awesome! */
|
/* we are connected, awesome! */
|
||||||
|
*connected = TRUE; /* this is truly a connect */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
failf(data, "socket error: %d", err);
|
failf(data, "socket error: %d", err);
|
||||||
/* we are _not_ connected, it was a false alert, continue please */
|
/* we are _not_ connected, it was a false alert, continue please */
|
||||||
}
|
}
|
||||||
|
else if(data->state.used_interface == Curl_if_multi) {
|
||||||
|
/* When running the multi interface, we bail out here */
|
||||||
|
rc = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* connect failed or timed out */
|
/* connect failed or timed out */
|
||||||
sclose(sockfd);
|
sclose(sockfd);
|
||||||
|
@ -542,8 +617,11 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
|
||||||
*/
|
*/
|
||||||
case EAGAIN:
|
case EAGAIN:
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* asynchronous connect, wait for connect or timeout */
|
/* asynchronous connect, wait for connect or timeout */
|
||||||
|
if(data->state.used_interface == Curl_if_multi)
|
||||||
|
/* don't hang when doing multi */
|
||||||
|
timeout_ms = 0;
|
||||||
|
|
||||||
rc = waitconnect(sockfd, timeout_ms);
|
rc = waitconnect(sockfd, timeout_ms);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -558,6 +636,7 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
|
||||||
int err = socketerror(sockfd);
|
int err = socketerror(sockfd);
|
||||||
if ((0 == err) || (EISCONN == err)) {
|
if ((0 == err) || (EISCONN == err)) {
|
||||||
/* we are connected, awesome! */
|
/* we are connected, awesome! */
|
||||||
|
*connected = TRUE; /* this is a true connect */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* nope, not connected for real */
|
/* nope, not connected for real */
|
||||||
|
@ -565,6 +644,12 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
|
||||||
}
|
}
|
||||||
|
|
||||||
if(0 != rc) {
|
if(0 != rc) {
|
||||||
|
if(data->state.used_interface == Curl_if_multi) {
|
||||||
|
/* When running the multi interface, we bail out here */
|
||||||
|
rc = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* get a new timeout for next attempt */
|
/* get a new timeout for next attempt */
|
||||||
after = Curl_tvnow();
|
after = Curl_tvnow();
|
||||||
timeout_ms -= Curl_tvdiff(after, before);
|
timeout_ms -= Curl_tvdiff(after, before);
|
||||||
|
|
|
@ -26,10 +26,15 @@
|
||||||
int Curl_nonblock(int socket, /* operate on this */
|
int Curl_nonblock(int socket, /* operate on this */
|
||||||
int nonblock /* TRUE or FALSE */);
|
int nonblock /* TRUE or FALSE */);
|
||||||
|
|
||||||
|
CURLcode Curl_is_connected(struct connectdata *conn,
|
||||||
|
int sockfd,
|
||||||
|
bool *connected);
|
||||||
|
|
||||||
CURLcode Curl_connecthost(struct connectdata *conn,
|
CURLcode Curl_connecthost(struct connectdata *conn,
|
||||||
Curl_addrinfo *host, /* connect to this */
|
Curl_addrinfo *host, /* connect to this */
|
||||||
int port, /* connect to this port number */
|
int port, /* connect to this port number */
|
||||||
int *sockconn, /* not set if error is returned */
|
int *sockconn, /* not set if error is returned */
|
||||||
Curl_ipconnect **addr /* the one we used */
|
Curl_ipconnect **addr, /* the one we used */
|
||||||
); /* index we used */
|
bool *connected /* truly connected? */
|
||||||
|
);
|
||||||
#endif
|
#endif
|
||||||
|
|
282
lib/ftp.c
282
lib/ftp.c
|
@ -387,8 +387,10 @@ int Curl_GetFTPResponse(char *buf,
|
||||||
return nread; /* total amount of bytes read */
|
return nread; /* total amount of bytes read */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ftp_connect() should do everything that is to be considered a part
|
/*
|
||||||
of the connection phase. */
|
* Curl_ftp_connect() should do everything that is to be considered a part of
|
||||||
|
* the connection phase.
|
||||||
|
*/
|
||||||
CURLcode Curl_ftp_connect(struct connectdata *conn)
|
CURLcode Curl_ftp_connect(struct connectdata *conn)
|
||||||
{
|
{
|
||||||
/* this is FTP and no proxy */
|
/* this is FTP and no proxy */
|
||||||
|
@ -1321,7 +1323,8 @@ CURLcode ftp_use_port(struct connectdata *conn)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static
|
static
|
||||||
CURLcode ftp_use_pasv(struct connectdata *conn)
|
CURLcode ftp_use_pasv(struct connectdata *conn,
|
||||||
|
bool *connected)
|
||||||
{
|
{
|
||||||
struct SessionHandle *data = conn->data;
|
struct SessionHandle *data = conn->data;
|
||||||
ssize_t nread;
|
ssize_t nread;
|
||||||
|
@ -1473,7 +1476,14 @@ CURLcode ftp_use_pasv(struct connectdata *conn)
|
||||||
addr,
|
addr,
|
||||||
connectport,
|
connectport,
|
||||||
&conn->secondarysocket,
|
&conn->secondarysocket,
|
||||||
&conninfo);
|
&conninfo,
|
||||||
|
connected);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When this is used from the multi interface, this might've returned with
|
||||||
|
* the 'connected' set to FALSE and thus we are now awaiting a non-blocking
|
||||||
|
* connect to connect and we should not be "hanging" here waiting.
|
||||||
|
*/
|
||||||
|
|
||||||
if((CURLE_OK == result) &&
|
if((CURLE_OK == result) &&
|
||||||
data->set.verbose)
|
data->set.verbose)
|
||||||
|
@ -1494,127 +1504,24 @@ CURLcode ftp_use_pasv(struct connectdata *conn)
|
||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
/*
|
||||||
|
* Curl_ftp_nextconnect()
|
||||||
*
|
*
|
||||||
* ftp_perform()
|
* This function shall be called when the second FTP connection has been
|
||||||
*
|
* established and is confirmed connected.
|
||||||
* This is the actual DO function for FTP. Get a file/directory according to
|
|
||||||
* the options previously setup.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static
|
CURLcode Curl_ftp_nextconnect(struct connectdata *conn)
|
||||||
CURLcode ftp_perform(struct connectdata *conn)
|
|
||||||
{
|
{
|
||||||
/* this is FTP and no proxy */
|
|
||||||
ssize_t nread;
|
|
||||||
CURLcode result=CURLE_OK;
|
|
||||||
struct SessionHandle *data=conn->data;
|
struct SessionHandle *data=conn->data;
|
||||||
char *buf = data->state.buffer; /* this is our buffer */
|
char *buf = data->state.buffer; /* this is our buffer */
|
||||||
|
CURLcode result;
|
||||||
|
ssize_t nread;
|
||||||
|
int ftpcode; /* for ftp status */
|
||||||
|
|
||||||
/* the ftp struct is already inited in ftp_connect() */
|
/* the ftp struct is already inited in ftp_connect() */
|
||||||
struct FTP *ftp = conn->proto.ftp;
|
struct FTP *ftp = conn->proto.ftp;
|
||||||
|
|
||||||
long *bytecountp = ftp->bytecountp;
|
long *bytecountp = ftp->bytecountp;
|
||||||
int ftpcode; /* for ftp status */
|
|
||||||
|
|
||||||
/* Send any QUOTE strings? */
|
|
||||||
if(data->set.quote) {
|
|
||||||
if ((result = ftp_sendquote(conn, data->set.quote)) != CURLE_OK)
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This is a re-used connection. Since we change directory to where the
|
|
||||||
transfer is taking place, we must now get back to the original dir
|
|
||||||
where we ended up after login: */
|
|
||||||
if (conn->bits.reuse) {
|
|
||||||
if ((result = ftp_cwd(conn, ftp->entrypath)) != CURLE_OK)
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* change directory first! */
|
|
||||||
if(ftp->dir && ftp->dir[0]) {
|
|
||||||
if ((result = ftp_cwd(conn, ftp->dir)) != CURLE_OK)
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Requested time of file? */
|
|
||||||
if(data->set.get_filetime && ftp->file) {
|
|
||||||
result = ftp_getfiletime(conn, ftp->file);
|
|
||||||
if(result)
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If we have selected NOBODY and HEADER, it means that we only want file
|
|
||||||
information. Which in FTP can't be much more than the file size and
|
|
||||||
date. */
|
|
||||||
if(data->set.no_body && data->set.include_header && ftp->file) {
|
|
||||||
/* The SIZE command is _not_ RFC 959 specified, and therefor many servers
|
|
||||||
may not support it! It is however the only way we have to get a file's
|
|
||||||
size! */
|
|
||||||
ssize_t filesize;
|
|
||||||
|
|
||||||
ftp->no_transfer = TRUE; /* this means no actual transfer is made */
|
|
||||||
|
|
||||||
/* Some servers return different sizes for different modes, and thus we
|
|
||||||
must set the proper type before we check the size */
|
|
||||||
result = ftp_transfertype(conn, data->set.ftp_ascii);
|
|
||||||
if(result)
|
|
||||||
return result;
|
|
||||||
|
|
||||||
/* failing to get size is not a serious error */
|
|
||||||
result = ftp_getsize(conn, ftp->file, &filesize);
|
|
||||||
|
|
||||||
if(CURLE_OK == result) {
|
|
||||||
sprintf(buf, "Content-Length: %d\r\n", filesize);
|
|
||||||
result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
|
|
||||||
if(result)
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If we asked for a time of the file and we actually got one as
|
|
||||||
well, we "emulate" a HTTP-style header in our output. */
|
|
||||||
|
|
||||||
#ifdef HAVE_STRFTIME
|
|
||||||
if(data->set.get_filetime && data->info.filetime) {
|
|
||||||
struct tm *tm;
|
|
||||||
#ifdef HAVE_LOCALTIME_R
|
|
||||||
struct tm buffer;
|
|
||||||
tm = (struct tm *)localtime_r(&data->info.filetime, &buffer);
|
|
||||||
#else
|
|
||||||
tm = localtime((unsigned long *)&data->info.filetime);
|
|
||||||
#endif
|
|
||||||
/* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
|
|
||||||
strftime(buf, BUFSIZE-1, "Last-Modified: %a, %d %b %Y %H:%M:%S %Z\r\n",
|
|
||||||
tm);
|
|
||||||
result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
|
|
||||||
if(result)
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return CURLE_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(data->set.no_body)
|
|
||||||
/* doesn't really transfer any data */
|
|
||||||
ftp->no_transfer = TRUE;
|
|
||||||
/* Get us a second connection up and connected */
|
|
||||||
else if(data->set.ftp_use_port) {
|
|
||||||
/* We have chosen to use the PORT command */
|
|
||||||
result = ftp_use_port(conn);
|
|
||||||
if(CURLE_OK == result)
|
|
||||||
/* we have the data connection ready */
|
|
||||||
infof(data, "Connected the data stream with PORT!\n");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* We have chosen (this is default) to use the PASV command */
|
|
||||||
result = ftp_use_pasv(conn);
|
|
||||||
if(CURLE_OK == result)
|
|
||||||
infof(data, "Connected the data stream with PASV!\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(result)
|
|
||||||
return result;
|
|
||||||
|
|
||||||
if(data->set.upload) {
|
if(data->set.upload) {
|
||||||
|
|
||||||
|
@ -1991,6 +1898,128 @@ CURLcode ftp_perform(struct connectdata *conn)
|
||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
*
|
||||||
|
* ftp_perform()
|
||||||
|
*
|
||||||
|
* This is the actual DO function for FTP. Get a file/directory according to
|
||||||
|
* the options previously setup.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static
|
||||||
|
CURLcode ftp_perform(struct connectdata *conn,
|
||||||
|
bool *connected) /* for the TCP connect status after
|
||||||
|
PASV / PORT */
|
||||||
|
{
|
||||||
|
/* this is FTP and no proxy */
|
||||||
|
CURLcode result=CURLE_OK;
|
||||||
|
struct SessionHandle *data=conn->data;
|
||||||
|
char *buf = data->state.buffer; /* this is our buffer */
|
||||||
|
|
||||||
|
/* the ftp struct is already inited in ftp_connect() */
|
||||||
|
struct FTP *ftp = conn->proto.ftp;
|
||||||
|
|
||||||
|
/* Send any QUOTE strings? */
|
||||||
|
if(data->set.quote) {
|
||||||
|
if ((result = ftp_sendquote(conn, data->set.quote)) != CURLE_OK)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This is a re-used connection. Since we change directory to where the
|
||||||
|
transfer is taking place, we must now get back to the original dir
|
||||||
|
where we ended up after login: */
|
||||||
|
if (conn->bits.reuse) {
|
||||||
|
if ((result = ftp_cwd(conn, ftp->entrypath)) != CURLE_OK)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* change directory first! */
|
||||||
|
if(ftp->dir && ftp->dir[0]) {
|
||||||
|
if ((result = ftp_cwd(conn, ftp->dir)) != CURLE_OK)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Requested time of file? */
|
||||||
|
if(data->set.get_filetime && ftp->file) {
|
||||||
|
result = ftp_getfiletime(conn, ftp->file);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we have selected NOBODY and HEADER, it means that we only want file
|
||||||
|
information. Which in FTP can't be much more than the file size and
|
||||||
|
date. */
|
||||||
|
if(data->set.no_body && data->set.include_header && ftp->file) {
|
||||||
|
/* The SIZE command is _not_ RFC 959 specified, and therefor many servers
|
||||||
|
may not support it! It is however the only way we have to get a file's
|
||||||
|
size! */
|
||||||
|
ssize_t filesize;
|
||||||
|
|
||||||
|
ftp->no_transfer = TRUE; /* this means no actual transfer is made */
|
||||||
|
|
||||||
|
/* Some servers return different sizes for different modes, and thus we
|
||||||
|
must set the proper type before we check the size */
|
||||||
|
result = ftp_transfertype(conn, data->set.ftp_ascii);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
/* failing to get size is not a serious error */
|
||||||
|
result = ftp_getsize(conn, ftp->file, &filesize);
|
||||||
|
|
||||||
|
if(CURLE_OK == result) {
|
||||||
|
sprintf(buf, "Content-Length: %d\r\n", filesize);
|
||||||
|
result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we asked for a time of the file and we actually got one as
|
||||||
|
well, we "emulate" a HTTP-style header in our output. */
|
||||||
|
|
||||||
|
#ifdef HAVE_STRFTIME
|
||||||
|
if(data->set.get_filetime && data->info.filetime) {
|
||||||
|
struct tm *tm;
|
||||||
|
#ifdef HAVE_LOCALTIME_R
|
||||||
|
struct tm buffer;
|
||||||
|
tm = (struct tm *)localtime_r(&data->info.filetime, &buffer);
|
||||||
|
#else
|
||||||
|
tm = localtime((unsigned long *)&data->info.filetime);
|
||||||
|
#endif
|
||||||
|
/* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
|
||||||
|
strftime(buf, BUFSIZE-1, "Last-Modified: %a, %d %b %Y %H:%M:%S %Z\r\n",
|
||||||
|
tm);
|
||||||
|
result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
|
||||||
|
if(result)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(data->set.no_body)
|
||||||
|
/* doesn't really transfer any data */
|
||||||
|
ftp->no_transfer = TRUE;
|
||||||
|
/* Get us a second connection up and connected */
|
||||||
|
else if(data->set.ftp_use_port) {
|
||||||
|
/* We have chosen to use the PORT command */
|
||||||
|
result = ftp_use_port(conn);
|
||||||
|
if(CURLE_OK == result) {
|
||||||
|
/* we have the data connection ready */
|
||||||
|
infof(data, "Ordered connect of the data stream with PORT!\n");
|
||||||
|
*connected = TRUE; /* mark us "still connected" */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* We have chosen (this is default) to use the PASV command */
|
||||||
|
result = ftp_use_pasv(conn, connected);
|
||||||
|
if(connected)
|
||||||
|
infof(data, "Connected the data stream with PASV!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
*
|
*
|
||||||
* Curl_ftp()
|
* Curl_ftp()
|
||||||
|
@ -2003,6 +2032,7 @@ CURLcode ftp_perform(struct connectdata *conn)
|
||||||
CURLcode Curl_ftp(struct connectdata *conn)
|
CURLcode Curl_ftp(struct connectdata *conn)
|
||||||
{
|
{
|
||||||
CURLcode retcode;
|
CURLcode retcode;
|
||||||
|
bool connected;
|
||||||
|
|
||||||
struct SessionHandle *data = conn->data;
|
struct SessionHandle *data = conn->data;
|
||||||
struct FTP *ftp;
|
struct FTP *ftp;
|
||||||
|
@ -2049,15 +2079,15 @@ CURLcode Curl_ftp(struct connectdata *conn)
|
||||||
else
|
else
|
||||||
ftp->dir = NULL;
|
ftp->dir = NULL;
|
||||||
|
|
||||||
retcode = ftp_perform(conn);
|
retcode = ftp_perform(conn, &connected);
|
||||||
|
|
||||||
/* clean up here, success or error doesn't matter */
|
if(CURLE_OK == retcode) {
|
||||||
if(ftp->file)
|
if(connected)
|
||||||
free(ftp->file);
|
retcode = Curl_ftp_nextconnect(conn);
|
||||||
if(ftp->dir)
|
else
|
||||||
free(ftp->dir);
|
/* since we didn't connect now, we want do_more to get called */
|
||||||
|
conn->do_more = TRUE;
|
||||||
ftp->file = ftp->dir = NULL; /* zero */
|
}
|
||||||
|
|
||||||
return retcode;
|
return retcode;
|
||||||
}
|
}
|
||||||
|
@ -2128,6 +2158,12 @@ CURLcode Curl_ftp_disconnect(struct connectdata *conn)
|
||||||
free(ftp->entrypath);
|
free(ftp->entrypath);
|
||||||
if(ftp->cache)
|
if(ftp->cache)
|
||||||
free(ftp->cache);
|
free(ftp->cache);
|
||||||
|
if(ftp->file)
|
||||||
|
free(ftp->file);
|
||||||
|
if(ftp->dir)
|
||||||
|
free(ftp->dir);
|
||||||
|
|
||||||
|
ftp->file = ftp->dir = NULL; /* zero */
|
||||||
}
|
}
|
||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
|
|
10
lib/ftp.h
10
lib/ftp.h
|
@ -1,6 +1,5 @@
|
||||||
#ifndef __FTP_H
|
#ifndef __FTP_H
|
||||||
#define __FTP_H
|
#define __FTP_H
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* _ _ ____ _
|
* _ _ ____ _
|
||||||
* Project ___| | | | _ \| |
|
* Project ___| | | | _ \| |
|
||||||
|
@ -24,22 +23,15 @@
|
||||||
* $Id$
|
* $Id$
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
/* MN 06/07/02 */
|
|
||||||
#ifndef CURL_DISABLE_FTP
|
#ifndef CURL_DISABLE_FTP
|
||||||
|
|
||||||
CURLcode Curl_ftp(struct connectdata *conn);
|
CURLcode Curl_ftp(struct connectdata *conn);
|
||||||
CURLcode Curl_ftp_done(struct connectdata *conn);
|
CURLcode Curl_ftp_done(struct connectdata *conn);
|
||||||
CURLcode Curl_ftp_connect(struct connectdata *conn);
|
CURLcode Curl_ftp_connect(struct connectdata *conn);
|
||||||
CURLcode Curl_ftp_disconnect(struct connectdata *conn);
|
CURLcode Curl_ftp_disconnect(struct connectdata *conn);
|
||||||
|
|
||||||
CURLcode Curl_ftpsendf(struct connectdata *, const char *fmt, ...);
|
CURLcode Curl_ftpsendf(struct connectdata *, const char *fmt, ...);
|
||||||
|
|
||||||
/* The kerberos stuff needs this: */
|
|
||||||
int Curl_GetFTPResponse(char *buf, struct connectdata *conn,
|
int Curl_GetFTPResponse(char *buf, struct connectdata *conn,
|
||||||
int *ftpcode);
|
int *ftpcode);
|
||||||
|
CURLcode Curl_ftp_nextconnect(struct connectdata *conn);
|
||||||
/* MN 06/07/02 */
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
111
lib/multi.c
111
lib/multi.c
|
@ -29,6 +29,7 @@
|
||||||
#include "urldata.h"
|
#include "urldata.h"
|
||||||
#include "transfer.h"
|
#include "transfer.h"
|
||||||
#include "url.h"
|
#include "url.h"
|
||||||
|
#include "connect.h"
|
||||||
|
|
||||||
/* The last #include file should be: */
|
/* The last #include file should be: */
|
||||||
#ifdef MALLOCDEBUG
|
#ifdef MALLOCDEBUG
|
||||||
|
@ -43,11 +44,13 @@ struct Curl_message {
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
CURLM_STATE_INIT,
|
CURLM_STATE_INIT,
|
||||||
CURLM_STATE_CONNECT,
|
CURLM_STATE_CONNECT, /* connect has been sent off */
|
||||||
CURLM_STATE_DO,
|
CURLM_STATE_WAITCONNECT, /* we're awaiting the connect to finalize */
|
||||||
CURLM_STATE_PERFORM,
|
CURLM_STATE_DO, /* send off the request (part 1) */
|
||||||
CURLM_STATE_DONE,
|
CURLM_STATE_DO_MORE, /* send off the request (part 2) */
|
||||||
CURLM_STATE_COMPLETED,
|
CURLM_STATE_PERFORM, /* transfer data */
|
||||||
|
CURLM_STATE_DONE, /* post data transfer operation */
|
||||||
|
CURLM_STATE_COMPLETED, /* operation complete */
|
||||||
|
|
||||||
CURLM_STATE_LAST /* not a true state, never use this */
|
CURLM_STATE_LAST /* not a true state, never use this */
|
||||||
} CURLMstate;
|
} CURLMstate;
|
||||||
|
@ -224,6 +227,32 @@ CURLMcode curl_multi_fdset(CURLM *multi_handle,
|
||||||
switch(easy->state) {
|
switch(easy->state) {
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
case CURLM_STATE_WAITCONNECT:
|
||||||
|
case CURLM_STATE_DO_MORE:
|
||||||
|
{
|
||||||
|
/* when we're waiting for a connect, we wait for the socket to
|
||||||
|
become writable */
|
||||||
|
struct connectdata *conn = easy->easy_conn;
|
||||||
|
int sockfd;
|
||||||
|
|
||||||
|
if(CURLM_STATE_WAITCONNECT == easy->state) {
|
||||||
|
sockfd = conn->firstsocket;
|
||||||
|
FD_SET(sockfd, write_fd_set);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* When in DO_MORE state, we could be either waiting for us
|
||||||
|
to connect to a remote site, or we could wait for that site
|
||||||
|
to connect to us. It makes a difference in the way: if we
|
||||||
|
connect to the site we wait for the socket to become writable, if
|
||||||
|
the site connects to us we wait for it to become readable */
|
||||||
|
sockfd = conn->secondarysocket;
|
||||||
|
FD_SET(sockfd, write_fd_set);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(sockfd > *max_fd)
|
||||||
|
*max_fd = sockfd;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case CURLM_STATE_PERFORM:
|
case CURLM_STATE_PERFORM:
|
||||||
/* This should have a set of file descriptors for us to set. */
|
/* This should have a set of file descriptors for us to set. */
|
||||||
/* after the transfer is done, go DONE */
|
/* after the transfer is done, go DONE */
|
||||||
|
@ -251,6 +280,7 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
|
||||||
bool done;
|
bool done;
|
||||||
CURLMcode result=CURLM_OK;
|
CURLMcode result=CURLM_OK;
|
||||||
struct Curl_message *msg = NULL;
|
struct Curl_message *msg = NULL;
|
||||||
|
bool connected;
|
||||||
|
|
||||||
*running_handles = 0; /* bump this once for every living handle */
|
*running_handles = 0; /* bump this once for every living handle */
|
||||||
|
|
||||||
|
@ -259,6 +289,12 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
|
||||||
|
|
||||||
easy=multi->easy.next;
|
easy=multi->easy.next;
|
||||||
while(easy) {
|
while(easy) {
|
||||||
|
|
||||||
|
#ifdef MALLOCDEBUG
|
||||||
|
fprintf(stderr, "HANDLE %p: State: %x\n",
|
||||||
|
(char *)easy, easy->state);
|
||||||
|
#endif
|
||||||
|
|
||||||
switch(easy->state) {
|
switch(easy->state) {
|
||||||
case CURLM_STATE_INIT:
|
case CURLM_STATE_INIT:
|
||||||
/* init this transfer. */
|
/* init this transfer. */
|
||||||
|
@ -287,23 +323,80 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
|
||||||
/* Connect. We get a connection identifier filled in. */
|
/* Connect. We get a connection identifier filled in. */
|
||||||
easy->result = Curl_connect(easy->easy_handle, &easy->easy_conn);
|
easy->result = Curl_connect(easy->easy_handle, &easy->easy_conn);
|
||||||
|
|
||||||
/* after connect, go DO */
|
/* after the connect has been sent off, go WAITCONNECT */
|
||||||
if(CURLE_OK == easy->result) {
|
if(CURLE_OK == easy->result) {
|
||||||
easy->state = CURLM_STATE_DO;
|
easy->state = CURLM_STATE_WAITCONNECT;
|
||||||
result = CURLM_CALL_MULTI_PERFORM;
|
result = CURLM_CALL_MULTI_PERFORM;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case CURLM_STATE_WAITCONNECT:
|
||||||
|
{
|
||||||
|
bool connected;
|
||||||
|
easy->result = Curl_is_connected(easy->easy_conn,
|
||||||
|
easy->easy_conn->firstsocket,
|
||||||
|
&connected);
|
||||||
|
if(connected)
|
||||||
|
easy->result = Curl_protocol_connect(easy->easy_conn, NULL);
|
||||||
|
|
||||||
|
if(CURLE_OK != easy->result)
|
||||||
|
/* failure detected */
|
||||||
|
break;
|
||||||
|
|
||||||
|
if(connected) {
|
||||||
|
/* after the connect has completed, go DO */
|
||||||
|
easy->state = CURLM_STATE_DO;
|
||||||
|
result = CURLM_CALL_MULTI_PERFORM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case CURLM_STATE_DO:
|
case CURLM_STATE_DO:
|
||||||
/* Do the fetch or put request */
|
/* Do the fetch or put request */
|
||||||
easy->result = Curl_do(&easy->easy_conn);
|
easy->result = Curl_do(&easy->easy_conn);
|
||||||
/* after do, go PERFORM */
|
|
||||||
if(CURLE_OK == easy->result) {
|
if(CURLE_OK == easy->result) {
|
||||||
if(CURLE_OK == Curl_readwrite_init(easy->easy_conn)) {
|
|
||||||
|
/* after do, go PERFORM... or DO_MORE */
|
||||||
|
if(easy->easy_conn->do_more) {
|
||||||
|
/* we're supposed to do more, but we need to sit down, relax
|
||||||
|
and wait a little while first */
|
||||||
|
easy->state = CURLM_STATE_DO_MORE;
|
||||||
|
result = CURLM_OK;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* we're done with the DO, now PERFORM */
|
||||||
|
easy->result = Curl_readwrite_init(easy->easy_conn);
|
||||||
|
if(CURLE_OK == easy->result) {
|
||||||
|
easy->state = CURLM_STATE_PERFORM;
|
||||||
|
result = CURLM_CALL_MULTI_PERFORM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CURLM_STATE_DO_MORE:
|
||||||
|
/*
|
||||||
|
* First, check if we really are ready to do more.
|
||||||
|
*/
|
||||||
|
easy->result = Curl_is_connected(easy->easy_conn,
|
||||||
|
easy->easy_conn->secondarysocket,
|
||||||
|
&connected);
|
||||||
|
if(connected) {
|
||||||
|
/*
|
||||||
|
* When we are connected, DO MORE and then go PERFORM
|
||||||
|
*/
|
||||||
|
easy->result = Curl_do_more(easy->easy_conn);
|
||||||
|
|
||||||
|
if(CURLE_OK == easy->result)
|
||||||
|
easy->result = Curl_readwrite_init(easy->easy_conn);
|
||||||
|
|
||||||
|
if(CURLE_OK == easy->result) {
|
||||||
easy->state = CURLM_STATE_PERFORM;
|
easy->state = CURLM_STATE_PERFORM;
|
||||||
result = CURLM_CALL_MULTI_PERFORM;
|
result = CURLM_CALL_MULTI_PERFORM;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CURLM_STATE_PERFORM:
|
case CURLM_STATE_PERFORM:
|
||||||
/* read/write data if it is ready to do so */
|
/* read/write data if it is ready to do so */
|
||||||
easy->result = Curl_readwrite(easy->easy_conn, &done);
|
easy->result = Curl_readwrite(easy->easy_conn, &done);
|
||||||
|
|
85
lib/url.c
85
lib/url.c
|
@ -1307,7 +1307,8 @@ ConnectionStore(struct SessionHandle *data,
|
||||||
}
|
}
|
||||||
|
|
||||||
static CURLcode ConnectPlease(struct connectdata *conn,
|
static CURLcode ConnectPlease(struct connectdata *conn,
|
||||||
Curl_addrinfo *hostaddr)
|
Curl_addrinfo *hostaddr,
|
||||||
|
bool *connected)
|
||||||
{
|
{
|
||||||
CURLcode result;
|
CURLcode result;
|
||||||
Curl_ipconnect *addr;
|
Curl_ipconnect *addr;
|
||||||
|
@ -1319,7 +1320,8 @@ static CURLcode ConnectPlease(struct connectdata *conn,
|
||||||
hostaddr,
|
hostaddr,
|
||||||
conn->port,
|
conn->port,
|
||||||
&conn->firstsocket,
|
&conn->firstsocket,
|
||||||
&addr);
|
&addr,
|
||||||
|
connected);
|
||||||
if(CURLE_OK == result) {
|
if(CURLE_OK == result) {
|
||||||
/* All is cool, then we store the current information from the hostaddr
|
/* All is cool, then we store the current information from the hostaddr
|
||||||
struct to the serv_addr, as it might be needed later. The address
|
struct to the serv_addr, as it might be needed later. The address
|
||||||
|
@ -1374,7 +1376,7 @@ static void verboseconnect(struct connectdata *conn,
|
||||||
struct in_addr in;
|
struct in_addr in;
|
||||||
(void) memcpy(&in.s_addr, &conn->serv_addr.sin_addr, sizeof (in.s_addr));
|
(void) memcpy(&in.s_addr, &conn->serv_addr.sin_addr, sizeof (in.s_addr));
|
||||||
infof(data, "Connected to %s (%s) port %d\n",
|
infof(data, "Connected to %s (%s) port %d\n",
|
||||||
hostaddr?hostaddr->h_name:"[re-used]",
|
hostaddr?hostaddr->h_name:"",
|
||||||
#if defined(HAVE_INET_NTOA_R)
|
#if defined(HAVE_INET_NTOA_R)
|
||||||
inet_ntoa_r(in, ntoa_buf, sizeof(ntoa_buf)),
|
inet_ntoa_r(in, ntoa_buf, sizeof(ntoa_buf)),
|
||||||
#else
|
#else
|
||||||
|
@ -1385,6 +1387,42 @@ static void verboseconnect(struct connectdata *conn,
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We have discovered that the TCP connection has been successful, we can now
|
||||||
|
* proceed with some action.
|
||||||
|
*
|
||||||
|
* If we're using the multi interface, this host address pointer is most
|
||||||
|
* likely NULL at this point as we can't keep the resolved info around. This
|
||||||
|
* may call for some reworking, like a reference counter in the struct or
|
||||||
|
* something. The hostaddr is not used for very much though, we have the
|
||||||
|
* 'serv_addr' field in the connectdata struct for most of it.
|
||||||
|
*/
|
||||||
|
CURLcode Curl_protocol_connect(struct connectdata *conn,
|
||||||
|
Curl_addrinfo *hostaddr)
|
||||||
|
{
|
||||||
|
struct SessionHandle *data = conn->data;
|
||||||
|
CURLcode result;
|
||||||
|
|
||||||
|
Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */
|
||||||
|
|
||||||
|
if(data->set.verbose)
|
||||||
|
verboseconnect(conn, hostaddr);
|
||||||
|
|
||||||
|
if(conn->curl_connect) {
|
||||||
|
/* is there a protocol-specific connect() procedure? */
|
||||||
|
|
||||||
|
/* set start time here for timeout purposes in the
|
||||||
|
* connect procedure, it is later set again for the
|
||||||
|
* progress meter purpose */
|
||||||
|
conn->now = Curl_tvnow();
|
||||||
|
|
||||||
|
/* Call the protocol-specific connect function */
|
||||||
|
result = conn->curl_connect(conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result; /* pass back status */
|
||||||
|
}
|
||||||
|
|
||||||
static CURLcode CreateConnection(struct SessionHandle *data,
|
static CURLcode CreateConnection(struct SessionHandle *data,
|
||||||
struct connectdata **in_connect)
|
struct connectdata **in_connect)
|
||||||
{
|
{
|
||||||
|
@ -1780,6 +1818,7 @@ static CURLcode CreateConnection(struct SessionHandle *data,
|
||||||
conn->remote_port = PORT_HTTP;
|
conn->remote_port = PORT_HTTP;
|
||||||
conn->protocol |= PROT_HTTP;
|
conn->protocol |= PROT_HTTP;
|
||||||
conn->curl_do = Curl_http;
|
conn->curl_do = Curl_http;
|
||||||
|
conn->curl_do_more = NULL;
|
||||||
conn->curl_done = Curl_http_done;
|
conn->curl_done = Curl_http_done;
|
||||||
conn->curl_connect = Curl_http_connect;
|
conn->curl_connect = Curl_http_connect;
|
||||||
#else
|
#else
|
||||||
|
@ -1797,6 +1836,7 @@ static CURLcode CreateConnection(struct SessionHandle *data,
|
||||||
conn->protocol |= PROT_HTTP|PROT_HTTPS|PROT_SSL;
|
conn->protocol |= PROT_HTTP|PROT_HTTPS|PROT_SSL;
|
||||||
|
|
||||||
conn->curl_do = Curl_http;
|
conn->curl_do = Curl_http;
|
||||||
|
conn->curl_do_more = NULL;
|
||||||
conn->curl_done = Curl_http_done;
|
conn->curl_done = Curl_http_done;
|
||||||
conn->curl_connect = Curl_http_connect;
|
conn->curl_connect = Curl_http_connect;
|
||||||
|
|
||||||
|
@ -1819,6 +1859,7 @@ static CURLcode CreateConnection(struct SessionHandle *data,
|
||||||
}
|
}
|
||||||
conn->protocol |= PROT_GOPHER;
|
conn->protocol |= PROT_GOPHER;
|
||||||
conn->curl_do = Curl_http;
|
conn->curl_do = Curl_http;
|
||||||
|
conn->curl_do_more = NULL;
|
||||||
conn->curl_done = Curl_http_done;
|
conn->curl_done = Curl_http_done;
|
||||||
#else
|
#else
|
||||||
failf(data, LIBCURL_NAME
|
failf(data, LIBCURL_NAME
|
||||||
|
@ -1867,6 +1908,7 @@ static CURLcode CreateConnection(struct SessionHandle *data,
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
conn->curl_do = Curl_ftp;
|
conn->curl_do = Curl_ftp;
|
||||||
|
conn->curl_do_more = Curl_ftp_nextconnect;
|
||||||
conn->curl_done = Curl_ftp_done;
|
conn->curl_done = Curl_ftp_done;
|
||||||
conn->curl_connect = Curl_ftp_connect;
|
conn->curl_connect = Curl_ftp_connect;
|
||||||
conn->curl_disconnect = Curl_ftp_disconnect;
|
conn->curl_disconnect = Curl_ftp_disconnect;
|
||||||
|
@ -2441,29 +2483,16 @@ static CURLcode CreateConnection(struct SessionHandle *data,
|
||||||
conn->headerbytecount = 0;
|
conn->headerbytecount = 0;
|
||||||
|
|
||||||
if(-1 == conn->firstsocket) {
|
if(-1 == conn->firstsocket) {
|
||||||
|
bool connected;
|
||||||
|
|
||||||
/* Connect only if not already connected! */
|
/* Connect only if not already connected! */
|
||||||
result = ConnectPlease(conn, hostaddr);
|
result = ConnectPlease(conn, hostaddr, &connected);
|
||||||
Curl_pgrsTime(data, TIMER_CONNECT); /* connect done, good or bad */
|
|
||||||
|
if(connected)
|
||||||
|
result = Curl_protocol_connect(conn, hostaddr);
|
||||||
|
|
||||||
if(CURLE_OK != result)
|
if(CURLE_OK != result)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
if(data->set.verbose)
|
|
||||||
verboseconnect(conn, hostaddr);
|
|
||||||
|
|
||||||
if(conn->curl_connect) {
|
|
||||||
/* is there a protocol-specific connect() procedure? */
|
|
||||||
|
|
||||||
/* set start time here for timeout purposes in the
|
|
||||||
* connect procedure, it is later set again for the
|
|
||||||
* progress meter purpose */
|
|
||||||
conn->now = Curl_tvnow();
|
|
||||||
|
|
||||||
/* Call the protocol-specific connect function */
|
|
||||||
result = conn->curl_connect(conn);
|
|
||||||
if(result != CURLE_OK)
|
|
||||||
return result; /* pass back errors */
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Curl_pgrsTime(data, TIMER_CONNECT); /* we're connected already */
|
Curl_pgrsTime(data, TIMER_CONNECT); /* we're connected already */
|
||||||
|
@ -2558,6 +2587,8 @@ CURLcode Curl_do(struct connectdata **connp)
|
||||||
struct connectdata *conn = *connp;
|
struct connectdata *conn = *connp;
|
||||||
struct SessionHandle *data=conn->data;
|
struct SessionHandle *data=conn->data;
|
||||||
|
|
||||||
|
conn->do_more = FALSE; /* by default there's no curl_do_more() to use */
|
||||||
|
|
||||||
if(conn->curl_do) {
|
if(conn->curl_do) {
|
||||||
/* generic protocol-specific function pointer set in curl_connect() */
|
/* generic protocol-specific function pointer set in curl_connect() */
|
||||||
result = conn->curl_do(conn);
|
result = conn->curl_do(conn);
|
||||||
|
@ -2587,6 +2618,16 @@ CURLcode Curl_do(struct connectdata **connp)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CURLcode Curl_do_more(struct connectdata *conn)
|
||||||
|
{
|
||||||
|
CURLcode result=CURLE_OK;
|
||||||
|
|
||||||
|
if(conn->curl_do_more)
|
||||||
|
result = conn->curl_do_more(conn);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* local variables:
|
* local variables:
|
||||||
* eval: (load-file "../curl-mode.el")
|
* eval: (load-file "../curl-mode.el")
|
||||||
|
|
|
@ -32,7 +32,9 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...);
|
||||||
CURLcode Curl_close(struct SessionHandle *data); /* opposite of curl_open() */
|
CURLcode Curl_close(struct SessionHandle *data); /* opposite of curl_open() */
|
||||||
CURLcode Curl_connect(struct SessionHandle *, struct connectdata **);
|
CURLcode Curl_connect(struct SessionHandle *, struct connectdata **);
|
||||||
CURLcode Curl_do(struct connectdata **);
|
CURLcode Curl_do(struct connectdata **);
|
||||||
|
CURLcode Curl_do_more(struct connectdata *);
|
||||||
CURLcode Curl_done(struct connectdata *);
|
CURLcode Curl_done(struct connectdata *);
|
||||||
CURLcode Curl_disconnect(struct connectdata *);
|
CURLcode Curl_disconnect(struct connectdata *);
|
||||||
|
CURLcode Curl_protocol_connect(struct connectdata *conn,
|
||||||
|
Curl_addrinfo *hostaddr);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -328,6 +328,12 @@ struct connectdata {
|
||||||
CURLcode (*curl_do)(struct connectdata *connect);
|
CURLcode (*curl_do)(struct connectdata *connect);
|
||||||
CURLcode (*curl_done)(struct connectdata *connect);
|
CURLcode (*curl_done)(struct connectdata *connect);
|
||||||
|
|
||||||
|
/* If the curl_do() function is better made in two halves, this
|
||||||
|
* curl_do_more() function will be called afterwards, if set. For example
|
||||||
|
* for doing the FTP stuff after the PASV/PORT command.
|
||||||
|
*/
|
||||||
|
CURLcode (*curl_do_more)(struct connectdata *connect);
|
||||||
|
|
||||||
/* This function *MAY* be set to a protocol-dependent function that is run
|
/* This function *MAY* be set to a protocol-dependent function that is run
|
||||||
* after the connect() and everything is done, as a step in the connection.
|
* after the connect() and everything is done, as a step in the connection.
|
||||||
*/
|
*/
|
||||||
|
@ -414,7 +420,10 @@ struct connectdata {
|
||||||
buffer, so the next read should read from where this pointer points to,
|
buffer, so the next read should read from where this pointer points to,
|
||||||
and the 'upload_present' contains the number of bytes available at this
|
and the 'upload_present' contains the number of bytes available at this
|
||||||
position */
|
position */
|
||||||
char *upload_fromhere;
|
char *upload_fromhere;
|
||||||
|
|
||||||
|
bool do_more; /* this is set TRUE if the ->curl_do_more() function is
|
||||||
|
supposed to be called, after ->curl_do() */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in New Issue