From: Andy Pan Date: Sat, 5 Apr 2025 15:55:32 +0000 (+0800) Subject: socket: use accept4 when available X-Git-Tag: curl-8_14_0~348 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=3d02872be7cfe6dcdef4b02321b47af19e1ce268;p=thirdparty%2Fcurl.git socket: use accept4 when available 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§ion=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 --- diff --git a/CMake/unix-cache.cmake b/CMake/unix-cache.cmake index f76c639149..d97709bcf0 100644 --- a/CMake/unix-cache.cmake +++ b/CMake/unix-cache.cmake @@ -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) diff --git a/CMake/win32-cache.cmake b/CMake/win32-cache.cmake index ee2d9f9d3b..aac0678e75 100644 --- a/CMake/win32-cache.cmake +++ b/CMake/win32-cache.cmake @@ -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) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7052e1c51d..38c7847a32 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) diff --git a/configure.ac b/configure.ac index 311d2853e6..fde12e559f 100644 --- a/configure.ac +++ b/configure.ac @@ -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 will not expose it. case $host_os in linux*) @@ -4112,6 +4112,7 @@ case $host in esac AC_CHECK_FUNCS([\ + accept4 \ eventfd \ fnmatch \ geteuid \ diff --git a/lib/cf-socket.c b/lib/cf-socket.c index eeea77acec..4bc57b8572 100644 --- a/lib/cf-socket.c +++ b/lib/cf-socket.c @@ -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; diff --git a/lib/curl_config.h.cmake b/lib/curl_config.h.cmake index e78747e668..12d513cce9 100644 --- a/lib/curl_config.h.cmake +++ b/lib/curl_config.h.cmake @@ -197,6 +197,9 @@ /* 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 diff --git a/lib/memdebug.c b/lib/memdebug.c index 58e4614f5f..b351726b32 100644 --- a/lib/memdebug.c +++ b/lib/memdebug.c @@ -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) { diff --git a/lib/memdebug.h b/lib/memdebug.h index aabcaadef4..11b250dea2 100644 --- a/lib/memdebug.h +++ b/lib/memdebug.h @@ -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, \