socketpair: cleaner interface

Declutter the ifdefs in socketpair.h. Introduce Curl_wakeup_*()
function that encapsulate the details about how the socketpair
is implemented.

This moves the EVENTFD specials from the using code into socketpair
implemenatation, avoiding duplications in three places.

Closes #20340
This commit is contained in:
Stefan Eissing 2026-01-16 13:59:03 +01:00 committed by Daniel Stenberg
parent 1a57302d1a
commit 6c8956c1cb
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
4 changed files with 144 additions and 138 deletions

View file

@ -28,11 +28,14 @@
#include "rand.h"
#include "curlx/nonblock.h"
#ifndef CURL_DISABLE_SOCKETPAIR
/* choose implementation */
#ifdef USE_EVENTFD
#include <sys/eventfd.h>
int Curl_eventfd(curl_socket_t socks[2], bool nonblocking)
static int wakeup_eventfd(curl_socket_t socks[2], bool nonblocking)
{
int efd = eventfd(0, nonblocking ? EFD_CLOEXEC | EFD_NONBLOCK : EFD_CLOEXEC);
if(efd == -1) {
@ -49,7 +52,7 @@ int Curl_eventfd(curl_socket_t socks[2], bool nonblocking)
#include <fcntl.h>
#endif
int Curl_pipe(curl_socket_t socks[2], bool nonblocking)
static int wakeup_pipe(curl_socket_t socks[2], bool nonblocking)
{
#ifdef HAVE_PIPE2
int flags = nonblocking ? O_NONBLOCK | O_CLOEXEC : O_CLOEXEC;
@ -81,18 +84,24 @@ int Curl_pipe(curl_socket_t socks[2], bool nonblocking)
return 0;
}
#endif /* USE_EVENTFD */
#elif defined(HAVE_SOCKETPAIR) /* !USE_EVENTFD && !HAVE_PIPE */
#ifndef CURL_DISABLE_SOCKETPAIR
#ifdef HAVE_SOCKETPAIR
#ifdef USE_SOCKETPAIR
int Curl_socketpair(int domain, int type, int protocol,
curl_socket_t socks[2], bool nonblocking)
{
#ifdef SOCK_NONBLOCK
type = nonblocking ? type | SOCK_NONBLOCK : type;
#ifndef USE_UNIX_SOCKETS
#error "unsupported Unix domain and socketpair build combo"
#endif
if(CURL_SOCKETPAIR(domain, type, protocol, socks))
static int wakeup_socketpair(curl_socket_t socks[2], bool nonblocking)
{
int type = SOCK_STREAM;
#ifdef SOCK_CLOEXEC
type |= SOCK_CLOEXEC;
#endif
#ifdef SOCK_NONBLOCK
if(nonblocking)
type |= SOCK_NONBLOCK;
#endif
if(CURL_SOCKETPAIR(AF_UNIX, type, 0, socks))
return -1;
#ifndef SOCK_NONBLOCK
if(nonblocking) {
@ -106,8 +115,8 @@ int Curl_socketpair(int domain, int type, int protocol,
#endif
return 0;
}
#endif /* USE_SOCKETPAIR */
#else /* !HAVE_SOCKETPAIR */
#else /* !USE_EVENTFD && !HAVE_PIPE && !HAVE_SOCKETPAIR */
#ifdef HAVE_NETDB_H
#include <netdb.h>
@ -125,8 +134,7 @@ int Curl_socketpair(int domain, int type, int protocol,
#include "select.h" /* for Curl_poll */
int Curl_socketpair(int domain, int type, int protocol,
curl_socket_t socks[2], bool nonblocking)
static int wakeup_inet(curl_socket_t socks[2], bool nonblocking)
{
union {
struct sockaddr_in inaddr;
@ -136,9 +144,6 @@ int Curl_socketpair(int domain, int type, int protocol,
curl_socklen_t addrlen = sizeof(a.inaddr);
int reuse = 1;
struct pollfd pfd[1];
(void)domain;
(void)type;
(void)protocol;
listener = CURL_SOCKET(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(listener == CURL_SOCKET_BAD)
@ -257,5 +262,99 @@ error:
sclose(socks[1]);
return -1;
}
#endif /* choose implementation */
int Curl_wakeup_init(curl_socket_t socks[2], bool nonblocking)
{
#ifdef USE_EVENTFD
return wakeup_eventfd(socks, nonblocking);
#elif defined(HAVE_PIPE)
return wakeup_pipe(socks, nonblocking);
#elif defined(HAVE_SOCKETPAIR)
return wakeup_socketpair(socks, nonblocking);
#else
return wakeup_inet(socks, nonblocking);
#endif
}
#if defined(USE_EVENTFD) || defined(HAVE_PIPE)
#define wakeup_write write
#define wakeup_read read
#define wakeup_close close
#else /* !USE_EVENTFD && !HAVE_PIPE */
#define wakeup_write swrite
#define wakeup_read sread
#define wakeup_close sclose
#endif
int Curl_wakeup_signal(curl_socket_t socks[2])
{
int err = 0;
#ifdef USE_EVENTFD
const uint64_t buf[1] = { 1 };
#else
const char buf[1] = { 1 };
#endif
while(1) {
if(wakeup_write(socks[1], buf, sizeof(buf)) < 0) {
err = SOCKERRNO;
#ifdef USE_WINSOCK
if(err == SOCKEWOULDBLOCK)
err = 0; /* wakeup is already ongoing */
#else
if(SOCKEINTR == err)
continue;
if((err == SOCKEWOULDBLOCK) || (err == EAGAIN))
err = 0; /* wakeup is already ongoing */
#endif
}
break;
}
return err;
}
CURLcode Curl_wakeup_consume(curl_socket_t socks[2], bool all)
{
char buf[64];
ssize_t rc;
CURLcode result = CURLE_OK;
do {
rc = wakeup_read(socks[0], buf, sizeof(buf));
if(!rc)
break;
else if(rc < 0) {
#ifdef USE_WINSOCK
if(SOCKERRNO == SOCKEWOULDBLOCK)
break;
#else
if(SOCKEINTR == SOCKERRNO)
continue;
if((SOCKERRNO == SOCKEWOULDBLOCK) || (SOCKERRNO == EAGAIN))
break;
#endif
result = CURLE_READ_ERROR;
break;
}
} while(all);
return result;
}
void Curl_wakeup_destroy(curl_socket_t socks[2])
{
#ifndef USE_EVENTFD
if(socks[1] != CURL_SOCKET_BAD)
wakeup_close(socks[1]);
#endif
if(socks[0] != CURL_SOCKET_BAD)
wakeup_close(socks[0]);
socks[0] = socks[1] = CURL_SOCKET_BAD;
}
#endif /* !CURL_DISABLE_SOCKETPAIR */