]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
socket: use accept4 when available
authorAndy Pan <i@andypan.me>
Sat, 5 Apr 2025 15:55:32 +0000 (23:55 +0800)
committerDaniel Stenberg <daniel@haxx.se>
Sun, 6 Apr 2025 11:08:33 +0000 (13:08 +0200)
Linux, *BSD, and Solaris support accept4 system call that enables the
caller to assign additional flags and save some extra system calls. It
can come in handy when O_NONBLOCK or/and FD_CLOEXEC is/are required on a
socket after being accepted.

Ref:
https://man7.org/linux/man-pages/man2/accept.2.html
https://man.freebsd.org/cgi/man.cgi?query=accept4
https://man.dragonflybsd.org/?command=accept&section=2
https://man.openbsd.org/accept.2
https://man.netbsd.org/accept.2
https://docs.oracle.com/cd/E88353_01/html/E37843/accept4-3c.html
https://www.gnu.org/software/gnulib/manual/html_node/accept4.html

Closes #16979

CMake/unix-cache.cmake
CMake/win32-cache.cmake
CMakeLists.txt
configure.ac
lib/cf-socket.c
lib/curl_config.h.cmake
lib/memdebug.c
lib/memdebug.h

index f76c639149b6a22e2a88e654027e38119d5d2f2a..d97709bcf0b3b8cecf17b0119636b961fa4bb3de 100644 (file)
@@ -26,6 +26,15 @@ if(NOT UNIX)
   message(FATAL_ERROR "This file should be included on Unix platforms only")
 endif()
 
+if(APPLE OR
+   CYGWIN)
+  set(HAVE_ACCEPT4 0)
+elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux" OR
+       CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR
+       CMAKE_SYSTEM_NAME STREQUAL "NetBSD" OR
+       CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")
+  set(HAVE_ACCEPT4 1)
+endif()
 set(HAVE_ALARM 1)
 if(ANDROID)
   set(HAVE_ARC4RANDOM 1)
index ee2d9f9d3b0a856a08933239acac401f26e8aba6..aac0678e75a802b989a9b88b9c832fa376e6b73f 100644 (file)
@@ -85,6 +85,7 @@ else()
   set(HAVE_ATOMIC 0)
 endif()
 
+set(HAVE_ACCEPT4 0)
 set(HAVE_ALARM 0)
 set(HAVE_ARC4RANDOM 0)
 set(HAVE_ARPA_INET_H 0)
index 7052e1c51da647ae42dec9adea22e5bef19b687a..38c7847a32788ccbec094a076cd7bb4b8f975457 100644 (file)
@@ -282,7 +282,7 @@ endif()
 include(PickyWarnings)
 
 if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
-  string(APPEND CMAKE_C_FLAGS " -D_GNU_SOURCE")  # Required for sendmmsg()
+  string(APPEND CMAKE_C_FLAGS " -D_GNU_SOURCE")  # Required for sendmmsg() and accept4()
 endif()
 
 option(ENABLE_DEBUG "Enable curl debug features (for developing curl itself)" OFF)
@@ -1732,6 +1732,7 @@ elseif(DOS)
   list(APPEND CMAKE_REQUIRED_LIBRARIES "${WATT_ROOT}/lib/libwatt.a")
 endif()
 
+check_function_exists("accept4"       HAVE_ACCEPT4)
 check_function_exists("fnmatch"       HAVE_FNMATCH)
 check_symbol_exists("basename"        "${CURL_INCLUDES};string.h" HAVE_BASENAME)  # libgen.h unistd.h
 check_symbol_exists("opendir"         "dirent.h" HAVE_OPENDIR)
index 311d2853e67566d38dd0fcbf39990b33196412ee..fde12e559f89f6a809ebe1bde188206f1a0e8988 100644 (file)
@@ -574,7 +574,7 @@ esac
 
 AM_CONDITIONAL(BUILD_UNITTESTS, test x$supports_unittests = xyes)
 
-# In order to detect support of sendmmsg(), we need to escape the POSIX
+# In order to detect support of sendmmsg() and accept4(), we need to escape the POSIX
 # jail by defining _GNU_SOURCE or <sys/socket.h> will not expose it.
 case $host_os in
   linux*)
@@ -4112,6 +4112,7 @@ case $host in
 esac
 
 AC_CHECK_FUNCS([\
+  accept4 \
   eventfd \
   fnmatch \
   geteuid \
index eeea77aceccb3c26d3d6943df51e2dd195fcddb0..4bc57b85720e193374e2c4ad04de338990d032c6 100644 (file)
@@ -2144,7 +2144,12 @@ static CURLcode cf_tcp_accept_connect(struct Curl_cfilter *cf,
 
   if(0 == getsockname(ctx->sock, (struct sockaddr *) &add, &size)) {
     size = sizeof(add);
+#ifdef HAVE_ACCEPT4
+    s_accepted = accept4(ctx->sock, (struct sockaddr *) &add, &size,
+                         SOCK_NONBLOCK | SOCK_CLOEXEC);
+#else
     s_accepted = accept(ctx->sock, (struct sockaddr *) &add, &size);
+#endif
   }
 
   if(CURL_SOCKET_BAD == s_accepted) {
@@ -2153,7 +2158,9 @@ static CURLcode cf_tcp_accept_connect(struct Curl_cfilter *cf,
   }
 
   infof(data, "Connection accepted from server");
+#ifndef HAVE_ACCEPT4
   (void)curlx_nonblock(s_accepted, TRUE); /* enable non-blocking */
+#endif
   /* Replace any filter on SECONDARY with one listening on this socket */
   ctx->listening = FALSE;
   ctx->accepted = TRUE;
index e78747e668cba32bf678049a904dbf007f5d8919..12d513cce995754d12db378606fa39af3064946d 100644 (file)
 /* Define to 1 if you have _Atomic support. */
 #cmakedefine HAVE_ATOMIC 1
 
+/* Define to 1 if you have the `accept4' function. */
+#cmakedefine HAVE_ACCEPT4 1
+
 /* Define to 1 if you have the `fnmatch' function. */
 #cmakedefine HAVE_FNMATCH 1
 
index 58e4614f5f0a2b9896299f0b62634c5c3907ec53..b351726b320da393cfc57507697719457d4b91f3 100644 (file)
@@ -378,6 +378,24 @@ curl_socket_t curl_dbg_accept(curl_socket_t s, void *saddr, void *saddrlen,
   return sockfd;
 }
 
+#ifdef HAVE_ACCEPT4
+curl_socket_t curl_dbg_accept4(curl_socket_t s, void *saddr, void *saddrlen,
+                               int flags,
+                               int line, const char *source)
+{
+  struct sockaddr *addr = (struct sockaddr *)saddr;
+  curl_socklen_t *addrlen = (curl_socklen_t *)saddrlen;
+
+  curl_socket_t sockfd = accept4(s, addr, addrlen, flags);
+
+  if(source && (sockfd != CURL_SOCKET_BAD))
+    curl_dbg_log("FD %s:%d accept() = %" FMT_SOCKET_T "\n",
+                 source, line, sockfd);
+
+  return sockfd;
+}
+#endif
+
 /* separate function to allow libcurl to mark a "faked" close */
 void curl_dbg_mark_sclose(curl_socket_t sockfd, int line, const char *source)
 {
index aabcaadef489fe78371b5388744adbc693090471..11b250dea233df614baa28ab224f3c445b443d5e 100644 (file)
@@ -92,6 +92,11 @@ CURL_EXTERN int curl_dbg_sclose(curl_socket_t sockfd,
                                 int line, const char *source);
 CURL_EXTERN curl_socket_t curl_dbg_accept(curl_socket_t s, void *a, void *alen,
                                           int line, const char *source);
+#ifdef HAVE_ACCEPT4
+CURL_EXTERN curl_socket_t curl_dbg_accept4(curl_socket_t s, void *saddr,
+                                           void *saddrlen, int flags,
+                                           int line, const char *source);
+#endif
 #ifdef HAVE_SOCKETPAIR
 CURL_EXTERN int curl_dbg_socketpair(int domain, int type, int protocol,
                                     curl_socket_t socket_vector[2],
@@ -159,6 +164,11 @@ CURL_EXTERN ALLOC_FUNC
 #undef accept /* for those with accept as a macro */
 #define accept(sock,addr,len)\
  curl_dbg_accept(sock, addr, len, __LINE__, __FILE__)
+#ifdef HAVE_ACCEPT4
+#undef accept4 /* for those with accept4 as a macro */
+#define accept4(sock,addr,len,flags)\
+ curl_dbg_accept4(sock, addr, len, flags, __LINE__, __FILE__)
+#endif
 #ifdef HAVE_SOCKETPAIR
 #define socketpair(domain,type,protocol,socket_vector)\
  curl_dbg_socketpair((int)domain, type, protocol, socket_vector, \