}
}
-static void capsule_cf_close(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- struct cf_capsule_ctx *ctx = cf->ctx;
-
- CURL_TRC_CF(data, cf, "close");
- cf->connected = FALSE;
- if(ctx) {
- Curl_bufq_reset(&ctx->recvbuf);
- curlx_safefree(ctx->pending);
- ctx->pending_len = 0;
- ctx->pending_offset = 0;
- ctx->pending_payload = 0;
- }
- if(cf->next)
- cf->next->cft->do_close(cf->next, data);
-}
-
static CURLcode capsule_cf_connect(struct Curl_cfilter *cf,
struct Curl_easy *data,
bool *done)
0,
capsule_cf_destroy,
capsule_cf_connect,
- capsule_cf_close,
Curl_cf_def_shutdown,
Curl_cf_def_adjust_pollset,
capsule_cf_data_pending,
cf_dns_ctx_destroy(data, ctx);
}
-static void cf_dns_close(struct Curl_cfilter *cf, struct Curl_easy *data)
-{
- cf->connected = FALSE;
- if(cf->next)
- cf->next->cft->do_close(cf->next, data);
-}
-
static CURLcode cf_dns_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps)
CURL_LOG_LVL_NONE,
cf_dns_destroy,
cf_dns_connect,
- cf_dns_close,
Curl_cf_def_shutdown,
cf_dns_adjust_pollset,
Curl_cf_def_data_pending,
*/
CURL_TRC_CF(data, cf, "CONNECT need to close+open");
infof(data, "Connect me again please");
- Curl_conn_cf_close(cf, data);
- result = Curl_conn_cf_connect(cf->next, data, &done);
- return result;
+ return CURLE_AGAIN;
}
else {
/* staying on this connection, reset state */
curlx_safefree(cf->ctx);
}
-static void cf_h1_proxy_close(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- struct cf_h1_proxy_ctx *pctx = cf->ctx;
- CURL_TRC_CF(data, cf, "close");
- cf->connected = FALSE;
- if(pctx && pctx->ts)
- h1_tunnel_go_state(cf, pctx->ts, H1_TUNNEL_INIT, data);
- if(cf->next)
- cf->next->cft->do_close(cf->next, data);
-}
-
static CURLcode cf_h1_proxy_query(struct Curl_cfilter *cf,
struct Curl_easy *data,
int query, int *pres1, void *pres2)
0,
cf_h1_proxy_destroy,
cf_h1_proxy_connect,
- cf_h1_proxy_close,
Curl_cf_def_shutdown,
cf_h1_proxy_adjust_pollset,
cf_h1_proxy_data_pending,
return result;
}
-static void cf_h2_proxy_close(struct Curl_cfilter *cf, struct Curl_easy *data)
-{
- struct cf_h2_proxy_ctx *ctx = cf->ctx;
-
- if(ctx) {
- struct cf_call_data save;
-
- CF_DATA_SAVE(save, cf, data);
- cf_h2_proxy_ctx_clear(ctx);
- CF_DATA_RESTORE(cf, save);
- }
- if(cf->next)
- cf->next->cft->do_close(cf->next, data);
-}
-
static void cf_h2_proxy_destroy(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
CURL_LOG_LVL_NONE,
cf_h2_proxy_destroy,
cf_h2_proxy_connect,
- cf_h2_proxy_close,
cf_h2_proxy_shutdown,
cf_h2_proxy_adjust_pollset,
cf_h2_proxy_data_pending,
}
}
-static void cf_h3_proxy_close(struct Curl_cfilter *cf, struct Curl_easy *data)
-{
- struct cf_h3_proxy_ctx *ctx = cf->ctx;
-
- if(ctx) {
- if(ctx->ngtcp2_ctx) {
- cf_ngtcp2_proxy_close(cf, data);
- cf_ngtcp2_proxy_ctx_free(ctx->ngtcp2_ctx);
- ctx->ngtcp2_ctx = NULL;
- }
- cf_h3_proxy_ctx_clear(ctx);
- cf->connected = FALSE;
- }
-
- if(cf->next)
- cf->next->cft->do_close(cf->next, data);
-}
-
static CURLcode cf_h3_proxy_shutdown(struct Curl_cfilter *cf,
struct Curl_easy *data, bool *done)
{
CURL_LOG_LVL_NONE,
cf_h3_proxy_destroy,
cf_h3_proxy_connect,
- cf_h3_proxy_close,
cf_h3_proxy_shutdown,
cf_h3_proxy_adjust_pollset,
cf_h3_proxy_data_pending,
struct dynbuf data_out;
};
-static void cf_haproxy_ctx_reset(struct cf_haproxy_ctx *ctx)
-{
- DEBUGASSERT(ctx);
- ctx->state = HAPROXY_INIT;
- curlx_dyn_reset(&ctx->data_out);
-}
-
static void cf_haproxy_ctx_free(struct cf_haproxy_ctx *ctx)
{
if(ctx) {
cf_haproxy_ctx_free(cf->ctx);
}
-static void cf_haproxy_close(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- CURL_TRC_CF(data, cf, "close");
- cf->connected = FALSE;
- cf_haproxy_ctx_reset(cf->ctx);
- if(cf->next)
- cf->next->cft->do_close(cf->next, data);
-}
-
static CURLcode cf_haproxy_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps)
0,
cf_haproxy_destroy,
cf_haproxy_connect,
- cf_haproxy_close,
Curl_cf_def_shutdown,
cf_haproxy_adjust_pollset,
Curl_cf_def_data_pending,
struct Curl_easy *data)
{
if(b->cf) {
- Curl_conn_cf_close(b->cf, data);
Curl_conn_cf_discard_chain(&b->cf, data);
b->cf = NULL;
}
return result;
}
-static void cf_hc_close(struct Curl_cfilter *cf, struct Curl_easy *data)
-{
- CURL_TRC_CF(data, cf, "close");
- cf_hc_ctx_close(data, cf->ctx);
- cf->connected = FALSE;
-
- if(cf->next) {
- cf->next->cft->do_close(cf->next, data);
- Curl_conn_cf_discard_chain(&cf->next, data);
- }
-}
-
static void cf_hc_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
{
struct cf_hc_ctx *ctx = cf->ctx;
CURL_LOG_LVL_NONE,
cf_hc_destroy,
cf_hc_connect,
- cf_hc_close,
cf_hc_shutdown,
cf_hc_adjust_pollset,
cf_hc_data_pending,
return result;
}
-static void cf_ip_happy_close(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- struct cf_ip_happy_ctx *ctx = cf->ctx;
-
- CURL_TRC_CF(data, cf, "close");
- cf_ip_happy_ctx_clear(cf, data);
- cf->connected = FALSE;
- ctx->state = SCFST_INIT;
-
- if(cf->next) {
- cf->next->cft->do_close(cf->next, data);
- Curl_conn_cf_discard_chain(&cf->next, data);
- }
-}
-
static bool cf_ip_happy_data_pending(struct Curl_cfilter *cf,
const struct Curl_easy *data)
{
CURL_LOG_LVL_NONE,
cf_ip_happy_destroy,
cf_ip_happy_connect,
- cf_ip_happy_close,
cf_ip_happy_shutdown,
cf_ip_happy_adjust_pollset,
cf_ip_happy_data_pending,
return CURLE_OK;
}
-static void cf_socket_close(struct Curl_cfilter *cf, struct Curl_easy *data)
-{
- struct cf_socket_ctx *ctx = cf->ctx;
-
- if(ctx && ctx->sock != CURL_SOCKET_BAD) {
- CURL_TRC_CF(data, cf, "cf_socket_close, fd=%" FMT_SOCKET_T, ctx->sock);
- if(ctx->sock == cf->conn->sock[cf->sockindex])
- cf->conn->sock[cf->sockindex] = CURL_SOCKET_BAD;
- socket_close(data, cf->conn, !ctx->accepted, ctx->sock);
- ctx->sock = CURL_SOCKET_BAD;
- ctx->active = FALSE;
- memset(&ctx->started_at, 0, sizeof(ctx->started_at));
- memset(&ctx->connected_at, 0, sizeof(ctx->connected_at));
- }
-
- cf->connected = FALSE;
-}
-
static CURLcode cf_socket_shutdown(struct Curl_cfilter *cf,
struct Curl_easy *data,
bool *done)
{
struct cf_socket_ctx *ctx = cf->ctx;
- cf_socket_close(cf, data);
CURL_TRC_CF(data, cf, "destroy");
- curlx_free(ctx);
- cf->ctx = NULL;
+ if(ctx) {
+ if(ctx->sock != CURL_SOCKET_BAD) {
+ CURL_TRC_CF(data, cf, "cf_socket_close, fd=%" FMT_SOCKET_T, ctx->sock);
+ if(ctx->sock == cf->conn->sock[cf->sockindex])
+ cf->conn->sock[cf->sockindex] = CURL_SOCKET_BAD;
+ socket_close(data, cf->conn, !ctx->accepted, ctx->sock);
+ }
+ curlx_free(ctx);
+ }
}
static void set_local_ip(struct Curl_cfilter *cf,
CURL_LOG_LVL_NONE,
cf_socket_destroy,
cf_tcp_connect,
- cf_socket_close,
cf_socket_shutdown,
cf_socket_adjust_pollset,
Curl_cf_def_data_pending,
CURL_LOG_LVL_NONE,
cf_socket_destroy,
cf_udp_connect,
- cf_socket_close,
cf_socket_shutdown,
cf_socket_adjust_pollset,
Curl_cf_def_data_pending,
CURL_LOG_LVL_NONE,
cf_socket_destroy,
cf_tcp_connect,
- cf_socket_close,
cf_socket_shutdown,
cf_socket_adjust_pollset,
Curl_cf_def_data_pending,
CURL_LOG_LVL_NONE,
cf_socket_destroy,
cf_tcp_accept_connect,
- cf_socket_close,
cf_socket_shutdown,
cf_socket_adjust_pollset,
Curl_cf_def_data_pending,
#include "select.h"
#include "curlx/strparse.h"
-#ifdef UNITTESTS
-/* @unittest 2600 */
-UNITTEST void cf_def_close(struct Curl_cfilter *cf, struct Curl_easy *data);
-UNITTEST void cf_def_close(struct Curl_cfilter *cf, struct Curl_easy *data)
-{
- cf->connected = FALSE;
- if(cf->next)
- cf->next->cft->do_close(cf->next, data);
-}
-#endif
-
CURLcode Curl_cf_def_shutdown(struct Curl_cfilter *cf,
struct Curl_easy *data, bool *done)
{
void Curl_conn_cf_discard_all(struct Curl_easy *data,
struct connectdata *conn, int sockindex)
{
+ struct curltime *pt = &conn->shutdown.start[sockindex];
+ memset(pt, 0, sizeof(*pt));
Curl_conn_cf_discard_chain(&conn->cfilter[sockindex], data);
}
-void Curl_conn_close(struct Curl_easy *data, int sockindex)
-{
- struct Curl_cfilter *cf;
-
- DEBUGASSERT(data->conn);
- /* it is valid to call that without filters being present */
- cf = data->conn->cfilter[sockindex];
- if(cf) {
- cf->cft->do_close(cf, data);
- }
- Curl_shutdown_clear(data, sockindex);
-}
-
CURLcode Curl_conn_shutdown(struct Curl_easy *data, int sockindex, bool *done)
{
struct Curl_cfilter *cf;
return CURLE_FAILED_INIT;
}
-void Curl_conn_cf_close(struct Curl_cfilter *cf, struct Curl_easy *data)
-{
- if(cf)
- cf->cft->do_close(cf, data);
-}
-
CURLcode Curl_conn_cf_send(struct Curl_cfilter *cf, struct Curl_easy *data,
const uint8_t *buf, size_t len, bool eos,
size_t *pnwritten)
typedef void Curl_cft_destroy_this(struct Curl_cfilter *cf,
struct Curl_easy *data);
-/* Callback to close the connection immediately. */
-typedef void Curl_cft_close(struct Curl_cfilter *cf,
- struct Curl_easy *data);
-
/* Callback to close the connection filter gracefully, non-blocking.
* Implementations MUST NOT chain calls to cf->next.
*/
int log_level; /* log level for such filters */
Curl_cft_destroy_this *destroy; /* destroy resources of this cf */
Curl_cft_connect *do_connect; /* establish connection */
- Curl_cft_close *do_close; /* close conn */
Curl_cft_shutdown *do_shutdown; /* shutdown conn */
Curl_cft_adjust_pollset *adjust_pollset; /* adjust transfer poll set */
Curl_cft_data_pending *has_data_pending; /* conn has data pending */
CURLcode Curl_conn_cf_connect(struct Curl_cfilter *cf,
struct Curl_easy *data,
bool *done);
-void Curl_conn_cf_close(struct Curl_cfilter *cf, struct Curl_easy *data);
CURLcode Curl_conn_cf_send(struct Curl_cfilter *cf, struct Curl_easy *data,
const uint8_t *buf, size_t len, bool eos,
size_t *pnwritten);
const char *Curl_conn_get_alpn_negotiated(struct Curl_easy *data,
struct connectdata *conn);
-/**
- * Close the filter chain at `sockindex` for connection `data->conn`.
- * Filters remain in place and may be connected again afterwards.
- */
-void Curl_conn_close(struct Curl_easy *data, int sockindex);
-
/**
* Shutdown the connection at `sockindex` non-blocking, using timeout
* from `data->set.shutdowntimeout`, default DEFAULT_SHUTDOWN_TIMEOUT_MS.
cf_setup_state state;
int ssl_mode;
uint8_t transport;
+ uint8_t retry_count;
};
#ifndef CURL_DISABLE_PROXY
return result;
}
-static CURLcode cf_setup_connect(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- bool *done)
+static CURLcode cf_setup_connect_steps(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool *done)
{
struct cf_setup_ctx *ctx = cf->ctx;
CURLcode result = CURLE_OK;
return CURLE_OK;
}
-static void cf_setup_close(struct Curl_cfilter *cf,
- struct Curl_easy *data)
+static CURLcode cf_setup_connect(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool *done)
{
struct cf_setup_ctx *ctx = cf->ctx;
+ CURLcode result;
- CURL_TRC_CF(data, cf, "close");
- cf->connected = FALSE;
- ctx->state = CF_SETUP_INIT;
+ /* In some situations, a server/proxy may close the connection and
+ * we need to connect again (HTTP/1.x proxy auth, for example).
+ * We used to close the filters and reuse them for another attempt,
+ * however that complicates filter code and it is simpler to tear them
+ * all down and start over. */
+retry:
+ result = cf_setup_connect_steps(cf, data, done);
- if(cf->next) {
- cf->next->cft->do_close(cf->next, data);
+ if(result == CURLE_AGAIN) {
+ ++ctx->retry_count;
+ if(ctx->retry_count > 5) /* arbitrary limit, better just timeout? */
+ return CURLE_COULDNT_CONNECT;
+
+ CURL_TRC_CF(data, cf, "retrying connect, %d. time", ctx->retry_count);
Curl_conn_cf_discard_chain(&cf->next, data);
+ ctx->state = CF_SETUP_INIT;
+ goto retry;
}
+ return result;
}
static void cf_setup_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
CURL_LOG_LVL_NONE,
cf_setup_destroy,
cf_setup_connect,
- cf_setup_close,
Curl_cf_def_shutdown,
Curl_cf_def_adjust_pollset,
Curl_cf_def_data_pending,
CURL_TRC_M(admin, "[SHUTDOWN] %sclosing connection #%" FMT_OFF_T,
conn->bits.shutdown_filters ? "" : "force ",
conn->connection_id);
- Curl_conn_close(admin, SECONDARYSOCKET);
- Curl_conn_close(admin, FIRSTSOCKET);
+ Curl_conn_cf_discard_all(admin, conn, SECONDARYSOCKET);
+ Curl_conn_cf_discard_all(admin, conn, FIRSTSOCKET);
Curl_detach_connection(admin);
if(data->multi)
{
(void)ftpc;
CURL_TRC_FTP(data, "[%s] closing DATA connection", FTP_CSTATE(ftpc));
- Curl_conn_close(data, SECONDARYSOCKET);
Curl_conn_cf_discard_all(data, data->conn, SECONDARYSOCKET);
}
static void cf_h2_ctx_free(struct cf_h2_ctx *ctx)
{
if(ctx && ctx->initialized) {
+ if(ctx->h2)
+ nghttp2_session_del(ctx->h2);
Curl_bufq_free(&ctx->inbufq);
Curl_bufq_free(&ctx->outbufq);
Curl_bufcp_free(&ctx->stream_bufcp);
curlx_free(ctx);
}
-static void cf_h2_ctx_close(struct cf_h2_ctx *ctx)
-{
- if(ctx->h2) {
- nghttp2_session_del(ctx->h2);
- ctx->h2 = NULL;
- }
-}
-
static uint32_t cf_h2_initial_win_size(struct Curl_easy *data)
{
#if NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE
return result;
}
-static void cf_h2_close(struct Curl_cfilter *cf, struct Curl_easy *data)
-{
- struct cf_h2_ctx *ctx = cf->ctx;
-
- if(ctx) {
- struct cf_call_data save;
-
- CF_DATA_SAVE(save, cf, data);
- cf_h2_ctx_close(ctx);
- CF_DATA_RESTORE(cf, save);
- cf->connected = FALSE;
- }
- if(cf->next)
- cf->next->cft->do_close(cf->next, data);
-}
-
static void cf_h2_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
{
struct cf_h2_ctx *ctx = cf->ctx;
CURL_LOG_LVL_NONE,
cf_h2_destroy,
cf_h2_connect,
- cf_h2_close,
cf_h2_shutdown,
cf_h2_adjust_pollset,
cf_h2_data_pending,
}
}
-static void http_proxy_cf_close(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- CURL_TRC_CF(data, cf, "close");
- cf->connected = FALSE;
- if(cf->next)
- cf->next->cft->do_close(cf->next, data);
-}
-
struct Curl_cftype Curl_cft_http_proxy = {
"HTTP-PROXY",
CF_TYPE_IP_CONNECT | CF_TYPE_PROXY | CF_TYPE_SETUP,
0,
http_proxy_cf_destroy,
http_proxy_cf_connect,
- http_proxy_cf_close,
Curl_cf_def_shutdown,
Curl_cf_def_adjust_pollset,
Curl_cf_def_data_pending,
return result;
}
-static void socks_proxy_cf_close(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- cf->connected = FALSE;
- if(cf->next)
- cf->next->cft->do_close(cf->next, data);
-}
-
static void socks_proxy_cf_destroy(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
0,
socks_proxy_cf_destroy,
socks_proxy_cf_connect,
- socks_proxy_cf_close,
Curl_cf_def_shutdown,
socks_cf_adjust_pollset,
Curl_cf_def_data_pending,
cf_ngtcp2_shutdown(cf, data, &done);
}
-static void cf_ngtcp2_close(struct Curl_cfilter *cf, struct Curl_easy *data)
+static void cf_ngtcp2_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
{
struct cf_ngtcp2_ctx *ctx = cf->ctx;
- struct cf_call_data save;
-
- CF_DATA_SAVE(save, cf, data);
- if(ctx && ctx->qconn) {
- cf_ngtcp2_conn_close(cf, data);
- cf_ngtcp2_ctx_close(ctx);
- CURL_TRC_CF(data, cf, "close");
- }
- cf->connected = FALSE;
- CF_DATA_RESTORE(cf, save);
-}
-static void cf_ngtcp2_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
-{
CURL_TRC_CF(data, cf, "destroy");
- if(cf->ctx) {
- cf_ngtcp2_close(cf, data);
+ if(ctx) {
+ if(ctx->qconn) {
+ struct cf_call_data save;
+ CF_DATA_SAVE(save, cf, data);
+ cf_ngtcp2_conn_close(cf, data);
+ cf_ngtcp2_ctx_close(ctx);
+ CF_DATA_RESTORE(cf, save);
+ }
cf_ngtcp2_ctx_free(cf->ctx);
cf->ctx = NULL;
}
0,
cf_ngtcp2_destroy,
cf_ngtcp2_connect,
- cf_ngtcp2_close,
cf_ngtcp2_shutdown,
cf_ngtcp2_adjust_pollset,
Curl_cf_def_data_pending,
return result;
}
-static void cf_quiche_close(struct Curl_cfilter *cf, struct Curl_easy *data)
-{
- if(cf->ctx) {
- bool done;
- (void)cf_quiche_shutdown(cf, data, &done);
- cf_quiche_ctx_close(cf->ctx);
- cf->connected = FALSE;
- }
-}
-
static void cf_quiche_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
{
(void)data;
0,
cf_quiche_destroy,
cf_quiche_connect,
- cf_quiche_close,
cf_quiche_shutdown,
cf_quiche_adjust_pollset,
Curl_cf_def_data_pending,
cf->ctx = NULL;
}
-static void ssl_cf_close(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- struct cf_call_data save;
-
- CF_DATA_SAVE(save, cf, data);
- cf_close(cf, data);
- if(cf->next)
- cf->next->cft->do_close(cf->next, data);
- CF_DATA_RESTORE(cf, save);
-}
-
static CURLcode ssl_cf_connect(struct Curl_cfilter *cf,
struct Curl_easy *data,
bool *done)
CURL_LOG_LVL_NONE,
ssl_cf_destroy,
ssl_cf_connect,
- ssl_cf_close,
ssl_cf_shutdown,
ssl_cf_adjust_pollset,
ssl_cf_data_pending,
CURL_LOG_LVL_NONE,
ssl_cf_destroy,
ssl_cf_connect,
- ssl_cf_close,
ssl_cf_shutdown,
ssl_cf_adjust_pollset,
ssl_cf_data_pending,
CURL_LOG_LVL_NONE,
cf_test_destroy,
cf_test_connect,
- cf_def_close,
Curl_cf_def_shutdown,
cf_test_adjust_pollset,
Curl_cf_def_data_pending,