]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
socket: detect "dead" connections better, e.g. not fit for reuse
authorStefan Eissing <stefan@eissing.org>
Wed, 1 Mar 2023 12:05:09 +0000 (13:05 +0100)
committerDaniel Stenberg <daniel@haxx.se>
Thu, 2 Mar 2023 08:03:06 +0000 (09:03 +0100)
- 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

lib/cf-socket.c
lib/vtls/vtls.c

index d41206488e23adb3f062eac4a5429bc299ff3f60..f523b1332568f6699111ff27fec51c7d8b17adad 100644 (file)
@@ -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;
 }
 
index 15f6844c7b89f6c66cbd7ee979009ee230b55b6e..0fb3d43f418412ceab850afcb5f942d66c1d4a0a 100644 (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);
   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 = {