From 87bcb6f3775a437579c7526d0972c714c2e5d31d Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 11 Feb 2006 22:35:16 +0000 Subject: [PATCH] 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. --- CHANGES | 5 +++ RELEASE-NOTES | 15 ++++--- docs/libcurl/curl_easy_getinfo.3 | 6 +++ docs/libcurl/curl_easy_setopt.3 | 8 ++++ include/curl/curl.h | 7 ++- lib/easy.c | 2 + lib/ftp.c | 4 +- lib/getinfo.c | 10 ++++- lib/http.c | 2 +- lib/multi.c | 75 ++++++++++++++++++-------------- lib/transfer.c | 6 +++ lib/url.c | 25 +++++++++-- lib/urldata.h | 2 + 13 files changed, 119 insertions(+), 48 deletions(-) diff --git a/CHANGES b/CHANGES index 88961d32d..826b02100 100644 --- a/CHANGES +++ b/CHANGES @@ -7,6 +7,11 @@ Changelog Daniel (11 February 2006) +- 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. + - Kent Boortz improved the configure check for GnuTLS to properly set LIBS instead of LDFLAGS. diff --git a/RELEASE-NOTES b/RELEASE-NOTES index d7babaab2..5cd89a464 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -2,21 +2,22 @@ Curl and libcurl 7.15.2 Public curl release number: 92 Releases counted from the very beginning: 119 - Available command line options: 109 - Available curl_easy_setopt() options: 125 + Available command line options: 111 + Available curl_easy_setopt() options: 129 Number of public functions in libcurl: 46 - Amount of public web site mirrors: 30 + Amount of public web site mirrors: 31 Number of known libcurl bindings: 32 Number of contributors: 474 This release includes the following changes: + o CURLOPT_CONNECT_ONLY and CURLINFO_LASTSOCKET added o CURLOPT_LOCALPORT and CURLOPT_LOCALPORTRANGE (--local-port) added o Dropped support for the LPRT ftp command - o Gopher is now officially abandoned as a protocol (lib)curl tries to support. + o Gopher is now officially abandoned as a protocol (lib)curl tries to support o curl_global_init() and curl_global_cleanup() are now using a refcount so that it is now legal to call them multiple times. See updated info for - details. + details This release includes the following bugfixes: @@ -60,7 +61,7 @@ advice from friends like these: Dov Murik, Jean Jacques Drouin, Andres Garcia, Yang Tse, Gisle Vanem, Dan Fandrich, Alexander Lazic, Michael Jahn, Andrew Benham, Bryan Henderson, - David Shaw, Jon Turner, Duane Cathey, Michal Marek, Philippe Vaucher, - Kent Boortz + David Shaw, Jon Turner, Duane Cathey, Michal Marek, Philippe Vaucher, Kent + Boortz, Karl M Thanks! (and sorry if I forgot to mention someone) diff --git a/docs/libcurl/curl_easy_getinfo.3 b/docs/libcurl/curl_easy_getinfo.3 index bc4f2063b..2119ea211 100644 --- a/docs/libcurl/curl_easy_getinfo.3 +++ b/docs/libcurl/curl_easy_getinfo.3 @@ -141,6 +141,12 @@ cookies cURL knows (expired ones, too). Don't forget to cookies (cookies for the handle have not been enabled or simply none have been received) 'struct curl_slist *' will be set to point to NULL. (Added in 7.14.1) +.IP CURLINFO_LASTSOCKET +Pass a pointer to a long to receive the last socket used by this curl +session. If the socket is no longer valid, -1 is returned. When you finish +working with the socket, you must call curl_easy_cleanup() as usual and let +libcurl close the socket and cleanup other resources associated with the +handle. (Added in 7.15.2) .SH TIMES .NF An overview of the six time values available from curl_easy_getinfo() diff --git a/docs/libcurl/curl_easy_setopt.3 b/docs/libcurl/curl_easy_setopt.3 index 25e7e7707..8a152947c 100644 --- a/docs/libcurl/curl_easy_setopt.3 +++ b/docs/libcurl/curl_easy_setopt.3 @@ -1044,6 +1044,14 @@ Resolve to ipv4 addresses. .IP CURL_IPRESOLVE_V6 Resolve to ipv6 addresses. .RE +.SH CURLOPT_CONNECT_ONLY +Pass a long. A non-zero parameter tells the library to perform any required +proxy authentication and connection setup, but no data transfer. + +This option is useful with the \fICURLINFO_LASTSOCKET\fP option to +\fIcurl_easy_getinfo(3)\fP. The library can set up the connection and then the +application can obtain the most recently used socket for special data +transfers. (Added in 7.15.2) .SH SSL and SECURITY OPTIONS .IP CURLOPT_SSLCERT Pass a pointer to a zero terminated string as parameter. The string should be diff --git a/include/curl/curl.h b/include/curl/curl.h index 95c478a07..1ad282df8 100644 --- a/include/curl/curl.h +++ b/include/curl/curl.h @@ -923,6 +923,10 @@ typedef enum { */ CINIT(LOCALPORTRANGE, LONG, 140), + /* no transfer, set up connection and let application use the socket by + extracting it with CURLINFO_LASTSOCKET */ + CINIT(CONNECT_ONLY, LONG, 141), + CURLOPT_LASTENTRY /* the last unused */ } CURLoption; @@ -1277,9 +1281,10 @@ typedef enum { CURLINFO_NUM_CONNECTS = CURLINFO_LONG + 26, CURLINFO_SSL_ENGINES = CURLINFO_SLIST + 27, CURLINFO_COOKIELIST = CURLINFO_SLIST + 28, + CURLINFO_LASTSOCKET = CURLINFO_LONG + 29, /* Fill in new entries below here! */ - CURLINFO_LASTONE = 28 + CURLINFO_LASTONE = 29 } CURLINFO; /* CURLINFO_RESPONSE_CODE is the new name for the option previously known as diff --git a/lib/easy.c b/lib/easy.c index 2de18037f..d86b755fb 100644 --- a/lib/easy.c +++ b/lib/easy.c @@ -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; diff --git a/lib/ftp.c b/lib/ftp.c index ecb717696..02732f452 100644 --- a/lib/ftp.c +++ b/lib/ftp.c @@ -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 */ diff --git a/lib/getinfo.c b/lib/getinfo.c index 47828212b..2a4c3aac4 100644 --- a/lib/getinfo.c +++ b/lib/getinfo.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2005, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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; } diff --git a/lib/http.c b/lib/http.c index 39e2940ff..e15054f57 100644 --- a/lib/http.c +++ b/lib/http.c @@ -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, diff --git a/lib/multi.c b/lib/multi.c index a60e1f5a9..a7d1988d6 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2005, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2006, Daniel Stenberg, , 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; diff --git a/lib/transfer.c b/lib/transfer.c index 50a8bae98..2fbc2c615 100644 --- a/lib/transfer.c +++ b/lib/transfer.c @@ -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 */ diff --git a/lib/url.c b/lib/url.c index f17213f79..49e7c1cbf 100644 --- a/lib/url.c +++ b/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; } diff --git a/lib/urldata.h b/lib/urldata.h index 96494a7ce..a3802b7c3 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -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 */ }; /*