summaryrefslogtreecommitdiff
path: root/Utilities/cmcurl/lib/multi.c
diff options
context:
space:
mode:
Diffstat (limited to 'Utilities/cmcurl/lib/multi.c')
-rw-r--r--Utilities/cmcurl/lib/multi.c241
1 files changed, 127 insertions, 114 deletions
diff --git a/Utilities/cmcurl/lib/multi.c b/Utilities/cmcurl/lib/multi.c
index 51acba73ac..b96ee7c7ea 100644
--- a/Utilities/cmcurl/lib/multi.c
+++ b/Utilities/cmcurl/lib/multi.c
@@ -29,6 +29,7 @@
#include "urldata.h"
#include "transfer.h"
#include "url.h"
+#include "cfilters.h"
#include "connect.h"
#include "progress.h"
#include "easyif.h"
@@ -160,7 +161,7 @@ static void mstate(struct Curl_easy *data, CURLMstate state
NULL, /* TUNNELING */
NULL, /* PROTOCONNECT */
NULL, /* PROTOCONNECTING */
- Curl_connect_free, /* DO */
+ NULL, /* DO */
NULL, /* DOING */
NULL, /* DOING_MORE */
before_perform, /* DID */
@@ -709,6 +710,11 @@ static CURLcode multi_done(struct Curl_easy *data,
#endif
) || conn->bits.close
|| (premature && !(conn->handler->flags & PROTOPT_STREAM))) {
+ DEBUGF(infof(data, "multi_done, not re-using connection=%ld, forbid=%d"
+ ", close=%d, premature=%d, stream=%d",
+ conn->connection_id,
+ data->set.reuse_forbid, conn->bits.close, premature,
+ (conn->handler->flags & PROTOPT_STREAM)));
connclose(conn, "disconnecting");
Curl_conncache_remove_conn(data, conn, FALSE);
CONNCACHE_UNLOCK(data);
@@ -948,9 +954,8 @@ void Curl_detach_connection(struct Curl_easy *data)
{
struct connectdata *conn = data->conn;
if(conn) {
- Curl_connect_done(data); /* if mid-CONNECT, shut it down */
+ Curl_conn_detach_data(conn, data);
Curl_llist_remove(&conn->easyq, &data->conn_queue, NULL);
- Curl_ssl_detach_conn(data, conn);
}
data->conn = NULL;
}
@@ -968,53 +973,9 @@ void Curl_attach_connection(struct Curl_easy *data,
data->conn = conn;
Curl_llist_insert_next(&conn->easyq, conn->easyq.tail, data,
&data->conn_queue);
+ Curl_conn_attach_data(conn, data);
if(conn->handler->attach)
conn->handler->attach(data, conn);
- Curl_ssl_associate_conn(data, conn);
-}
-
-static int waitconnect_getsock(struct connectdata *conn,
- curl_socket_t *sock)
-{
- int i;
- int s = 0;
- int rc = 0;
-
-#ifdef USE_SSL
-#ifndef CURL_DISABLE_PROXY
- if(CONNECT_FIRSTSOCKET_PROXY_SSL())
- return Curl_ssl->getsock(conn, sock);
-#endif
-#endif
-
- if(SOCKS_STATE(conn->cnnct.state))
- return Curl_SOCKS_getsock(conn, sock, FIRSTSOCKET);
-
- for(i = 0; i<2; i++) {
- if(conn->tempsock[i] != CURL_SOCKET_BAD) {
- sock[s] = conn->tempsock[i];
- rc |= GETSOCK_WRITESOCK(s);
-#ifdef ENABLE_QUIC
- if(conn->transport == TRNSPRT_QUIC)
- /* when connecting QUIC, we want to read the socket too */
- rc |= GETSOCK_READSOCK(s);
-#endif
- s++;
- }
- }
-
- return rc;
-}
-
-static int waitproxyconnect_getsock(struct connectdata *conn,
- curl_socket_t *sock)
-{
- sock[0] = conn->sock[FIRSTSOCKET];
-
- if(conn->connect_state)
- return Curl_connect_getsock(conn);
-
- return GETSOCK_WRITESOCK(0);
}
static int domore_getsock(struct Curl_easy *data,
@@ -1076,10 +1037,8 @@ static int multi_getsock(struct Curl_easy *data,
return doing_getsock(data, conn, socks);
case MSTATE_TUNNELING:
- return waitproxyconnect_getsock(conn, socks);
-
case MSTATE_CONNECTING:
- return waitconnect_getsock(conn, socks);
+ return Curl_conn_get_select_socks(data, FIRSTSOCKET, socks);
case MSTATE_DOING_MORE:
return domore_getsock(data, conn, socks);
@@ -1737,7 +1696,8 @@ static CURLcode protocol_connect(struct Curl_easy *data,
*protocol_done = FALSE;
- if(conn->bits.tcpconnect[FIRSTSOCKET] && conn->bits.protoconnstart) {
+ if(Curl_conn_is_connected(conn, FIRSTSOCKET)
+ && conn->bits.protoconnstart) {
/* We already are connected, get back. This may happen when the connect
worked fine in the first call, like when we connect to a local server
or proxy. Note that we don't know if the protocol is actually done.
@@ -1751,21 +1711,6 @@ static CURLcode protocol_connect(struct Curl_easy *data,
}
if(!conn->bits.protoconnstart) {
-#ifndef CURL_DISABLE_PROXY
- result = Curl_proxy_connect(data, FIRSTSOCKET);
- if(result)
- return result;
-
- if(CONNECT_FIRSTSOCKET_PROXY_SSL())
- /* wait for HTTPS proxy SSL initialization to complete */
- return CURLE_OK;
-
- if(conn->bits.tunnel_proxy && conn->bits.httpproxy &&
- Curl_connect_ongoing(conn))
- /* when using an HTTP tunnel proxy, await complete tunnel establishment
- before proceeding further. Return CURLE_OK so we'll be called again */
- return CURLE_OK;
-#endif
if(conn->handler->connect_it) {
/* is there a protocol-specific connect() procedure? */
@@ -1785,6 +1730,90 @@ static CURLcode protocol_connect(struct Curl_easy *data,
}
/*
+ * readrewind() rewinds the read stream. This is typically used for HTTP
+ * POST/PUT with multi-pass authentication when a sending was denied and a
+ * resend is necessary.
+ */
+static CURLcode readrewind(struct Curl_easy *data)
+{
+ struct connectdata *conn = data->conn;
+ curl_mimepart *mimepart = &data->set.mimepost;
+ DEBUGASSERT(conn);
+
+ data->state.rewindbeforesend = FALSE; /* we rewind now */
+
+ /* explicitly switch off sending data on this connection now since we are
+ about to restart a new transfer and thus we want to avoid inadvertently
+ sending more data on the existing connection until the next transfer
+ starts */
+ data->req.keepon &= ~KEEP_SEND;
+
+ /* We have sent away data. If not using CURLOPT_POSTFIELDS or
+ CURLOPT_HTTPPOST, call app to rewind
+ */
+ if(conn->handler->protocol & PROTO_FAMILY_HTTP) {
+ struct HTTP *http = data->req.p.http;
+
+ if(http->sendit)
+ mimepart = http->sendit;
+ }
+ if(data->set.postfields ||
+ (data->state.httpreq == HTTPREQ_GET) ||
+ (data->state.httpreq == HTTPREQ_HEAD))
+ ; /* no need to rewind */
+ else if(data->state.httpreq == HTTPREQ_POST_MIME ||
+ data->state.httpreq == HTTPREQ_POST_FORM) {
+ CURLcode result = Curl_mime_rewind(mimepart);
+ if(result) {
+ failf(data, "Cannot rewind mime/post data");
+ return result;
+ }
+ }
+ else {
+ if(data->set.seek_func) {
+ int err;
+
+ Curl_set_in_callback(data, true);
+ err = (data->set.seek_func)(data->set.seek_client, 0, SEEK_SET);
+ Curl_set_in_callback(data, false);
+ if(err) {
+ failf(data, "seek callback returned error %d", (int)err);
+ return CURLE_SEND_FAIL_REWIND;
+ }
+ }
+ else if(data->set.ioctl_func) {
+ curlioerr err;
+
+ Curl_set_in_callback(data, true);
+ err = (data->set.ioctl_func)(data, CURLIOCMD_RESTARTREAD,
+ data->set.ioctl_client);
+ Curl_set_in_callback(data, false);
+ infof(data, "the ioctl callback returned %d", (int)err);
+
+ if(err) {
+ failf(data, "ioctl callback returned error %d", (int)err);
+ return CURLE_SEND_FAIL_REWIND;
+ }
+ }
+ else {
+ /* If no CURLOPT_READFUNCTION is used, we know that we operate on a
+ given FILE * stream and we can actually attempt to rewind that
+ ourselves with fseek() */
+ if(data->state.fread_func == (curl_read_callback)fread) {
+ if(-1 != fseek(data->state.in, 0, SEEK_SET))
+ /* successful rewind */
+ return CURLE_OK;
+ }
+
+ /* no callback set or failure above, makes us fail at once */
+ failf(data, "necessary data rewind wasn't possible");
+ return CURLE_SEND_FAIL_REWIND;
+ }
+ }
+ return CURLE_OK;
+}
+
+/*
* Curl_preconnect() is called immediately before a connect starts. When a
* redirect is followed, this is then called multiple times during a single
* transfer.
@@ -1796,6 +1825,7 @@ CURLcode Curl_preconnect(struct Curl_easy *data)
if(!data->state.buffer)
return CURLE_OUT_OF_MEMORY;
}
+
return CURLE_OK;
}
@@ -1901,7 +1931,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
if(data->set.connecttimeout)
Curl_expire(data, data->set.connecttimeout, EXPIRE_CONNECTTIMEOUT);
- result = Curl_connect(data, &async, &protocol_connected);
+ result = Curl_connect(data, &async, &connected);
if(CURLE_NO_CONNECTION_AVAILABLE == result) {
/* There was no connection available. We will go to the pending
state and wait for an available connection. */
@@ -1929,15 +1959,10 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
WAITDO or DO! */
rc = CURLM_CALL_MULTI_PERFORM;
- if(protocol_connected)
- multistate(data, MSTATE_DO);
+ if(connected)
+ multistate(data, MSTATE_PROTOCONNECT);
else {
-#ifndef CURL_DISABLE_HTTP
- if(Curl_connect_ongoing(data->conn))
- multistate(data, MSTATE_TUNNELING);
- else
-#endif
- multistate(data, MSTATE_CONNECTING);
+ multistate(data, MSTATE_CONNECTING);
}
}
}
@@ -1989,7 +2014,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
if(dns) {
/* Perform the next step in the connection phase, and then move on
to the WAITCONNECT state */
- result = Curl_once_resolved(data, &protocol_connected);
+ result = Curl_once_resolved(data, &connected);
if(result)
/* if Curl_once_resolved() returns failure, the connection struct
@@ -1998,15 +2023,10 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
else {
/* call again please so that we get the next socket setup */
rc = CURLM_CALL_MULTI_PERFORM;
- if(protocol_connected)
- multistate(data, MSTATE_DO);
+ if(connected)
+ multistate(data, MSTATE_PROTOCONNECT);
else {
-#ifndef CURL_DISABLE_HTTP
- if(Curl_connect_ongoing(data->conn))
- multistate(data, MSTATE_TUNNELING);
- else
-#endif
- multistate(data, MSTATE_CONNECTING);
+ multistate(data, MSTATE_CONNECTING);
}
}
}
@@ -2035,16 +2055,9 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
else
#endif
if(!result) {
- if(
-#ifndef CURL_DISABLE_PROXY
- (data->conn->http_proxy.proxytype != CURLPROXY_HTTPS ||
- data->conn->bits.proxy_ssl_connected[FIRSTSOCKET]) &&
-#endif
- Curl_connect_complete(data->conn)) {
- rc = CURLM_CALL_MULTI_PERFORM;
- /* initiate protocol connect phase */
- multistate(data, MSTATE_PROTOCONNECT);
- }
+ rc = CURLM_CALL_MULTI_PERFORM;
+ /* initiate protocol connect phase */
+ multistate(data, MSTATE_PROTOCONNECT);
}
else
stream_error = TRUE;
@@ -2054,27 +2067,10 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
case MSTATE_CONNECTING:
/* awaiting a completion of an asynch TCP connect */
DEBUGASSERT(data->conn);
- result = Curl_is_connected(data, data->conn, FIRSTSOCKET, &connected);
+ result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &connected);
if(connected && !result) {
-#ifndef CURL_DISABLE_HTTP
- if(
-#ifndef CURL_DISABLE_PROXY
- (data->conn->http_proxy.proxytype == CURLPROXY_HTTPS &&
- !data->conn->bits.proxy_ssl_connected[FIRSTSOCKET]) ||
-#endif
- Curl_connect_ongoing(data->conn)) {
- multistate(data, MSTATE_TUNNELING);
- break;
- }
-#endif
rc = CURLM_CALL_MULTI_PERFORM;
-#ifndef CURL_DISABLE_PROXY
- multistate(data,
- data->conn->bits.tunnel_proxy?
- MSTATE_TUNNELING : MSTATE_PROTOCONNECT);
-#else
multistate(data, MSTATE_PROTOCONNECT);
-#endif
}
else if(result) {
/* failure detected */
@@ -2086,7 +2082,19 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
break;
case MSTATE_PROTOCONNECT:
- result = protocol_connect(data, &protocol_connected);
+ if(data->state.rewindbeforesend)
+ result = readrewind(data);
+
+ if(!result && data->conn->bits.reuse) {
+ /* ftp seems to hang when protoconnect on reused connection
+ * since we handle PROTOCONNECT in general inside the filers, it
+ * seems wrong to restart this on a reused connection. */
+ multistate(data, MSTATE_DO);
+ rc = CURLM_CALL_MULTI_PERFORM;
+ break;
+ }
+ if(!result)
+ result = protocol_connect(data, &protocol_connected);
if(!result && !protocol_connected)
/* switch to waiting state */
multistate(data, MSTATE_PROTOCONNECTING);
@@ -2770,6 +2778,11 @@ CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
wakeup_close(multi->wakeup_pair[1]);
#endif
#endif
+
+#ifdef USE_SSL
+ Curl_free_multi_ssl_backend_data(multi->ssl_backend_data);
+#endif
+
free(multi);
return CURLM_OK;