diff --git a/lib/cf-h1-proxy.c b/lib/cf-h1-proxy.c index 7e87af4f67..e2f86fc1f2 100644 --- a/lib/cf-h1-proxy.c +++ b/lib/cf-h1-proxy.c @@ -598,7 +598,7 @@ static CURLcode H1_CONNECT(struct Curl_cfilter *cf, infof(data, "Connect me again please"); Curl_conn_cf_close(cf, data); connkeep(conn, "HTTP proxy CONNECT"); - result = Curl_conn_cf_connect(cf->next, data, FALSE, &done); + result = Curl_conn_cf_connect(cf->next, data, &done); goto out; } else { @@ -638,7 +638,7 @@ out: static CURLcode cf_h1_proxy_connect(struct Curl_cfilter *cf, struct Curl_easy *data, - bool blocking, bool *done) + bool *done) { CURLcode result; struct h1_tunnel_state *ts = cf->ctx; @@ -649,7 +649,7 @@ static CURLcode cf_h1_proxy_connect(struct Curl_cfilter *cf, } CURL_TRC_CF(data, cf, "connect"); - result = cf->next->cft->do_connect(cf->next, data, blocking, done); + result = cf->next->cft->do_connect(cf->next, data, done); if(result || !*done) return result; diff --git a/lib/cf-h2-proxy.c b/lib/cf-h2-proxy.c index ec7d4d53e6..fbff37992e 100644 --- a/lib/cf-h2-proxy.c +++ b/lib/cf-h2-proxy.c @@ -1090,7 +1090,7 @@ out: static CURLcode cf_h2_proxy_connect(struct Curl_cfilter *cf, struct Curl_easy *data, - bool blocking, bool *done) + bool *done) { struct cf_h2_proxy_ctx *ctx = cf->ctx; CURLcode result = CURLE_OK; @@ -1105,7 +1105,7 @@ static CURLcode cf_h2_proxy_connect(struct Curl_cfilter *cf, /* Connect the lower filters first */ if(!cf->next->connected) { - result = Curl_conn_cf_connect(cf->next, data, blocking, done); + result = Curl_conn_cf_connect(cf->next, data, done); if(result || !*done) return result; } diff --git a/lib/cf-haproxy.c b/lib/cf-haproxy.c index ae2402f224..10d54f4456 100644 --- a/lib/cf-haproxy.c +++ b/lib/cf-haproxy.c @@ -105,7 +105,7 @@ static CURLcode cf_haproxy_date_out_set(struct Curl_cfilter*cf, static CURLcode cf_haproxy_connect(struct Curl_cfilter *cf, struct Curl_easy *data, - bool blocking, bool *done) + bool *done) { struct cf_haproxy_ctx *ctx = cf->ctx; CURLcode result; @@ -117,7 +117,7 @@ static CURLcode cf_haproxy_connect(struct Curl_cfilter *cf, return CURLE_OK; } - result = cf->next->cft->do_connect(cf->next, data, blocking, done); + result = cf->next->cft->do_connect(cf->next, data, done); if(result || !*done) return result; diff --git a/lib/cf-https-connect.c b/lib/cf-https-connect.c index 2a645d415b..812d8b1d91 100644 --- a/lib/cf-https-connect.c +++ b/lib/cf-https-connect.c @@ -175,7 +175,7 @@ static CURLcode cf_hc_baller_connect(struct cf_hc_baller *b, struct Curl_cfilter *save = cf->next; cf->next = b->cf; - b->result = Curl_conn_cf_connect(cf->next, data, FALSE, done); + b->result = Curl_conn_cf_connect(cf->next, data, done); b->cf = cf->next; /* it might mutate */ cf->next = save; return b->result; @@ -291,14 +291,13 @@ static bool time_to_start_next(struct Curl_cfilter *cf, static CURLcode cf_hc_connect(struct Curl_cfilter *cf, struct Curl_easy *data, - bool blocking, bool *done) + bool *done) { struct cf_hc_ctx *ctx = cf->ctx; struct curltime now; CURLcode result = CURLE_OK; size_t i, failed_ballers; - (void)blocking; if(cf->connected) { *done = TRUE; return CURLE_OK; diff --git a/lib/cf-socket.c b/lib/cf-socket.c index 967a27fc2e..0f36bcec86 100644 --- a/lib/cf-socket.c +++ b/lib/cf-socket.c @@ -1304,7 +1304,7 @@ static int do_connect(struct Curl_cfilter *cf, struct Curl_easy *data, static CURLcode cf_tcp_connect(struct Curl_cfilter *cf, struct Curl_easy *data, - bool blocking, bool *done) + bool *done) { struct cf_socket_ctx *ctx = cf->ctx; CURLcode result = CURLE_COULDNT_CONNECT; @@ -1316,9 +1316,6 @@ static CURLcode cf_tcp_connect(struct Curl_cfilter *cf, return CURLE_OK; } - if(blocking) - return CURLE_UNSUPPORTED_PROTOCOL; - *done = FALSE; /* a negative world view is best */ if(ctx->sock == CURL_SOCKET_BAD) { int error; @@ -1889,12 +1886,11 @@ static CURLcode cf_udp_setup_quic(struct Curl_cfilter *cf, static CURLcode cf_udp_connect(struct Curl_cfilter *cf, struct Curl_easy *data, - bool blocking, bool *done) + bool *done) { struct cf_socket_ctx *ctx = cf->ctx; CURLcode result = CURLE_COULDNT_CONNECT; - (void)blocking; if(cf->connected) { *done = TRUE; return CURLE_OK; @@ -2099,7 +2095,7 @@ static void cf_tcp_set_accepted_remote_ip(struct Curl_cfilter *cf, static CURLcode cf_tcp_accept_connect(struct Curl_cfilter *cf, struct Curl_easy *data, - bool blocking, bool *done) + bool *done) { struct cf_socket_ctx *ctx = cf->ctx; #ifdef USE_IPV6 @@ -2115,7 +2111,6 @@ static CURLcode cf_tcp_accept_connect(struct Curl_cfilter *cf, /* we start accepted, if we ever close, we cannot go on */ (void)data; - (void)blocking; if(cf->connected) { *done = TRUE; return CURLE_OK; diff --git a/lib/cfilters.c b/lib/cfilters.c index 3cc1a41840..1c9e7bc776 100644 --- a/lib/cfilters.c +++ b/lib/cfilters.c @@ -368,10 +368,10 @@ bool Curl_conn_cf_discard_sub(struct Curl_cfilter *cf, CURLcode Curl_conn_cf_connect(struct Curl_cfilter *cf, struct Curl_easy *data, - bool blocking, bool *done) + bool *done) { if(cf) - return cf->cft->do_connect(cf, data, blocking, done); + return cf->cft->do_connect(cf, data, done); return CURLE_FAILED_INIT; } @@ -405,6 +405,9 @@ CURLcode Curl_conn_connect(struct Curl_easy *data, bool blocking, bool *done) { +#define CF_CONN_NUM_POLLS_ON_STACK 5 + struct pollfd a_few_on_stack[CF_CONN_NUM_POLLS_ON_STACK]; + struct curl_pollfds cpfds; struct Curl_cfilter *cf; CURLcode result = CURLE_OK; @@ -419,7 +422,11 @@ CURLcode Curl_conn_connect(struct Curl_easy *data, } *done = cf->connected; - if(!*done) { + if(*done) + return CURLE_OK; + + Curl_pollfds_init(&cpfds, a_few_on_stack, CF_CONN_NUM_POLLS_ON_STACK); + while(!*done) { if(Curl_conn_needs_flush(data, sockindex)) { DEBUGF(infof(data, "Curl_conn_connect(index=%d), flush", sockindex)); result = Curl_conn_flush(data, sockindex); @@ -427,7 +434,9 @@ CURLcode Curl_conn_connect(struct Curl_easy *data, return result; } - result = cf->cft->do_connect(cf, data, blocking, done); + result = cf->cft->do_connect(cf, data, done); + CURL_TRC_CF(data, cf, "Curl_conn_connect(block=%d) -> %d, done=%d", + blocking, result, *done); if(!result && *done) { /* Now that the complete filter chain is connected, let all filters * persist information at the connection. E.g. cf-socket sets the @@ -436,12 +445,56 @@ CURLcode Curl_conn_connect(struct Curl_easy *data, conn_report_connect_stats(data, data->conn); data->conn->keepalive = Curl_now(); Curl_verboseconnect(data, data->conn, sockindex); + goto out; } else if(result) { + CURL_TRC_CF(data, cf, "Curl_conn_connect(), filter returned %d", + result); conn_report_connect_stats(data, data->conn); + goto out; + } + + if(!blocking) + goto out; + else { + /* check allowed time left */ + const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE); + curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data); + struct easy_pollset ps; + int rc; + + if(timeout_ms < 0) { + /* no need to continue if time already is up */ + failf(data, "connect timeout"); + result = CURLE_OPERATION_TIMEDOUT; + goto out; + } + + CURL_TRC_CF(data, cf, "Curl_conn_connect(block=1), do poll"); + Curl_pollfds_reset(&cpfds); + memset(&ps, 0, sizeof(ps)); + /* In general, we want to send after connect, wait on that. */ + if(sockfd != CURL_SOCKET_BAD) + Curl_pollset_set_out_only(data, &ps, sockfd); + Curl_conn_adjust_pollset(data, &ps); + result = Curl_pollfds_add_ps(&cpfds, &ps); + if(result) + goto out; + + rc = Curl_poll(cpfds.pfds, cpfds.n, + CURLMIN(timeout_ms, (cpfds.n ? 1000 : 10))); + CURL_TRC_CF(data, cf, "Curl_conn_connect(block=1), Curl_poll() -> %d", + rc); + if(rc < 0) { + result = CURLE_COULDNT_CONNECT; + goto out; + } + /* continue iterating */ } } +out: + Curl_pollfds_cleanup(&cpfds); return result; } diff --git a/lib/cfilters.h b/lib/cfilters.h index 23746edcde..19edea9b98 100644 --- a/lib/cfilters.h +++ b/lib/cfilters.h @@ -51,7 +51,7 @@ typedef CURLcode Curl_cft_shutdown(struct Curl_cfilter *cf, typedef CURLcode Curl_cft_connect(struct Curl_cfilter *cf, struct Curl_easy *data, - bool blocking, bool *done); + bool *done); /* Return the hostname and port the connection goes to. * This may change with the connection state of filters when tunneling @@ -324,7 +324,7 @@ void Curl_conn_cf_discard_all(struct Curl_easy *data, CURLcode Curl_conn_cf_connect(struct Curl_cfilter *cf, struct Curl_easy *data, - bool blocking, bool *done); + bool *done); void Curl_conn_cf_close(struct Curl_cfilter *cf, struct Curl_easy *data); ssize_t Curl_conn_cf_send(struct Curl_cfilter *cf, struct Curl_easy *data, const void *buf, size_t len, bool eos, diff --git a/lib/connect.c b/lib/connect.c index 7b7fa785fe..02abd158f3 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -593,7 +593,7 @@ static CURLcode baller_connect(struct Curl_cfilter *cf, *connected = baller->connected; if(!baller->result && !*connected) { /* evaluate again */ - baller->result = Curl_conn_cf_connect(baller->cf, data, 0, connected); + baller->result = Curl_conn_cf_connect(baller->cf, data, connected); if(!baller->result) { if(*connected) { @@ -948,7 +948,7 @@ static void cf_he_adjust_pollset(struct Curl_cfilter *cf, static CURLcode cf_he_connect(struct Curl_cfilter *cf, struct Curl_easy *data, - bool blocking, bool *done) + bool *done) { struct cf_he_ctx *ctx = cf->ctx; CURLcode result = CURLE_OK; @@ -958,7 +958,6 @@ static CURLcode cf_he_connect(struct Curl_cfilter *cf, return CURLE_OK; } - (void)blocking; DEBUGASSERT(ctx); *done = FALSE; @@ -1263,7 +1262,7 @@ struct cf_setup_ctx { static CURLcode cf_setup_connect(struct Curl_cfilter *cf, struct Curl_easy *data, - bool blocking, bool *done) + bool *done) { struct cf_setup_ctx *ctx = cf->ctx; CURLcode result = CURLE_OK; @@ -1276,7 +1275,7 @@ static CURLcode cf_setup_connect(struct Curl_cfilter *cf, /* connect current sub-chain */ connect_sub_chain: if(cf->next && !cf->next->connected) { - result = Curl_conn_cf_connect(cf->next, data, blocking, done); + result = Curl_conn_cf_connect(cf->next, data, done); if(result || !*done) return result; } diff --git a/lib/ftp.c b/lib/ftp.c index e38ee1b88d..4ce932efe5 100644 --- a/lib/ftp.c +++ b/lib/ftp.c @@ -3603,7 +3603,7 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep) if(ftpc->wait_data_conn) { bool serv_conned; - result = Curl_conn_connect(data, SECONDARYSOCKET, TRUE, &serv_conned); + result = Curl_conn_connect(data, SECONDARYSOCKET, FALSE, &serv_conned); if(result) return result; /* Failed to accept data connection */ diff --git a/lib/http2.c b/lib/http2.c index 1f36786aa2..cd7512871e 100644 --- a/lib/http2.c +++ b/lib/http2.c @@ -2441,7 +2441,7 @@ static void cf_h2_adjust_pollset(struct Curl_cfilter *cf, static CURLcode cf_h2_connect(struct Curl_cfilter *cf, struct Curl_easy *data, - bool blocking, bool *done) + bool *done) { struct cf_h2_ctx *ctx = cf->ctx; CURLcode result = CURLE_OK; @@ -2455,7 +2455,7 @@ static CURLcode cf_h2_connect(struct Curl_cfilter *cf, /* Connect the lower filters first */ if(!cf->next->connected) { - result = Curl_conn_cf_connect(cf->next, data, blocking, done); + result = Curl_conn_cf_connect(cf->next, data, done); if(result || !*done) return result; } @@ -2827,7 +2827,7 @@ CURLcode Curl_http2_switch(struct Curl_easy *data) if(cf->next) { bool done; - return Curl_conn_cf_connect(cf, data, FALSE, &done); + return Curl_conn_cf_connect(cf, data, &done); } return CURLE_OK; } @@ -2849,7 +2849,7 @@ CURLcode Curl_http2_switch_at(struct Curl_cfilter *cf, struct Curl_easy *data) if(cf_h2->next) { bool done; - return Curl_conn_cf_connect(cf_h2, data, FALSE, &done); + return Curl_conn_cf_connect(cf_h2, data, &done); } return CURLE_OK; } @@ -2900,7 +2900,7 @@ CURLcode Curl_http2_upgrade(struct Curl_easy *data, if(cf->next) { bool done; - return Curl_conn_cf_connect(cf, data, FALSE, &done); + return Curl_conn_cf_connect(cf, data, &done); } return CURLE_OK; } diff --git a/lib/http_proxy.c b/lib/http_proxy.c index 8a9effd49f..0ccb826edb 100644 --- a/lib/http_proxy.c +++ b/lib/http_proxy.c @@ -307,7 +307,7 @@ out: static CURLcode http_proxy_cf_connect(struct Curl_cfilter *cf, struct Curl_easy *data, - bool blocking, bool *done) + bool *done) { struct cf_proxy_ctx *ctx = cf->ctx; CURLcode result; @@ -319,7 +319,7 @@ static CURLcode http_proxy_cf_connect(struct Curl_cfilter *cf, CURL_TRC_CF(data, cf, "connect"); connect_sub: - result = cf->next->cft->do_connect(cf->next, data, blocking, done); + result = cf->next->cft->do_connect(cf->next, data, done); if(result || !*done) return result; diff --git a/lib/select.c b/lib/select.c index ef8d554f1c..7b52f55d8f 100644 --- a/lib/select.c +++ b/lib/select.c @@ -410,6 +410,11 @@ void Curl_pollfds_init(struct curl_pollfds *cpfds, } } +void Curl_pollfds_reset(struct curl_pollfds *cpfds) +{ + cpfds->n = 0; +} + void Curl_pollfds_cleanup(struct curl_pollfds *cpfds) { DEBUGASSERT(cpfds); diff --git a/lib/select.h b/lib/select.h index 608395ff34..60e166b001 100644 --- a/lib/select.h +++ b/lib/select.h @@ -122,6 +122,8 @@ void Curl_pollfds_init(struct curl_pollfds *cpfds, struct pollfd *static_pfds, unsigned int static_count); +void Curl_pollfds_reset(struct curl_pollfds *cpfds); + void Curl_pollfds_cleanup(struct curl_pollfds *cpfds); CURLcode Curl_pollfds_add_ps(struct curl_pollfds *cpfds, diff --git a/lib/socks.c b/lib/socks.c index d16a30b90a..30a73112c3 100644 --- a/lib/socks.c +++ b/lib/socks.c @@ -1128,7 +1128,7 @@ static void socks_proxy_cf_free(struct Curl_cfilter *cf) */ static CURLcode socks_proxy_cf_connect(struct Curl_cfilter *cf, struct Curl_easy *data, - bool blocking, bool *done) + bool *done) { CURLcode result; struct connectdata *conn = cf->conn; @@ -1140,7 +1140,7 @@ static CURLcode socks_proxy_cf_connect(struct Curl_cfilter *cf, return CURLE_OK; } - result = cf->next->cft->do_connect(cf->next, data, blocking, done); + result = cf->next->cft->do_connect(cf->next, data, done); if(result || !*done) return result; diff --git a/lib/vquic/curl_msh3.c b/lib/vquic/curl_msh3.c index c592b2ec2b..8f23e90ece 100644 --- a/lib/vquic/curl_msh3.c +++ b/lib/vquic/curl_msh3.c @@ -877,13 +877,12 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf, static CURLcode cf_msh3_connect(struct Curl_cfilter *cf, struct Curl_easy *data, - bool blocking, bool *done) + bool *done) { struct cf_msh3_ctx *ctx = cf->ctx; struct cf_call_data save; CURLcode result = CURLE_OK; - (void)blocking; if(cf->connected) { *done = TRUE; return CURLE_OK; diff --git a/lib/vquic/curl_ngtcp2.c b/lib/vquic/curl_ngtcp2.c index 92c39b5a03..28c38c8844 100644 --- a/lib/vquic/curl_ngtcp2.c +++ b/lib/vquic/curl_ngtcp2.c @@ -2453,7 +2453,7 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf, static CURLcode cf_ngtcp2_connect(struct Curl_cfilter *cf, struct Curl_easy *data, - bool blocking, bool *done) + bool *done) { struct cf_ngtcp2_ctx *ctx = cf->ctx; CURLcode result = CURLE_OK; @@ -2468,7 +2468,7 @@ static CURLcode cf_ngtcp2_connect(struct Curl_cfilter *cf, /* Connect the UDP filter first */ if(!cf->next->connected) { - result = Curl_conn_cf_connect(cf->next, data, blocking, done); + result = Curl_conn_cf_connect(cf->next, data, done); if(result || !*done) return result; } diff --git a/lib/vquic/curl_osslq.c b/lib/vquic/curl_osslq.c index 4fd4fee11a..8360fda32c 100644 --- a/lib/vquic/curl_osslq.c +++ b/lib/vquic/curl_osslq.c @@ -1718,7 +1718,7 @@ out: static CURLcode cf_osslq_connect(struct Curl_cfilter *cf, struct Curl_easy *data, - bool blocking, bool *done) + bool *done) { struct cf_osslq_ctx *ctx = cf->ctx; CURLcode result = CURLE_OK; @@ -1733,7 +1733,7 @@ static CURLcode cf_osslq_connect(struct Curl_cfilter *cf, /* Connect the UDP filter first */ if(!cf->next->connected) { - result = Curl_conn_cf_connect(cf->next, data, blocking, done); + result = Curl_conn_cf_connect(cf->next, data, done); if(result || !*done) return result; } diff --git a/lib/vquic/curl_quiche.c b/lib/vquic/curl_quiche.c index 679cba3641..b7385cdef9 100644 --- a/lib/vquic/curl_quiche.c +++ b/lib/vquic/curl_quiche.c @@ -1378,7 +1378,7 @@ static CURLcode cf_quiche_verify_peer(struct Curl_cfilter *cf, static CURLcode cf_quiche_connect(struct Curl_cfilter *cf, struct Curl_easy *data, - bool blocking, bool *done) + bool *done) { struct cf_quiche_ctx *ctx = cf->ctx; CURLcode result = CURLE_OK; @@ -1390,7 +1390,7 @@ static CURLcode cf_quiche_connect(struct Curl_cfilter *cf, /* Connect the UDP filter first */ if(!cf->next->connected) { - result = Curl_conn_cf_connect(cf->next, data, blocking, done); + result = Curl_conn_cf_connect(cf->next, data, done); if(result || !*done) return result; } diff --git a/lib/vtls/bearssl.c b/lib/vtls/bearssl.c index 8b15b03d2d..09974be2b8 100644 --- a/lib/vtls/bearssl.c +++ b/lib/vtls/bearssl.c @@ -911,18 +911,14 @@ static ssize_t bearssl_recv(struct Curl_cfilter *cf, struct Curl_easy *data, return applen; } -static CURLcode bearssl_connect_common(struct Curl_cfilter *cf, - struct Curl_easy *data, - bool nonblocking, - bool *done) +static CURLcode bearssl_connect(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool *done) { CURLcode ret; struct ssl_connect_data *connssl = cf->ctx; - curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data); - timediff_t timeout_ms; - int what; - CURL_TRC_CF(data, cf, "connect_common(blocking=%d)", !nonblocking); + CURL_TRC_CF(data, cf, "connect()"); /* check if the connection has already been established */ if(ssl_connection_complete == connssl->state) { CURL_TRC_CF(data, cf, "connect_common, connected"); @@ -930,61 +926,18 @@ static CURLcode bearssl_connect_common(struct Curl_cfilter *cf, return CURLE_OK; } + *done = FALSE; + connssl->io_need = CURL_SSL_IO_NEED_NONE; + if(ssl_connect_1 == connssl->connecting_state) { ret = bearssl_connect_step1(cf, data); if(ret) return ret; } - while(ssl_connect_2 == connssl->connecting_state) { - /* check allowed time left */ - timeout_ms = Curl_timeleft(data, NULL, TRUE); - - if(timeout_ms < 0) { - /* no need to continue if time already is up */ - failf(data, "SSL connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - - /* if ssl is expecting something, check if it is available. */ - if(connssl->io_need) { - curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND) ? - sockfd : CURL_SOCKET_BAD; - curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV) ? - sockfd : CURL_SOCKET_BAD; - - CURL_TRC_CF(data, cf, "connect_common, check socket"); - what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, - nonblocking ? 0 : timeout_ms); - CURL_TRC_CF(data, cf, "connect_common, check socket -> %d", what); - if(what < 0) { - /* fatal error */ - failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); - return CURLE_SSL_CONNECT_ERROR; - } - else if(0 == what) { - if(nonblocking) { - *done = FALSE; - return CURLE_OK; - } - else { - /* timeout */ - failf(data, "SSL connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - } - /* socket is readable or writable */ - } - - /* Run transaction, and return to the caller if it failed or if this - * connection is done nonblocking and this loop would execute again. This - * permits the owner of a multi handle to abort a connection attempt - * before step2 has completed while ensuring that a client using select() - * or epoll() will always have a valid fdset to wait on. - */ - connssl->io_need = CURL_SSL_IO_NEED_NONE; + if(ssl_connect_2 == connssl->connecting_state) { ret = bearssl_connect_step2(cf, data); - if(ret || (nonblocking && (ssl_connect_2 == connssl->connecting_state))) + if(ret) return ret; } @@ -998,11 +951,6 @@ static CURLcode bearssl_connect_common(struct Curl_cfilter *cf, connssl->state = ssl_connection_complete; *done = TRUE; } - else - *done = FALSE; - - /* Reset our connect state machine */ - connssl->connecting_state = ssl_connect_1; return CURLE_OK; } @@ -1044,28 +992,6 @@ static CURLcode bearssl_random(struct Curl_easy *data UNUSED_PARAM, return CURLE_OK; } -static CURLcode bearssl_connect(struct Curl_cfilter *cf, - struct Curl_easy *data) -{ - CURLcode ret; - bool done = FALSE; - - ret = bearssl_connect_common(cf, data, FALSE, &done); - if(ret) - return ret; - - DEBUGASSERT(done); - - return CURLE_OK; -} - -static CURLcode bearssl_connect_nonblocking(struct Curl_cfilter *cf, - struct Curl_easy *data, - bool *done) -{ - return bearssl_connect_common(cf, data, TRUE, done); -} - static void *bearssl_get_internals(struct ssl_connect_data *connssl, CURLINFO info UNUSED_PARAM) { @@ -1161,7 +1087,6 @@ const struct Curl_ssl Curl_ssl_bearssl = { bearssl_random, /* random */ NULL, /* cert_status_request */ bearssl_connect, /* connect */ - bearssl_connect_nonblocking, /* connect_nonblocking */ Curl_ssl_adjust_pollset, /* adjust_pollset */ bearssl_get_internals, /* get_internals */ bearssl_close, /* close_one */ diff --git a/lib/vtls/gtls.c b/lib/vtls/gtls.c index a47d803c72..84cb387398 100644 --- a/lib/vtls/gtls.c +++ b/lib/vtls/gtls.c @@ -238,115 +238,68 @@ static void unload_file(gnutls_datum_t data) /* this function does a SSL/TLS (re-)handshake */ static CURLcode handshake(struct Curl_cfilter *cf, - struct Curl_easy *data, - bool duringconnect, - bool nonblocking) + struct Curl_easy *data) { struct ssl_connect_data *connssl = cf->ctx; struct gtls_ssl_backend_data *backend = (struct gtls_ssl_backend_data *)connssl->backend; gnutls_session_t session; - curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data); + int rc; DEBUGASSERT(backend); session = backend->gtls.session; - connssl->connecting_state = ssl_connect_2; - for(;;) { - timediff_t timeout_ms; - int rc; + connssl->io_need = CURL_SSL_IO_NEED_NONE; + backend->gtls.io_result = CURLE_OK; + rc = gnutls_handshake(session); - /* check allowed time left */ - timeout_ms = Curl_timeleft(data, NULL, duringconnect); - - if(timeout_ms < 0) { - /* no need to continue if time already is up */ - failf(data, "SSL connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - - /* if ssl is expecting something, check if it is available. */ - if(connssl->io_need) { - int what; - curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND) ? - sockfd : CURL_SOCKET_BAD; - curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV) ? - sockfd : CURL_SOCKET_BAD; - - what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, - nonblocking ? 0 : - timeout_ms ? timeout_ms : 1000); - if(what < 0) { - /* fatal error */ - failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); - return CURLE_SSL_CONNECT_ERROR; - } - else if(0 == what) { - if(nonblocking) - return CURLE_AGAIN; - else if(timeout_ms) { - /* timeout */ - failf(data, "SSL connection timeout at %ld", (long)timeout_ms); - return CURLE_OPERATION_TIMEDOUT; - } - } - /* socket is readable or writable */ - } - - connssl->io_need = CURL_SSL_IO_NEED_NONE; - backend->gtls.io_result = CURLE_OK; - rc = gnutls_handshake(session); - - if(!backend->gtls.shared_creds->trust_setup) { - /* After having send off the ClientHello, we prepare the trust - * store to verify the coming certificate from the server */ - CURLcode result = Curl_gtls_client_trust_setup(cf, data, &backend->gtls); - if(result) - return result; - } - - if((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED)) { - connssl->io_need = - gnutls_record_get_direction(session) ? - CURL_SSL_IO_NEED_SEND : CURL_SSL_IO_NEED_RECV; - continue; - } - else if((rc < 0) && !gnutls_error_is_fatal(rc)) { - const char *strerr = NULL; - - if(rc == GNUTLS_E_WARNING_ALERT_RECEIVED) { - gnutls_alert_description_t alert = gnutls_alert_get(session); - strerr = gnutls_alert_get_name(alert); - } - - if(!strerr) - strerr = gnutls_strerror(rc); - - infof(data, "gnutls_handshake() warning: %s", strerr); - continue; - } - else if((rc < 0) && backend->gtls.io_result) { - return backend->gtls.io_result; - } - else if(rc < 0) { - const char *strerr = NULL; - - if(rc == GNUTLS_E_FATAL_ALERT_RECEIVED) { - gnutls_alert_description_t alert = gnutls_alert_get(session); - strerr = gnutls_alert_get_name(alert); - } - - if(!strerr) - strerr = gnutls_strerror(rc); - - failf(data, "GnuTLS, handshake failed: %s", strerr); - return CURLE_SSL_CONNECT_ERROR; - } - - /* Reset our connect state machine */ - connssl->connecting_state = ssl_connect_1; - return CURLE_OK; + if(!backend->gtls.shared_creds->trust_setup) { + /* After having send off the ClientHello, we prepare the trust + * store to verify the coming certificate from the server */ + CURLcode result = Curl_gtls_client_trust_setup(cf, data, &backend->gtls); + if(result) + return result; } + + if((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED)) { + connssl->io_need = + gnutls_record_get_direction(session) ? + CURL_SSL_IO_NEED_SEND : CURL_SSL_IO_NEED_RECV; + return CURLE_AGAIN; + } + else if((rc < 0) && !gnutls_error_is_fatal(rc)) { + const char *strerr = NULL; + + if(rc == GNUTLS_E_WARNING_ALERT_RECEIVED) { + gnutls_alert_description_t alert = gnutls_alert_get(session); + strerr = gnutls_alert_get_name(alert); + } + + if(!strerr) + strerr = gnutls_strerror(rc); + + infof(data, "gnutls_handshake() warning: %s", strerr); + return CURLE_AGAIN; + } + else if((rc < 0) && backend->gtls.io_result) { + return backend->gtls.io_result; + } + else if(rc < 0) { + const char *strerr = NULL; + + if(rc == GNUTLS_E_FATAL_ALERT_RECEIVED) { + gnutls_alert_description_t alert = gnutls_alert_get(session); + strerr = gnutls_alert_get_name(alert); + } + + if(!strerr) + strerr = gnutls_strerror(rc); + + failf(data, "GnuTLS, handshake failed: %s", strerr); + return CURLE_SSL_CONNECT_ERROR; + } + + return CURLE_OK; } static gnutls_x509_crt_fmt_t gnutls_do_file_type(const char *type) @@ -1258,7 +1211,6 @@ gtls_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) CURLcode result; DEBUGASSERT(backend); - DEBUGASSERT(ssl_connect_1 == connssl->connecting_state); if(connssl->state == ssl_connection_complete) /* to make us tolerant against being called more than once for the @@ -1901,17 +1853,22 @@ out: 'ssl_connect_2' (doing handshake with the server), and 'ssl_connect_3' (verifying and getting stats). */ -static CURLcode -gtls_connect_common(struct Curl_cfilter *cf, - struct Curl_easy *data, - bool nonblocking, - bool *done) { +static CURLcode gtls_connect_common(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool *done) { struct ssl_connect_data *connssl = cf->ctx; struct gtls_ssl_backend_data *backend = (struct gtls_ssl_backend_data *)connssl->backend; CURLcode result = CURLE_OK; DEBUGASSERT(backend); + /* check if the connection has already been established */ + if(ssl_connection_complete == connssl->state) { + *done = TRUE; + return CURLE_OK; + } + + *done = FALSE; /* Initiate the connection, if not already done */ if(connssl->connecting_state == ssl_connect_1) { @@ -1936,7 +1893,7 @@ gtls_connect_common(struct Curl_cfilter *cf, DEBUGASSERT((connssl->earlydata_state == ssl_earlydata_none) || (connssl->earlydata_state == ssl_earlydata_sent)); - result = handshake(cf, data, TRUE, nonblocking); + result = handshake(cf, data); if(result) goto out; connssl->connecting_state = ssl_connect_3; @@ -1951,7 +1908,6 @@ gtls_connect_common(struct Curl_cfilter *cf, goto out; connssl->state = ssl_connection_complete; - connssl->connecting_state = ssl_connect_1; rc = gnutls_alpn_get_selected_protocol(backend->gtls.session, &proto); if(rc) { /* No ALPN from server */ @@ -1982,6 +1938,12 @@ gtls_connect_common(struct Curl_cfilter *cf, connssl->earlydata_skip = 0; } } + connssl->connecting_state = ssl_connect_done; + } + + if(ssl_connect_done == connssl->connecting_state) { + connssl->state = ssl_connection_complete; + *done = TRUE; } out: @@ -1994,9 +1956,9 @@ out: return result; } -static CURLcode gtls_connect_nonblocking(struct Curl_cfilter *cf, - struct Curl_easy *data, - bool *done) +static CURLcode gtls_connect(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool *done) { struct ssl_connect_data *connssl = cf->ctx; if(connssl->state == ssl_connection_deferred) { @@ -2004,22 +1966,7 @@ static CURLcode gtls_connect_nonblocking(struct Curl_cfilter *cf, *done = TRUE; return CURLE_OK; } - return gtls_connect_common(cf, data, TRUE, done); -} - -static CURLcode gtls_connect(struct Curl_cfilter *cf, - struct Curl_easy *data) -{ - CURLcode result; - bool done = FALSE; - - result = gtls_connect_common(cf, data, FALSE, &done); - if(result) - return result; - - DEBUGASSERT(done); - - return CURLE_OK; + return gtls_connect_common(cf, data, done); } static CURLcode gtls_connect_deferred(struct Curl_cfilter *cf, @@ -2039,7 +1986,7 @@ static CURLcode gtls_connect_deferred(struct Curl_cfilter *cf, return result; } - return gtls_connect_common(cf, data, TRUE, done); + return gtls_connect_common(cf, data, done); } static bool gtls_data_pending(struct Curl_cfilter *cf, @@ -2272,9 +2219,8 @@ static ssize_t gtls_recv(struct Curl_cfilter *cf, if(ret == GNUTLS_E_REHANDSHAKE) { /* BLOCKING call, this is bad but a work-around for now. Fixing this "the proper way" takes a whole lot of work. */ - CURLcode result = handshake(cf, data, FALSE, FALSE); + CURLcode result = handshake(cf, data); if(result) - /* handshake() writes error message on its own */ *curlcode = result; else *curlcode = CURLE_AGAIN; /* then return as if this was a wouldblock */ @@ -2356,7 +2302,6 @@ const struct Curl_ssl Curl_ssl_gnutls = { gtls_random, /* random */ gtls_cert_status_request, /* cert_status_request */ gtls_connect, /* connect */ - gtls_connect_nonblocking, /* connect_nonblocking */ Curl_ssl_adjust_pollset, /* adjust_pollset */ gtls_get_internals, /* get_internals */ gtls_close, /* close_one */ diff --git a/lib/vtls/mbedtls.c b/lib/vtls/mbedtls.c index 13e44c7c01..5145fbdaf0 100644 --- a/lib/vtls/mbedtls.c +++ b/lib/vtls/mbedtls.c @@ -1440,16 +1440,12 @@ static CURLcode mbedtls_random(struct Curl_easy *data, #endif } -static CURLcode -mbed_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data, - bool nonblocking, - bool *done) +static CURLcode mbedtls_connect(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool *done) { CURLcode retcode; struct ssl_connect_data *connssl = cf->ctx; - curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data); - timediff_t timeout_ms; - int what; /* check if the connection has already been established */ if(ssl_connection_complete == connssl->state) { @@ -1457,73 +1453,20 @@ mbed_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data, return CURLE_OK; } - if(ssl_connect_1 == connssl->connecting_state) { - /* Find out how much more time we are allowed */ - timeout_ms = Curl_timeleft(data, NULL, TRUE); + *done = FALSE; + connssl->io_need = CURL_SSL_IO_NEED_NONE; - if(timeout_ms < 0) { - /* no need to continue if time already is up */ - failf(data, "SSL connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } + if(ssl_connect_1 == connssl->connecting_state) { retcode = mbed_connect_step1(cf, data); if(retcode) return retcode; } - while(ssl_connect_2 == connssl->connecting_state) { - - /* check allowed time left */ - timeout_ms = Curl_timeleft(data, NULL, TRUE); - - if(timeout_ms < 0) { - /* no need to continue if time already is up */ - failf(data, "SSL connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - - /* if ssl is expecting something, check if it is available. */ - if(connssl->io_need) { - curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND) ? - sockfd : CURL_SOCKET_BAD; - curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV) ? - sockfd : CURL_SOCKET_BAD; - - what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, - nonblocking ? 0 : timeout_ms); - if(what < 0) { - /* fatal error */ - failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); - return CURLE_SSL_CONNECT_ERROR; - } - else if(0 == what) { - if(nonblocking) { - *done = FALSE; - return CURLE_OK; - } - else { - /* timeout */ - failf(data, "SSL connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - } - /* socket is readable or writable */ - } - - /* Run transaction, and return to the caller if it failed or if - * this connection is part of a multi handle and this loop would - * execute again. This permits the owner of a multi handle to - * abort a connection attempt before step2 has completed while - * ensuring that a client using select() or epoll() will always - * have a valid fdset to wait on. - */ - connssl->io_need = CURL_SSL_IO_NEED_NONE; + if(ssl_connect_2 == connssl->connecting_state) { retcode = mbed_connect_step2(cf, data); - if(retcode || - (nonblocking && (ssl_connect_2 == connssl->connecting_state))) + if(retcode) return retcode; - - } /* repeat step2 until all transactions are done. */ + } if(ssl_connect_3 == connssl->connecting_state) { /* For tls1.3 we get notified about new sessions */ @@ -1548,34 +1491,6 @@ mbed_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data, connssl->state = ssl_connection_complete; *done = TRUE; } - else - *done = FALSE; - - /* Reset our connect state machine */ - connssl->connecting_state = ssl_connect_1; - - return CURLE_OK; -} - -static CURLcode mbedtls_connect_nonblocking(struct Curl_cfilter *cf, - struct Curl_easy *data, - bool *done) -{ - return mbed_connect_common(cf, data, TRUE, done); -} - - -static CURLcode mbedtls_connect(struct Curl_cfilter *cf, - struct Curl_easy *data) -{ - CURLcode retcode; - bool done = FALSE; - - retcode = mbed_connect_common(cf, data, FALSE, &done); - if(retcode) - return retcode; - - DEBUGASSERT(done); return CURLE_OK; } @@ -1682,7 +1597,6 @@ const struct Curl_ssl Curl_ssl_mbedtls = { mbedtls_random, /* random */ NULL, /* cert_status_request */ mbedtls_connect, /* connect */ - mbedtls_connect_nonblocking, /* connect_nonblocking */ Curl_ssl_adjust_pollset, /* adjust_pollset */ mbedtls_get_internals, /* get_internals */ mbedtls_close, /* close_one */ diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index d5f55d7c46..3eddbfa7e4 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -4919,85 +4919,33 @@ static CURLcode ossl_connect_step3(struct Curl_cfilter *cf, return result; } -static CURLcode ossl_connect_common(struct Curl_cfilter *cf, - struct Curl_easy *data, - bool nonblocking, - bool *done) +static CURLcode ossl_connect(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool *done) { CURLcode result = CURLE_OK; struct ssl_connect_data *connssl = cf->ctx; - curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data); - int what; - connssl->io_need = CURL_SSL_IO_NEED_NONE; /* check if the connection has already been established */ if(ssl_connection_complete == connssl->state) { *done = TRUE; return CURLE_OK; } + *done = FALSE; + connssl->io_need = CURL_SSL_IO_NEED_NONE; + if(ssl_connect_1 == connssl->connecting_state) { - /* Find out how much more time we are allowed */ - const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE); - - if(timeout_ms < 0) { - /* no need to continue if time is already up */ - failf(data, "SSL connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - result = ossl_connect_step1(cf, data); if(result) goto out; } - while(ssl_connect_2 == connssl->connecting_state) { - - /* check allowed time left */ - const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE); - - if(timeout_ms < 0) { - /* no need to continue if time already is up */ - failf(data, "SSL connection timeout"); - result = CURLE_OPERATION_TIMEDOUT; - goto out; - } - - /* if ssl is expecting something, check if it is available. */ - if(!nonblocking && connssl->io_need) { - curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND) ? - sockfd : CURL_SOCKET_BAD; - curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV) ? - sockfd : CURL_SOCKET_BAD; - - what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, - timeout_ms); - if(what < 0) { - /* fatal error */ - failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); - result = CURLE_SSL_CONNECT_ERROR; - goto out; - } - if(0 == what) { - /* timeout */ - failf(data, "SSL connection timeout"); - result = CURLE_OPERATION_TIMEDOUT; - goto out; - } - /* socket is readable or writable */ - } - - /* Run transaction, and return to the caller if it failed or if this - * connection is done nonblocking and this loop would execute again. This - * permits the owner of a multi handle to abort a connection attempt - * before step2 has completed while ensuring that a client using select() - * or epoll() will always have a valid fdset to wait on. - */ + if(ssl_connect_2 == connssl->connecting_state) { result = ossl_connect_step2(cf, data); - if(result || (nonblocking && (ssl_connect_2 == connssl->connecting_state))) + if(result) goto out; - - } /* repeat step2 until all transactions are done. */ + } if(ssl_connect_3 == connssl->connecting_state) { result = ossl_connect_step3(cf, data); @@ -5009,38 +4957,11 @@ static CURLcode ossl_connect_common(struct Curl_cfilter *cf, connssl->state = ssl_connection_complete; *done = TRUE; } - else - *done = FALSE; - - /* Reset our connect state machine */ - connssl->connecting_state = ssl_connect_1; out: return result; } -static CURLcode ossl_connect_nonblocking(struct Curl_cfilter *cf, - struct Curl_easy *data, - bool *done) -{ - return ossl_connect_common(cf, data, TRUE, done); -} - -static CURLcode ossl_connect(struct Curl_cfilter *cf, - struct Curl_easy *data) -{ - CURLcode result; - bool done = FALSE; - - result = ossl_connect_common(cf, data, FALSE, &done); - if(result) - return result; - - DEBUGASSERT(done); - - return CURLE_OK; -} - static bool ossl_data_pending(struct Curl_cfilter *cf, const struct Curl_easy *data) { @@ -5500,7 +5421,6 @@ const struct Curl_ssl Curl_ssl_openssl = { ossl_random, /* random */ ossl_cert_status_request, /* cert_status_request */ ossl_connect, /* connect */ - ossl_connect_nonblocking, /* connect_nonblocking */ Curl_ssl_adjust_pollset, /* adjust_pollset */ ossl_get_internals, /* get_internals */ ossl_close, /* close_one */ diff --git a/lib/vtls/rustls.c b/lib/vtls/rustls.c index 948d0e9cce..2fecca0970 100644 --- a/lib/vtls/rustls.c +++ b/lib/vtls/rustls.c @@ -779,48 +779,36 @@ cr_set_negotiated_alpn(struct Curl_cfilter *cf, struct Curl_easy *data, /* Given an established network connection, do a TLS handshake. * - * If `blocking` is true, this function will block until the handshake is - * complete. Otherwise it will return as soon as I/O would block. - * - * For the non-blocking I/O case, this function will set `*done` to true - * once the handshake is complete. This function never reads the value of - * `*done*`. + * This function will set `*done` to true once the handshake is complete. + * This function never reads the value of `*done*`. */ static CURLcode -cr_connect_common(struct Curl_cfilter *cf, - struct Curl_easy *data, - bool blocking, - bool *done) +cr_connect(struct Curl_cfilter *cf, + struct Curl_easy *data, bool *done) { struct ssl_connect_data *const connssl = cf->ctx; - curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data); struct rustls_ssl_backend_data *const backend = (struct rustls_ssl_backend_data *)connssl->backend; struct rustls_connection *rconn = NULL; CURLcode tmperr = CURLE_OK; int result; - int what; bool wants_read; bool wants_write; - curl_socket_t writefd; - curl_socket_t readfd; - timediff_t timeout_ms; - timediff_t socket_check_timeout; DEBUGASSERT(backend); - CURL_TRC_CF(data, cf, "cr_connect_common, state=%d", connssl->state); + CURL_TRC_CF(data, cf, "cr_connect, state=%d", connssl->state); *done = FALSE; + if(!backend->conn) { result = cr_init_backend(cf, data, (struct rustls_ssl_backend_data *)connssl->backend); - CURL_TRC_CF(data, cf, "cr_connect_common, init backend -> %d", result); + CURL_TRC_CF(data, cf, "cr_connect, init backend -> %d", result); if(result != CURLE_OK) { return result; } connssl->state = ssl_connection_negotiating; } - rconn = backend->conn; /* Read/write data until the handshake is done or the socket would block. */ @@ -868,50 +856,14 @@ cr_connect_common(struct Curl_cfilter *cf, wants_write = rustls_connection_wants_write(rconn) || backend->plain_out_buffered; DEBUGASSERT(wants_read || wants_write); - writefd = wants_write ? sockfd : CURL_SOCKET_BAD; - readfd = wants_read ? sockfd : CURL_SOCKET_BAD; - - /* check allowed time left */ - timeout_ms = Curl_timeleft(data, NULL, TRUE); - - if(timeout_ms < 0) { - /* no need to continue if time already is up */ - failf(data, "rustls: operation timed out before socket check"); - return CURLE_OPERATION_TIMEDOUT; - } - - socket_check_timeout = blocking ? timeout_ms : 0; - - what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, - socket_check_timeout); - if(what < 0) { - /* fatal error */ - failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); - return CURLE_SSL_CONNECT_ERROR; - } - if(blocking && 0 == what) { - failf(data, "rustls: connection timeout after %" FMT_TIMEDIFF_T " ms", - socket_check_timeout); - return CURLE_OPERATION_TIMEDOUT; - } - if(0 == what) { - CURL_TRC_CF(data, cf, "Curl_socket_check: %s would block", - wants_read && wants_write ? "writing and reading" : - wants_write ? "writing" : "reading"); - if(wants_write) - connssl->io_need |= CURL_SSL_IO_NEED_SEND; - if(wants_read) - connssl->io_need |= CURL_SSL_IO_NEED_RECV; - return CURLE_OK; - } - /* socket is readable or writable */ if(wants_write) { CURL_TRC_CF(data, cf, "rustls_connection wants us to write_tls."); cr_send(cf, data, NULL, 0, &tmperr); if(tmperr == CURLE_AGAIN) { CURL_TRC_CF(data, cf, "writing would block"); - /* fall through */ + connssl->io_need = CURL_SSL_IO_NEED_SEND; + return CURLE_OK; } else if(tmperr != CURLE_OK) { return tmperr; @@ -923,7 +875,8 @@ cr_connect_common(struct Curl_cfilter *cf, if(tls_recv_more(cf, data, &tmperr) < 0) { if(tmperr == CURLE_AGAIN) { CURL_TRC_CF(data, cf, "reading would block"); - /* fall through */ + connssl->io_need = CURL_SSL_IO_NEED_RECV; + return CURLE_OK; } else if(tmperr == CURLE_RECV_ERROR) { return CURLE_SSL_CONNECT_ERROR; @@ -940,20 +893,6 @@ cr_connect_common(struct Curl_cfilter *cf, DEBUGASSERT(FALSE); } -static CURLcode -cr_connect_nonblocking(struct Curl_cfilter *cf, - struct Curl_easy *data, bool *done) -{ - return cr_connect_common(cf, data, false, done); -} - -static CURLcode -cr_connect_blocking(struct Curl_cfilter *cf, struct Curl_easy *data) -{ - bool done; /* unused */ - return cr_connect_common(cf, data, true, &done); -} - static void * cr_get_internals(struct ssl_connect_data *connssl, CURLINFO info UNUSED_PARAM) @@ -1083,8 +1022,7 @@ const struct Curl_ssl Curl_ssl_rustls = { cr_data_pending, /* data_pending */ cr_random, /* random */ NULL, /* cert_status_request */ - cr_connect_blocking, /* connect */ - cr_connect_nonblocking, /* connect_nonblocking */ + cr_connect, /* connect */ Curl_ssl_adjust_pollset, /* adjust_pollset */ cr_get_internals, /* get_internals */ cr_close, /* close_one */ diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c index 24a8f68a47..ffd681bd38 100644 --- a/lib/vtls/schannel.c +++ b/lib/vtls/schannel.c @@ -1648,16 +1648,12 @@ schannel_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data) return CURLE_OK; } -static CURLcode -schannel_connect_common(struct Curl_cfilter *cf, - struct Curl_easy *data, - bool nonblocking, bool *done) +static CURLcode schannel_connect(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool *done) { - CURLcode result; struct ssl_connect_data *connssl = cf->ctx; - curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data); - timediff_t timeout_ms; - int what; + CURLcode result; /* check if the connection has already been established */ if(ssl_connection_complete == connssl->state) { @@ -1665,73 +1661,19 @@ schannel_connect_common(struct Curl_cfilter *cf, return CURLE_OK; } + *done = FALSE; + if(ssl_connect_1 == connssl->connecting_state) { - /* check out how much more time we are allowed */ - timeout_ms = Curl_timeleft(data, NULL, TRUE); - - if(timeout_ms < 0) { - /* no need to continue if time already is up */ - failf(data, "SSL/TLS connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - result = schannel_connect_step1(cf, data); if(result) return result; } - while(ssl_connect_2 == connssl->connecting_state) { - - /* check out how much more time we are allowed */ - timeout_ms = Curl_timeleft(data, NULL, TRUE); - - if(timeout_ms < 0) { - /* no need to continue if time already is up */ - failf(data, "SSL/TLS connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - - /* if ssl is expecting something, check if it is available. */ - if(connssl->io_need) { - - curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND) ? - sockfd : CURL_SOCKET_BAD; - curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV) ? - sockfd : CURL_SOCKET_BAD; - - what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, - nonblocking ? 0 : timeout_ms); - if(what < 0) { - /* fatal error */ - failf(data, "select/poll on SSL/TLS socket, errno: %d", SOCKERRNO); - return CURLE_SSL_CONNECT_ERROR; - } - else if(0 == what) { - if(nonblocking) { - *done = FALSE; - return CURLE_OK; - } - else { - /* timeout */ - failf(data, "SSL/TLS connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - } - /* socket is readable or writable */ - } - - /* Run transaction, and return to the caller if it failed or if - * this connection is part of a multi handle and this loop would - * execute again. This permits the owner of a multi handle to - * abort a connection attempt before step2 has completed while - * ensuring that a client using select() or epoll() will always - * have a valid fdset to wait on. - */ + if(ssl_connect_2 == connssl->connecting_state) { result = schannel_connect_step2(cf, data); - if(result || (nonblocking && (ssl_connect_2 == connssl->connecting_state))) + if(result) return result; - - } /* repeat step2 until all transactions are done. */ + } if(ssl_connect_3 == connssl->connecting_state) { result = schannel_connect_step3(cf, data); @@ -1758,11 +1700,6 @@ schannel_connect_common(struct Curl_cfilter *cf, *done = TRUE; } - else - *done = FALSE; - - /* reset our connection state machine */ - connssl->connecting_state = ssl_connect_1; return CURLE_OK; } @@ -2135,7 +2072,7 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data, connssl->connecting_state = ssl_connect_2; connssl->io_need = CURL_SSL_IO_NEED_SEND; backend->recv_renegotiating = TRUE; - *err = schannel_connect_common(cf, data, FALSE, &done); + *err = schannel_connect(cf, data, &done); backend->recv_renegotiating = FALSE; if(*err) { infof(data, "schannel: renegotiation failed"); @@ -2246,28 +2183,6 @@ cleanup: return *err ? -1 : 0; } -static CURLcode schannel_connect_nonblocking(struct Curl_cfilter *cf, - struct Curl_easy *data, - bool *done) -{ - return schannel_connect_common(cf, data, TRUE, done); -} - -static CURLcode schannel_connect(struct Curl_cfilter *cf, - struct Curl_easy *data) -{ - CURLcode result; - bool done = FALSE; - - result = schannel_connect_common(cf, data, FALSE, &done); - if(result) - return result; - - DEBUGASSERT(done); - - return CURLE_OK; -} - static bool schannel_data_pending(struct Curl_cfilter *cf, const struct Curl_easy *data) { @@ -2806,7 +2721,6 @@ const struct Curl_ssl Curl_ssl_schannel = { schannel_random, /* random */ NULL, /* cert_status_request */ schannel_connect, /* connect */ - schannel_connect_nonblocking, /* connect_nonblocking */ Curl_ssl_adjust_pollset, /* adjust_pollset */ schannel_get_internals, /* get_internals */ schannel_close, /* close_one */ diff --git a/lib/vtls/sectransp.c b/lib/vtls/sectransp.c index bd8bf282fe..25d5874e09 100644 --- a/lib/vtls/sectransp.c +++ b/lib/vtls/sectransp.c @@ -2287,15 +2287,12 @@ static CURLcode sectransp_connect_step3(struct Curl_cfilter *cf, return CURLE_OK; } -static CURLcode -sectransp_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data, - bool nonblocking, - bool *done) +static CURLcode sectransp_connect(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool *done) { CURLcode result; struct ssl_connect_data *connssl = cf->ctx; - curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data); - int what; /* check if the connection has already been established */ if(ssl_connection_complete == connssl->state) { @@ -2303,73 +2300,20 @@ sectransp_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data, return CURLE_OK; } + *done = FALSE; + connssl->io_need = CURL_SSL_IO_NEED_NONE; + if(ssl_connect_1 == connssl->connecting_state) { - /* Find out how much more time we are allowed */ - const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE); - - if(timeout_ms < 0) { - /* no need to continue if time already is up */ - failf(data, "SSL connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - result = sectransp_connect_step1(cf, data); if(result) return result; } - while(ssl_connect_2 == connssl->connecting_state) { - - /* check allowed time left */ - const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE); - - if(timeout_ms < 0) { - /* no need to continue if time already is up */ - failf(data, "SSL connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - - /* if ssl is expecting something, check if it is available. */ - if(connssl->io_need) { - - curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND) ? - sockfd : CURL_SOCKET_BAD; - curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV) ? - sockfd : CURL_SOCKET_BAD; - - what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, - nonblocking ? 0 : timeout_ms); - if(what < 0) { - /* fatal error */ - failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); - return CURLE_SSL_CONNECT_ERROR; - } - else if(0 == what) { - if(nonblocking) { - *done = FALSE; - return CURLE_OK; - } - else { - /* timeout */ - failf(data, "SSL connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - } - /* socket is readable or writable */ - } - - /* Run transaction, and return to the caller if it failed or if this - * connection is done nonblocking and this loop would execute again. This - * permits the owner of a multi handle to abort a connection attempt - * before step2 has completed while ensuring that a client using select() - * or epoll() will always have a valid fdset to wait on. - */ + if(ssl_connect_2 == connssl->connecting_state) { result = sectransp_connect_step2(cf, data); - if(result || (nonblocking && (ssl_connect_2 == connssl->connecting_state))) + if(result) return result; - - } /* repeat step2 until all transactions are done. */ - + } if(ssl_connect_3 == connssl->connecting_state) { result = sectransp_connect_step3(cf, data); @@ -2382,34 +2326,6 @@ sectransp_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data, connssl->state = ssl_connection_complete; *done = TRUE; } - else - *done = FALSE; - - /* Reset our connect state machine */ - connssl->connecting_state = ssl_connect_1; - - return CURLE_OK; -} - -static CURLcode sectransp_connect_nonblocking(struct Curl_cfilter *cf, - struct Curl_easy *data, - bool *done) -{ - return sectransp_connect_common(cf, data, TRUE, done); -} - -static CURLcode sectransp_connect(struct Curl_cfilter *cf, - struct Curl_easy *data) -{ - CURLcode result; - bool done = FALSE; - - result = sectransp_connect_common(cf, data, FALSE, &done); - - if(result) - return result; - - DEBUGASSERT(done); return CURLE_OK; } @@ -2754,7 +2670,6 @@ const struct Curl_ssl Curl_ssl_sectransp = { sectransp_random, /* random */ NULL, /* cert_status_request */ sectransp_connect, /* connect */ - sectransp_connect_nonblocking, /* connect_nonblocking */ Curl_ssl_adjust_pollset, /* adjust_pollset */ sectransp_get_internals, /* get_internals */ sectransp_close, /* close_one */ diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c index 6297d82327..a6587c072e 100644 --- a/lib/vtls/vtls.c +++ b/lib/vtls/vtls.c @@ -485,29 +485,8 @@ static void cf_ctx_free(struct ssl_connect_data *ctx) } } -static CURLcode ssl_connect(struct Curl_cfilter *cf, struct Curl_easy *data) -{ - struct ssl_connect_data *connssl = cf->ctx; - CURLcode result; - - if(!ssl_prefs_check(data)) - return CURLE_SSL_CONNECT_ERROR; - - /* mark this is being ssl-enabled from here on. */ - connssl->state = ssl_connection_negotiating; - - result = connssl->ssl_impl->connect_blocking(cf, data); - - if(!result) { - DEBUGASSERT(connssl->state == ssl_connection_complete); - } - - return result; -} - static CURLcode -ssl_connect_nonblocking(struct Curl_cfilter *cf, struct Curl_easy *data, - bool *done) +ssl_connect(struct Curl_cfilter *cf, struct Curl_easy *data, bool *done) { struct ssl_connect_data *connssl = cf->ctx; @@ -515,7 +494,7 @@ ssl_connect_nonblocking(struct Curl_cfilter *cf, struct Curl_easy *data, return CURLE_SSL_CONNECT_ERROR; /* mark this is being ssl requested from here on. */ - return connssl->ssl_impl->connect_nonblocking(cf, data, done); + return connssl->ssl_impl->do_connect(cf, data, done); } CURLcode Curl_ssl_get_channel_binding(struct Curl_easy *data, int sockindex, @@ -923,20 +902,11 @@ static int multissl_init(void) } static CURLcode multissl_connect(struct Curl_cfilter *cf, - struct Curl_easy *data) + struct Curl_easy *data, bool *done) { if(multissl_setup(NULL)) return CURLE_FAILED_INIT; - return Curl_ssl->connect_blocking(cf, data); -} - -static CURLcode multissl_connect_nonblocking(struct Curl_cfilter *cf, - struct Curl_easy *data, - bool *done) -{ - if(multissl_setup(NULL)) - return CURLE_FAILED_INIT; - return Curl_ssl->connect_nonblocking(cf, data, done); + return Curl_ssl->do_connect(cf, data, done); } static void multissl_adjust_pollset(struct Curl_cfilter *cf, @@ -995,7 +965,6 @@ static const struct Curl_ssl Curl_ssl_multi = { NULL, /* random */ NULL, /* cert_status_request */ multissl_connect, /* connect */ - multissl_connect_nonblocking, /* connect_nonblocking */ multissl_adjust_pollset, /* adjust_pollset */ multissl_get_internals, /* get_internals */ multissl_close, /* close_one */ @@ -1343,7 +1312,7 @@ static void ssl_cf_close(struct Curl_cfilter *cf, static CURLcode ssl_cf_connect(struct Curl_cfilter *cf, struct Curl_easy *data, - bool blocking, bool *done) + bool *done) { struct ssl_connect_data *connssl = cf->ctx; struct cf_call_data save; @@ -1360,7 +1329,7 @@ static CURLcode ssl_cf_connect(struct Curl_cfilter *cf, } if(!cf->next->connected) { - result = cf->next->cft->do_connect(cf->next, data, blocking, done); + result = cf->next->cft->do_connect(cf->next, data, done); if(result || !*done) return result; } @@ -1380,13 +1349,7 @@ static CURLcode ssl_cf_connect(struct Curl_cfilter *cf, goto out; } - if(blocking) { - result = ssl_connect(cf, data); - *done = (result == CURLE_OK); - } - else { - result = ssl_connect_nonblocking(cf, data, done); - } + result = ssl_connect(cf, data, done); if(!result && *done) { cf->connected = TRUE; diff --git a/lib/vtls/vtls_int.h b/lib/vtls/vtls_int.h index 3a5611dfe4..0fe709014b 100644 --- a/lib/vtls/vtls_int.h +++ b/lib/vtls/vtls_int.h @@ -157,11 +157,8 @@ struct Curl_ssl { size_t length); bool (*cert_status_request)(void); - CURLcode (*connect_blocking)(struct Curl_cfilter *cf, - struct Curl_easy *data); - CURLcode (*connect_nonblocking)(struct Curl_cfilter *cf, - struct Curl_easy *data, - bool *done); + CURLcode (*do_connect)(struct Curl_cfilter *cf, struct Curl_easy *data, + bool *done); /* During handshake/shutdown, adjust the pollset to include the socket * for POLLOUT or POLLIN as needed. Mandatory. */ diff --git a/lib/vtls/wolfssl.c b/lib/vtls/wolfssl.c index 51e7e539a5..c9b1c8e5ec 100644 --- a/lib/vtls/wolfssl.c +++ b/lib/vtls/wolfssl.c @@ -1842,15 +1842,12 @@ static bool wolfssl_data_pending(struct Curl_cfilter *cf, return FALSE; } -static CURLcode -wolfssl_connect_common(struct Curl_cfilter *cf, - struct Curl_easy *data, - bool nonblocking, - bool *done) +static CURLcode wolfssl_connect(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool *done) { CURLcode result; struct ssl_connect_data *connssl = cf->ctx; - curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data); /* check if the connection has already been established */ if(ssl_connection_complete == connssl->state) { @@ -1858,70 +1855,20 @@ wolfssl_connect_common(struct Curl_cfilter *cf, return CURLE_OK; } + *done = FALSE; + connssl->io_need = CURL_SSL_IO_NEED_NONE; + if(ssl_connect_1 == connssl->connecting_state) { - /* Find out how much more time we are allowed */ - const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE); - - if(timeout_ms < 0) { - /* no need to continue if time already is up */ - failf(data, "SSL connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - result = wolfssl_connect_step1(cf, data); if(result) return result; } - while(ssl_connect_2 == connssl->connecting_state) { - - /* check allowed time left */ - const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE); - - if(timeout_ms < 0) { - /* no need to continue if time already is up */ - failf(data, "SSL connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - - /* if ssl is expecting something, check if it is available. */ - if(connssl->io_need) { - curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND) ? - sockfd : CURL_SOCKET_BAD; - curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV) ? - sockfd : CURL_SOCKET_BAD; - int what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, - nonblocking ? 0 : timeout_ms); - if(what < 0) { - /* fatal error */ - failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); - return CURLE_SSL_CONNECT_ERROR; - } - else if(0 == what) { - if(nonblocking) { - *done = FALSE; - return CURLE_OK; - } - else { - /* timeout */ - failf(data, "SSL connection timeout"); - return CURLE_OPERATION_TIMEDOUT; - } - } - /* socket is readable or writable */ - } - - /* Run transaction, and return to the caller if it failed or if - * this connection is part of a multi handle and this loop would - * execute again. This permits the owner of a multi handle to - * abort a connection attempt before step2 has completed while - * ensuring that a client using select() or epoll() will always - * have a valid fdset to wait on. - */ + if(ssl_connect_2 == connssl->connecting_state) { result = wolfssl_connect_step2(cf, data); - if(result || (nonblocking && (ssl_connect_2 == connssl->connecting_state))) + if(result) return result; - } /* repeat step2 until all transactions are done. */ + } if(ssl_connect_3 == connssl->connecting_state) { /* In other backends, this is where we verify the certificate, but @@ -1933,39 +1880,11 @@ wolfssl_connect_common(struct Curl_cfilter *cf, connssl->state = ssl_connection_complete; *done = TRUE; } - else - *done = FALSE; - - /* Reset our connect state machine */ - connssl->connecting_state = ssl_connect_1; return CURLE_OK; } -static CURLcode wolfssl_connect_nonblocking(struct Curl_cfilter *cf, - struct Curl_easy *data, - bool *done) -{ - return wolfssl_connect_common(cf, data, TRUE, done); -} - - -static CURLcode wolfssl_connect(struct Curl_cfilter *cf, - struct Curl_easy *data) -{ - CURLcode result; - bool done = FALSE; - - result = wolfssl_connect_common(cf, data, FALSE, &done); - if(result) - return result; - - DEBUGASSERT(done); - - return CURLE_OK; -} - static CURLcode wolfssl_random(struct Curl_easy *data, unsigned char *entropy, size_t length) { @@ -2037,7 +1956,6 @@ const struct Curl_ssl Curl_ssl_wolfssl = { wolfssl_random, /* random */ NULL, /* cert_status_request */ wolfssl_connect, /* connect */ - wolfssl_connect_nonblocking, /* connect_nonblocking */ Curl_ssl_adjust_pollset, /* adjust_pollset */ wolfssl_get_internals, /* get_internals */ wolfssl_close, /* close_one */ diff --git a/tests/unit/unit2600.c b/tests/unit/unit2600.c index 8c19ebc774..6b2aca842c 100644 --- a/tests/unit/unit2600.c +++ b/tests/unit/unit2600.c @@ -134,13 +134,12 @@ static void cf_test_destroy(struct Curl_cfilter *cf, struct Curl_easy *data) static CURLcode cf_test_connect(struct Curl_cfilter *cf, struct Curl_easy *data, - bool blocking, bool *done) + bool *done) { struct cf_test_ctx *ctx = cf->ctx; timediff_t duration_ms; (void)data; - (void)blocking; *done = FALSE; duration_ms = Curl_timediff(Curl_now(), ctx->started); if(duration_ms >= ctx->fail_delay_ms) {