summaryrefslogtreecommitdiff
path: root/lib/url.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/url.c')
-rw-r--r--lib/url.c97
1 files changed, 59 insertions, 38 deletions
diff --git a/lib/url.c b/lib/url.c
index ab56760de..7512bb4d9 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -364,6 +364,9 @@ CURLcode Curl_close(struct Curl_easy **datap)
Curl_expire_clear(data); /* shut off timers */
+ /* Detach connection if any is left. This should not be normal, but can be
+ the case for example with CONNECT_ONLY + recv/send (test 556) */
+ Curl_detach_connnection(data);
m = data->multi;
if(m)
/* This handle is still part of a multi handle, take care of this first
@@ -709,11 +712,11 @@ static void conn_reset_all_postponed_data(struct connectdata *conn)
#endif /* ! USE_RECV_BEFORE_SEND_WORKAROUND */
-static void conn_shutdown(struct connectdata *conn)
+static void conn_shutdown(struct Curl_easy *data, struct connectdata *conn)
{
DEBUGASSERT(conn);
- infof(conn->data, "Closing connection %ld\n", conn->connection_id);
- DEBUGASSERT(conn->data);
+ DEBUGASSERT(data);
+ infof(data, "Closing connection %ld\n", conn->connection_id);
/* possible left-overs from the async name resolvers */
Curl_resolver_cancel(conn);
@@ -725,13 +728,13 @@ static void conn_shutdown(struct connectdata *conn)
/* close possibly still open sockets */
if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET])
- Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
+ Curl_closesocket(data, conn, conn->sock[SECONDARYSOCKET]);
if(CURL_SOCKET_BAD != conn->sock[FIRSTSOCKET])
- Curl_closesocket(conn, conn->sock[FIRSTSOCKET]);
+ Curl_closesocket(data, conn, conn->sock[FIRSTSOCKET]);
if(CURL_SOCKET_BAD != conn->tempsock[0])
- Curl_closesocket(conn, conn->tempsock[0]);
+ Curl_closesocket(data, conn, conn->tempsock[0]);
if(CURL_SOCKET_BAD != conn->tempsock[1])
- Curl_closesocket(conn, conn->tempsock[1]);
+ Curl_closesocket(data, conn, conn->tempsock[1]);
}
static void conn_free(struct connectdata *conn)
@@ -834,11 +837,18 @@ CURLcode Curl_disconnect(struct Curl_easy *data,
/* treat the connection as dead in CONNECT_ONLY situations */
dead_connection = TRUE;
- if(conn->handler->disconnect)
+ if(conn->handler->disconnect) {
+ /* During disconnect, the connection and the transfer is already
+ disassociated, but the SSH backends (and more?) still need the
+ transfer's connection pointer to identify the used connection */
+ data->conn = conn;
+
/* This is set if protocol-specific cleanups should be made */
- conn->handler->disconnect(conn, dead_connection);
+ conn->handler->disconnect(data, conn, dead_connection);
+ data->conn = NULL; /* forget it again */
+ }
- conn_shutdown(conn);
+ conn_shutdown(data, conn);
conn_free(conn);
return CURLE_OK;
}
@@ -961,23 +971,29 @@ static bool conn_maxage(struct Curl_easy *data,
static bool extract_if_dead(struct connectdata *conn,
struct Curl_easy *data)
{
- if(!CONN_INUSE(conn) && !conn->data) {
+ if(!CONN_INUSE(conn)) {
/* The check for a dead socket makes sense only if the connection isn't in
use */
bool dead;
struct curltime now = Curl_now();
if(conn_maxage(data, conn, now)) {
+ /* avoid check if already too old */
dead = TRUE;
}
else if(conn->handler->connection_check) {
/* The protocol has a special method for checking the state of the
connection. Use it to check if the connection is dead. */
unsigned int state;
- struct Curl_easy *olddata = conn->data;
- conn->data = data; /* use this transfer for now */
- state = conn->handler->connection_check(conn, CONNCHECK_ISDEAD);
- conn->data = olddata;
+
+ /* briefly attach the connection to this transfer for the purpose of
+ checking it */
+ Curl_attach_connnection(data, conn);
+ conn->data = data; /* find the way back if necessary */
+ state = conn->handler->connection_check(data, conn, CONNCHECK_ISDEAD);
dead = (state & CONNRESULT_DEAD);
+ /* detach the connection again */
+ Curl_detach_connnection(data);
+ conn->data = NULL; /* clear it again */
}
else {
/* Use the general method for determining the death of a connection */
@@ -1002,10 +1018,11 @@ struct prunedead {
* Wrapper to use extract_if_dead() function in Curl_conncache_foreach()
*
*/
-static int call_extract_if_dead(struct connectdata *conn, void *param)
+static int call_extract_if_dead(struct Curl_easy *data,
+ struct connectdata *conn, void *param)
{
struct prunedead *p = (struct prunedead *)param;
- if(extract_if_dead(conn, p->data)) {
+ if(extract_if_dead(conn, data)) {
/* stop the iteration here, pass back the connection that was extracted */
p->extracted = conn;
return 1;
@@ -1015,14 +1032,16 @@ static int call_extract_if_dead(struct connectdata *conn, void *param)
/*
* This function scans the connection cache for half-open/dead connections,
- * closes and removes them.
- * The cleanup is done at most once per second.
+ * closes and removes them. The cleanup is done at most once per second.
+ *
+ * When called, this transfer has no connection attached.
*/
static void prune_dead_connections(struct Curl_easy *data)
{
struct curltime now = Curl_now();
timediff_t elapsed;
+ DEBUGASSERT(!data->conn); /* no connection */
CONNCACHE_LOCK(data);
elapsed =
Curl_timediff(now, data->state.conn_cache->last_cleanup);
@@ -1463,9 +1482,10 @@ ConnectionExists(struct Curl_easy *data,
* verboseconnect() displays verbose information after a connect
*/
#ifndef CURL_DISABLE_VERBOSE_STRINGS
-void Curl_verboseconnect(struct connectdata *conn)
+void Curl_verboseconnect(struct Curl_easy *data,
+ struct connectdata *conn)
{
- if(conn->data->set.verbose)
+ if(data->set.verbose)
infof(conn->data, "Connected to %s (%s) port %ld (#%ld)\n",
#ifndef CURL_DISABLE_PROXY
conn->bits.socksproxy ? conn->socks_proxy.host.dispname :
@@ -2084,7 +2104,8 @@ static CURLcode setup_range(struct Curl_easy *data)
*
* This MUST get called after proxy magic has been figured out.
*/
-static CURLcode setup_connection_internals(struct connectdata *conn)
+static CURLcode setup_connection_internals(struct Curl_easy *data,
+ struct connectdata *conn)
{
const struct Curl_handler *p;
CURLcode result;
@@ -2093,7 +2114,7 @@ static CURLcode setup_connection_internals(struct connectdata *conn)
p = conn->handler;
if(p->setup_connection) {
- result = (*p->setup_connection)(conn);
+ result = (*p->setup_connection)(data, conn);
if(result)
return result;
@@ -3337,7 +3358,8 @@ static CURLcode resolve_server(struct Curl_easy *data,
* previously existing one. All relevant data is copied over and old_conn is
* ready for freeing once this function returns.
*/
-static void reuse_conn(struct connectdata *old_conn,
+static void reuse_conn(struct Curl_easy *data,
+ struct connectdata *old_conn,
struct connectdata *conn)
{
#ifndef CURL_DISABLE_PROXY
@@ -3352,7 +3374,7 @@ static void reuse_conn(struct connectdata *old_conn,
allocated in vain and is targeted for destruction */
Curl_free_primary_ssl_config(&old_conn->ssl_config);
- conn->data = old_conn->data;
+ conn->data = data;
/* get the user+password information from the old_conn struct since it may
* be new for this request even when we re-use an existing connection */
@@ -3406,7 +3428,7 @@ static void reuse_conn(struct connectdata *old_conn,
old_conn->hostname_resolve = NULL;
/* persist connection info in session handle */
- Curl_persistconninfo(conn);
+ Curl_persistconninfo(data, conn);
conn_reset_all_postponed_data(old_conn); /* free buffers */
@@ -3600,7 +3622,7 @@ static CURLcode create_conn(struct Curl_easy *data,
* Setup internals depending on protocol. Needs to be done after
* we figured out what/if proxy to use.
*************************************************************/
- result = setup_connection_internals(conn);
+ result = setup_connection_internals(data, conn);
if(result)
goto out;
@@ -3620,8 +3642,8 @@ static CURLcode create_conn(struct Curl_easy *data,
/* this is supposed to be the connect function so we better at least check
that the file is present here! */
DEBUGASSERT(conn->handler->connect_it);
- Curl_persistconninfo(conn);
- result = conn->handler->connect_it(conn, &done);
+ Curl_persistconninfo(data, conn);
+ result = conn->handler->connect_it(data, &done);
/* Setup a "faked" transfer that'll do nothing */
if(!result) {
@@ -3639,7 +3661,7 @@ static CURLcode create_conn(struct Curl_easy *data,
if(result) {
DEBUGASSERT(conn->handler->done);
/* we ignore the return code for the protocol-specific DONE */
- (void)conn->handler->done(conn, result, FALSE);
+ (void)conn->handler->done(data, result, FALSE);
goto out;
}
Curl_setup_transfer(data, -1, -1, FALSE, -1);
@@ -3752,12 +3774,11 @@ static CURLcode create_conn(struct Curl_easy *data,
if(reuse) {
/*
- * We already have a connection for this, we got the former connection
- * in the conn_temp variable and thus we need to cleanup the one we
- * just allocated before we can move along and use the previously
- * existing one.
+ * We already have a connection for this, we got the former connection in
+ * the conn_temp variable and thus we need to cleanup the one we just
+ * allocated before we can move along and use the previously existing one.
*/
- reuse_conn(conn, conn_temp);
+ reuse_conn(data, conn, conn_temp);
#ifdef USE_SSL
free(conn->ssl_extra);
#endif
@@ -3958,7 +3979,7 @@ CURLcode Curl_setup_conn(struct connectdata *conn,
if(CURL_SOCKET_BAD == conn->sock[FIRSTSOCKET]) {
conn->bits.tcpconnect[FIRSTSOCKET] = FALSE;
- result = Curl_connecthost(conn, conn->dns_entry);
+ result = Curl_connecthost(data, conn, conn->dns_entry);
if(result)
return result;
}
@@ -3969,8 +3990,8 @@ CURLcode Curl_setup_conn(struct connectdata *conn,
Curl_pgrsTime(data, TIMER_APPCONNECT); /* we're connected already */
conn->bits.tcpconnect[FIRSTSOCKET] = TRUE;
*protocol_done = TRUE;
- Curl_updateconninfo(conn, conn->sock[FIRSTSOCKET]);
- Curl_verboseconnect(conn);
+ Curl_updateconninfo(data, conn, conn->sock[FIRSTSOCKET]);
+ Curl_verboseconnect(data, conn);
}
conn->now = Curl_now(); /* time this *after* the connect is done, we set