]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
tool_cb_rea: use poll instead of select if available
authorDaniel Stenberg <daniel@haxx.se>
Sun, 19 Oct 2025 13:59:09 +0000 (15:59 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Sun, 19 Oct 2025 21:59:37 +0000 (23:59 +0200)
- poll doesn't have the FD_SETSIZE problem

- select: if socket >= FD_SETSIZE, skip the call

Closes #19143

src/tool_cb_rea.c

index b7bd9a72273215b84de3a1db37468382414dc3af..b5c6143845212b2a1068273a1f4b74b054233d9b 100644 (file)
 #ifdef HAVE_SYS_SELECT_H
 #include <sys/select.h>
 #endif
+#ifdef HAVE_POLL_H
+#include <poll.h>
+#elif defined(HAVE_SYS_POLL_H)
+#include <sys/poll.h>
+#endif
 
 #include "tool_cfgable.h"
 #include "tool_cb_rea.h"
 
 #include "memdebug.h" /* keep this as LAST include */
 
+#ifndef _WIN32
+/* Wait up to a number of milliseconds for socket activity. This function
+   waits on read activity on a file descriptor that is not a socket which
+   makes it not work with select() or poll() on Windows. */
+static bool waitfd(int waitms, int fd)
+{
+#ifdef HAVE_POLL
+  struct pollfd set;
+
+  set.fd = fd;
+  set.events = POLLIN;
+  set.revents = 0;
+  if(poll(&set, 1, (int)waitms))
+    return TRUE; /* timeout */
+  return FALSE;
+#else
+  fd_set bits;
+  struct timeval timeout;
+
+  if(fd >= FD_SETSIZE)
+    /* can't wait! */
+    return FALSE;
+
+  /* wait this long at the most */
+  timeout.tv_sec = waitms / 1000;
+  timeout.tv_usec = (int)((waitms % 1000) * 1000);
+
+  FD_ZERO(&bits);
+#ifdef __DJGPP__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Warith-conversion"
+#endif
+  FD_SET(fd, &bits);
+#ifdef __DJGPP__
+#pragma GCC diagnostic pop
+#endif
+  if(!select(fd + 1, &bits, NULL, NULL, &timeout))
+    return TRUE; /* timeout */
+  return FALSE;
+#endif
+}
+#endif
+
 /*
 ** callback for CURLOPT_READFUNCTION
 */
@@ -59,28 +107,11 @@ size_t tool_read_cb(char *buffer, size_t sz, size_t nmemb, void *userdata)
       /* timeout */
       return 0;
 #ifndef _WIN32
-    /* this logic waits on read activity on a file descriptor that is not a
-       socket which makes it not work with select() on Windows */
     else {
-      fd_set bits;
-      struct timeval timeout;
-      long wait = config->timeout_ms - msdelta;
-
-      /* wait this long at the most */
-      timeout.tv_sec = wait/1000;
-      timeout.tv_usec = (int)((wait%1000)*1000);
-
-      FD_ZERO(&bits);
-#ifdef __DJGPP__
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Warith-conversion"
-#endif
-      FD_SET(per->infd, &bits);
-#ifdef __DJGPP__
-#pragma GCC diagnostic pop
-#endif
-      if(!select(per->infd + 1, &bits, NULL, NULL, &timeout))
-        return 0; /* timeout */
+      long w = config->timeout_ms - msdelta;
+      if(w > INT_MAX)
+        w = INT_MAX;
+      waitfd((int)w, per->infd);
     }
 #endif
   }
@@ -154,22 +185,7 @@ int tool_readbusy_cb(void *clientp,
   if(config->readbusy) {
     if(ulprev == ulnow) {
 #ifndef _WIN32
-      fd_set bits;
-      struct timeval timeout;
-      /* wait this long at the most */
-      timeout.tv_sec = 0;
-      timeout.tv_usec = 1000;
-
-      FD_ZERO(&bits);
-#ifdef __DJGPP__
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Warith-conversion"
-#endif
-      FD_SET(per->infd, &bits);
-#ifdef __DJGPP__
-#pragma GCC diagnostic pop
-#endif
-      select(per->infd + 1, &bits, NULL, NULL, &timeout);
+      waitfd(1, per->infd);
 #else
       /* sleep */
       curlx_wait_ms(1);