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
This commit is contained in:
Stefan Eissing 2023-03-01 13:05:09 +01:00 committed by Daniel Stenberg
parent 9deebd311b
commit 9fd2d5aa72
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
2 changed files with 25 additions and 20 deletions

View File

@ -1468,35 +1468,33 @@ static bool cf_socket_conn_is_alive(struct Curl_cfilter *cf,
struct Curl_easy *data) struct Curl_easy *data)
{ {
struct cf_socket_ctx *ctx = cf->ctx; struct cf_socket_ctx *ctx = cf->ctx;
int sval; struct pollfd pfd[1];
int r;
(void)data; (void)data;
if(!ctx || ctx->sock == CURL_SOCKET_BAD) if(!ctx || ctx->sock == CURL_SOCKET_BAD)
return FALSE; return FALSE;
sval = SOCKET_READABLE(ctx->sock, 0); /* Check with 0 timeout if there are any events pending on the socket */
if(sval == 0) { pfd[0].fd = ctx->sock;
/* timeout */ pfd[0].events = POLLRDNORM|POLLIN|POLLRDBAND|POLLPRI;
return TRUE; pfd[0].revents = 0;
}
else if(sval & CURL_CSELECT_ERR) { r = Curl_poll(pfd, 1, 0);
/* socket is in an error state */ if(r < 0) {
DEBUGF(LOG_CF(data, cf, "is_alive: poll error, assume dead"));
return FALSE; return FALSE;
} }
else if(sval & CURL_CSELECT_IN) { else if(r == 0) {
/* readable with no error. could still be closed */ DEBUGF(LOG_CF(data, cf, "is_alive: poll timeout, assume alive"));
/* 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
return TRUE; 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; return TRUE;
} }

View File

@ -1649,7 +1649,14 @@ static bool cf_ssl_is_alive(struct Curl_cfilter *cf, struct Curl_easy *data)
CF_DATA_SAVE(save, cf, data); CF_DATA_SAVE(save, cf, data);
result = Curl_ssl->check_cxn(cf, data) != 0; result = Curl_ssl->check_cxn(cf, data) != 0;
CF_DATA_RESTORE(cf, save); 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 = { struct Curl_cftype Curl_cft_ssl = {