Karl M added the CURLOPT_CONNECT_ONLY and CURLINFO_LASTSOCKET options that
an app can use to let libcurl only connect to a remote host and then extract the socket from libcurl. libcurl will then not attempt to do any transfer at all after the connect is done.
This commit is contained in:
@@ -527,6 +527,8 @@ CURL *curl_easy_duphandle(CURL *incurl)
|
||||
memset(outcurl->state.connects, 0,
|
||||
sizeof(struct connectdata *)*outcurl->state.numconnects);
|
||||
|
||||
outcurl->state.lastconnect = -1;
|
||||
|
||||
outcurl->progress.flags = data->progress.flags;
|
||||
outcurl->progress.callback = data->progress.callback;
|
||||
|
||||
|
||||
@@ -1689,7 +1689,7 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
|
||||
ftp_pasv_verbose(conn, conninfo, newhost, connectport);
|
||||
|
||||
#ifndef CURL_DISABLE_HTTP
|
||||
if(conn->bits.tunnel_proxy) {
|
||||
if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
|
||||
/* FIX: this MUST wait for a proper connect first if 'connected' is
|
||||
* FALSE */
|
||||
|
||||
@@ -2786,7 +2786,7 @@ CURLcode Curl_ftp_connect(struct connectdata *conn,
|
||||
ftp->response_time = 3600; /* set default response time-out */
|
||||
|
||||
#ifndef CURL_DISABLE_HTTP
|
||||
if (conn->bits.tunnel_proxy) {
|
||||
if (conn->bits.tunnel_proxy && conn->bits.httpproxy) {
|
||||
/* BLOCKING */
|
||||
/* We want "seamless" FTP operations through HTTP proxy tunnel */
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
* Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
@@ -187,6 +187,14 @@ CURLcode Curl_getinfo(struct SessionHandle *data, CURLINFO info, ...)
|
||||
case CURLINFO_COOKIELIST:
|
||||
*param_slistp = Curl_cookie_list(data);
|
||||
break;
|
||||
case CURLINFO_LASTSOCKET:
|
||||
if((data->state.lastconnect != -1) &&
|
||||
(data->state.connects[data->state.lastconnect] != NULL))
|
||||
*param_longp = data->state.connects[data->state.lastconnect]->
|
||||
sock[FIRSTSOCKET];
|
||||
else
|
||||
*param_longp = -1;
|
||||
break;
|
||||
default:
|
||||
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
}
|
||||
|
||||
@@ -1361,7 +1361,7 @@ CURLcode Curl_http_connect(struct connectdata *conn, bool *done)
|
||||
* after the connect has occured, can we start talking SSL
|
||||
*/
|
||||
|
||||
if(conn->bits.tunnel_proxy) {
|
||||
if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
|
||||
|
||||
/* either SSL over proxy, or explicitly asked for */
|
||||
result = Curl_proxyCONNECT(conn, FIRSTSOCKET,
|
||||
|
||||
75
lib/multi.c
75
lib/multi.c
@@ -5,7 +5,7 @@
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
* Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
@@ -522,40 +522,49 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
|
||||
break;
|
||||
|
||||
case CURLM_STATE_DO:
|
||||
/* Perform the protocol's DO action */
|
||||
easy->result = Curl_do(&easy->easy_conn, &dophase_done);
|
||||
|
||||
if(CURLE_OK == easy->result) {
|
||||
|
||||
if(!dophase_done) {
|
||||
/* DO was not completed in one function call, we must continue
|
||||
DOING... */
|
||||
multistate(easy, CURLM_STATE_DOING);
|
||||
result = CURLM_OK;
|
||||
}
|
||||
|
||||
/* after DO, go PERFORM... or DO_MORE */
|
||||
else if(easy->easy_conn->bits.do_more) {
|
||||
/* we're supposed to do more, but we need to sit down, relax
|
||||
and wait a little while first */
|
||||
multistate(easy, 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) {
|
||||
multistate(easy, CURLM_STATE_PERFORM);
|
||||
result = CURLM_CALL_MULTI_PERFORM;
|
||||
}
|
||||
}
|
||||
if(easy->easy_handle->set.connect_only) {
|
||||
/* keep connection open for application to use the socket */
|
||||
easy->easy_conn->bits.close = FALSE;
|
||||
multistate(easy, CURLM_STATE_DONE);
|
||||
easy->result = CURLE_OK;
|
||||
result = CURLM_OK;
|
||||
}
|
||||
else {
|
||||
/* failure detected */
|
||||
Curl_posttransfer(easy->easy_handle);
|
||||
Curl_done(&easy->easy_conn, easy->result);
|
||||
Curl_disconnect(easy->easy_conn); /* close the connection */
|
||||
easy->easy_conn = NULL; /* no more connection */
|
||||
/* Perform the protocol's DO action */
|
||||
easy->result = Curl_do(&easy->easy_conn, &dophase_done);
|
||||
|
||||
if(CURLE_OK == easy->result) {
|
||||
|
||||
if(!dophase_done) {
|
||||
/* DO was not completed in one function call, we must continue
|
||||
DOING... */
|
||||
multistate(easy, CURLM_STATE_DOING);
|
||||
result = CURLM_OK;
|
||||
}
|
||||
|
||||
/* after DO, go PERFORM... or DO_MORE */
|
||||
else if(easy->easy_conn->bits.do_more) {
|
||||
/* we're supposed to do more, but we need to sit down, relax
|
||||
and wait a little while first */
|
||||
multistate(easy, 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) {
|
||||
multistate(easy, CURLM_STATE_PERFORM);
|
||||
result = CURLM_CALL_MULTI_PERFORM;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* failure detected */
|
||||
Curl_posttransfer(easy->easy_handle);
|
||||
Curl_done(&easy->easy_conn, easy->result);
|
||||
Curl_disconnect(easy->easy_conn); /* close the connection */
|
||||
easy->easy_conn = NULL; /* no more connection */
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
@@ -2159,6 +2159,12 @@ CURLcode Curl_perform(struct SessionHandle *data)
|
||||
|
||||
if(res == CURLE_OK) {
|
||||
bool do_done;
|
||||
if(data->set.connect_only) {
|
||||
/* keep connection open for application to use the socket */
|
||||
conn->bits.close = FALSE;
|
||||
res = Curl_done(&conn, CURLE_OK);
|
||||
break;
|
||||
}
|
||||
res = Curl_do(&conn, &do_done);
|
||||
|
||||
/* for non 3rd party transfer only */
|
||||
|
||||
25
lib/url.c
25
lib/url.c
@@ -352,6 +352,9 @@ CURLcode Curl_open(struct SessionHandle **curl)
|
||||
memset(data->state.connects, 0,
|
||||
sizeof(struct connectdata *)*data->state.numconnects);
|
||||
|
||||
/* most recent connection is not yet defined */
|
||||
data->state.lastconnect = -1;
|
||||
|
||||
/*
|
||||
* libcurl 7.10 introduced SSL verification *by default*! This needs to be
|
||||
* switched off unless wanted.
|
||||
@@ -432,6 +435,10 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
|
||||
are being removed! */
|
||||
for(i=newconnects; i< data->state.numconnects; i++)
|
||||
Curl_disconnect(data->state.connects[i]);
|
||||
|
||||
/* If the most recent connection is no longer valid, mark it invalid. */
|
||||
if(data->state.lastconnect <= newconnects)
|
||||
data->state.lastconnect = -1;
|
||||
}
|
||||
if(newconnects) {
|
||||
newptr= (struct connectdata **)
|
||||
@@ -453,8 +460,9 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
|
||||
/* zero makes NO cache at all */
|
||||
if(data->state.connects)
|
||||
free(data->state.connects);
|
||||
data->state.connects=NULL;
|
||||
data->state.numconnects=0;
|
||||
data->state.connects = NULL;
|
||||
data->state.numconnects = 0;
|
||||
data->state.lastconnect = -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1471,6 +1479,13 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
|
||||
data->set.ignorecl = va_arg(param, long)?TRUE:FALSE;
|
||||
break;
|
||||
|
||||
case CURLOPT_CONNECT_ONLY:
|
||||
/*
|
||||
* No data transfer, set up connection and let application use the socket
|
||||
*/
|
||||
data->set.connect_only = va_arg(param, long)?TRUE:FALSE;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* unknown tag and its companion, just ignore: */
|
||||
result = CURLE_FAILED_INIT; /* correct this */
|
||||
@@ -3811,10 +3826,14 @@ CURLcode Curl_done(struct connectdata **connp,
|
||||
if(!result && res2)
|
||||
result = res2;
|
||||
}
|
||||
else
|
||||
else {
|
||||
/* remember the most recently used connection */
|
||||
data->state.lastconnect = conn->connectindex;
|
||||
|
||||
infof(data, "Connection #%ld to host %s left intact\n",
|
||||
conn->connectindex,
|
||||
conn->bits.httpproxy?conn->proxy.dispname:conn->host.dispname);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -856,6 +856,7 @@ struct UrlState {
|
||||
set, it holds an allocated connection. */
|
||||
struct connectdata **connects;
|
||||
long numconnects; /* size of the 'connects' array */
|
||||
int lastconnect; /* index of most recent connect or -1 if undefined */
|
||||
|
||||
char *headerbuff; /* allocated buffer to store headers in */
|
||||
size_t headersize; /* size of the allocation */
|
||||
@@ -1083,6 +1084,7 @@ struct UserDefined {
|
||||
bool ignorecl; /* ignore content length */
|
||||
bool ftp_skip_ip; /* skip the IP address the FTP server passes on to
|
||||
us */
|
||||
bool connect_only; /* make connection, let application use the socket */
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user