From: Stefan Eissing Date: Wed, 1 Mar 2023 12:05:09 +0000 (+0100) Subject: socket: detect "dead" connections better, e.g. not fit for reuse X-Git-Tag: curl-8_0_0~114 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=9fd2d5aa722d00c67b659938428c3b1047e949a6;p=thirdparty%2Fcurl.git socket: detect "dead" connections better, e.g. not fit for reuse - refs #10646 where reuse was attempted on closed connections in the cache, leading to an exhaustion of retries on a transfer - the mistake was that poll events like POLLHUP, POLLERR, etc were regarded as "not dead". - change cf-socket filter check to regard such events as inidication of corpsiness. - vtls filter checks: fixed interpretation of backend check result when inconclusive to interrogate status further down the filter chain. Reported-by: SendSonS on github Fixes #10646 Closes #10652 --- diff --git a/lib/cf-socket.c b/lib/cf-socket.c index d41206488e..f523b13325 100644 --- a/lib/cf-socket.c +++ b/lib/cf-socket.c @@ -1468,35 +1468,33 @@ static bool cf_socket_conn_is_alive(struct Curl_cfilter *cf, struct Curl_easy *data) { struct cf_socket_ctx *ctx = cf->ctx; - int sval; + struct pollfd pfd[1]; + int r; (void)data; if(!ctx || ctx->sock == CURL_SOCKET_BAD) return FALSE; - sval = SOCKET_READABLE(ctx->sock, 0); - if(sval == 0) { - /* timeout */ - return TRUE; - } - else if(sval & CURL_CSELECT_ERR) { - /* socket is in an error state */ + /* Check with 0 timeout if there are any events pending on the socket */ + pfd[0].fd = ctx->sock; + pfd[0].events = POLLRDNORM|POLLIN|POLLRDBAND|POLLPRI; + pfd[0].revents = 0; + + r = Curl_poll(pfd, 1, 0); + if(r < 0) { + DEBUGF(LOG_CF(data, cf, "is_alive: poll error, assume dead")); return FALSE; } - else if(sval & CURL_CSELECT_IN) { - /* readable with no error. could still be closed */ -/* Minix 3.1 doesn't support any flags on recv; just assume socket is OK */ -#ifdef MSG_PEEK - /* use the socket */ - char buf; - if(recv((RECV_TYPE_ARG1)ctx->sock, (RECV_TYPE_ARG2)&buf, - (RECV_TYPE_ARG3)1, (RECV_TYPE_ARG4)MSG_PEEK) == 0) { - return FALSE; /* FIN received */ - } -#endif + else if(r == 0) { + DEBUGF(LOG_CF(data, cf, "is_alive: poll timeout, assume alive")); return TRUE; } + else if(pfd[0].revents & (POLLERR|POLLHUP|POLLPRI|POLLNVAL)) { + DEBUGF(LOG_CF(data, cf, "is_alive: err/hup/etc events, assume dead")); + return FALSE; + } + DEBUGF(LOG_CF(data, cf, "is_alive: valid events, looks alive")); return TRUE; } diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c index 15f6844c7b..0fb3d43f41 100644 --- a/lib/vtls/vtls.c +++ b/lib/vtls/vtls.c @@ -1649,7 +1649,14 @@ static bool cf_ssl_is_alive(struct Curl_cfilter *cf, struct Curl_easy *data) CF_DATA_SAVE(save, cf, data); result = Curl_ssl->check_cxn(cf, data) != 0; CF_DATA_RESTORE(cf, save); - return result; + if(result > 0) + return TRUE; + if(result == 0) + return FALSE; + /* ssl backend does not know */ + return cf->next? + cf->next->cft->is_alive(cf->next, data) : + FALSE; /* pessimistic in absence of data */ } struct Curl_cftype Curl_cft_ssl = {