roken: provide poll fallback
This commit is contained in:
committed by
Nico Williams
parent
6ce504ad84
commit
6efb8b405e
+1
-1
@@ -192,7 +192,6 @@ AC_CHECK_FUNCS([ \
|
||||
mkdtemp \
|
||||
mkostemp \
|
||||
on_exit \
|
||||
poll \
|
||||
random \
|
||||
secure_getenv \
|
||||
setprogname \
|
||||
@@ -360,6 +359,7 @@ AC_BROKEN([ \
|
||||
mergesort \
|
||||
mergesort_r \
|
||||
mkstemp \
|
||||
poll \
|
||||
pread \
|
||||
putenv \
|
||||
rcmd \
|
||||
|
||||
@@ -41,8 +41,6 @@
|
||||
#include <sys/un.h>
|
||||
#endif
|
||||
|
||||
#include <poll.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
@@ -38,6 +38,7 @@ check_PROGRAMS = \
|
||||
parse_bytes-test \
|
||||
parse_reply-test \
|
||||
parse_time-test \
|
||||
poll-test \
|
||||
snprintf-test \
|
||||
strpftime-test \
|
||||
timeval \
|
||||
@@ -282,6 +283,8 @@ EXTRA_DIST = \
|
||||
getline.c \
|
||||
ndbm_wrap.c \
|
||||
ndbm_wrap.h \
|
||||
poll.c \
|
||||
poll-test.c \
|
||||
rename.c \
|
||||
simple_exec_w32.c \
|
||||
sleep.c \
|
||||
|
||||
@@ -90,6 +90,7 @@ libroken_la_OBJS = \
|
||||
$(OBJ)\parse_bytes.obj \
|
||||
$(OBJ)\parse_time.obj \
|
||||
$(OBJ)\parse_units.obj \
|
||||
$(OBJ)\poll.obj \
|
||||
$(OBJ)\pread.obj \
|
||||
$(OBJ)\realloc.obj \
|
||||
$(OBJ)\rename.obj \
|
||||
@@ -214,6 +215,7 @@ TEST_PROGS = \
|
||||
$(OBJ)\parse_bytes-test.exe \
|
||||
$(OBJ)\parse_reply-test.exe \
|
||||
$(OBJ)\parse_time-test.exe \
|
||||
$(OBJ)\poll-test.exe \
|
||||
$(OBJ)\snprintf-test.exe \
|
||||
$(OBJ)\strpftime-test.exe \
|
||||
$(OBJ)\dirent-test.exe \
|
||||
@@ -246,6 +248,9 @@ $(OBJ)\test-readenv.exe: $(OBJ)\test-readenv.obj $(OBJ)\test-mem.obj $(LIBROKEN)
|
||||
$(OBJ)\parse_time-test.exe: $(OBJ)\parse_time-test.obj $(OBJ)\test-mem.obj $(LIBROKEN)
|
||||
$(EXECONLINK)
|
||||
|
||||
$(OBJ)\poll-test.exe: $(OBJ)\poll-test.obj $(LIBROKEN)
|
||||
$(EXECONLINK)
|
||||
|
||||
$(OBJ)\strpftime-test.obj: strpftime-test.c
|
||||
$(C2OBJ) -DTEST_STRPFTIME -DBUILD_ROKEN_LIB
|
||||
|
||||
@@ -307,9 +312,9 @@ test-run:
|
||||
# Need to rewrite this test:
|
||||
# -parse_reply-test.exe
|
||||
-parse_time-test.exe
|
||||
poll-test.exe
|
||||
-snprintf-test.exe
|
||||
-strpftime-test.exe
|
||||
cd $(SRCDIR)
|
||||
|
||||
test:: test-binaries test-run
|
||||
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
#include <config.h>
|
||||
#include <roken.h>
|
||||
|
||||
static void
|
||||
close_pair(rk_socket_t a, rk_socket_t b)
|
||||
{
|
||||
if (!rk_IS_BAD_SOCKET(a))
|
||||
rk_closesocket(a);
|
||||
if (!rk_IS_BAD_SOCKET(b))
|
||||
rk_closesocket(b);
|
||||
}
|
||||
|
||||
static int
|
||||
connected_pair(rk_socket_t *a, rk_socket_t *b)
|
||||
{
|
||||
struct sockaddr_in sin;
|
||||
socklen_t len = sizeof(sin);
|
||||
rk_socket_t ls = rk_INVALID_SOCKET;
|
||||
rk_socket_t cs = rk_INVALID_SOCKET;
|
||||
rk_socket_t as = rk_INVALID_SOCKET;
|
||||
int one = 1;
|
||||
|
||||
memset(&sin, 0, sizeof(sin));
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
sin.sin_port = 0;
|
||||
|
||||
ls = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (rk_IS_BAD_SOCKET(ls))
|
||||
return rk_SOCK_ERRNO;
|
||||
|
||||
setsockopt(ls, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(one));
|
||||
|
||||
if (rk_IS_SOCKET_ERROR(bind(ls, (struct sockaddr *)&sin, sizeof(sin))) ||
|
||||
rk_IS_SOCKET_ERROR(listen(ls, 1)) ||
|
||||
rk_IS_SOCKET_ERROR(getsockname(ls, (struct sockaddr *)&sin, &len))) {
|
||||
int ret = rk_SOCK_ERRNO;
|
||||
rk_closesocket(ls);
|
||||
return ret;
|
||||
}
|
||||
|
||||
cs = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (rk_IS_BAD_SOCKET(cs)) {
|
||||
int ret = rk_SOCK_ERRNO;
|
||||
rk_closesocket(ls);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (rk_IS_SOCKET_ERROR(connect(cs, (struct sockaddr *)&sin, len))) {
|
||||
int ret = rk_SOCK_ERRNO;
|
||||
close_pair(ls, cs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
as = accept(ls, NULL, NULL);
|
||||
if (rk_IS_BAD_SOCKET(as)) {
|
||||
int ret = rk_SOCK_ERRNO;
|
||||
close_pair(ls, cs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
rk_closesocket(ls);
|
||||
*a = as;
|
||||
*b = cs;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
struct pollfd pfd;
|
||||
rk_socket_t a = rk_INVALID_SOCKET;
|
||||
rk_socket_t b = rk_INVALID_SOCKET;
|
||||
char c = 'x';
|
||||
int ret;
|
||||
|
||||
setprogname(argv[0]);
|
||||
|
||||
ret = rk_SOCK_INIT();
|
||||
if (ret)
|
||||
err(1, "rk_SOCK_INIT");
|
||||
|
||||
ret = poll(NULL, 0, 0);
|
||||
if (ret != 0)
|
||||
errx(1, "poll with no fds returned %d", ret);
|
||||
|
||||
ret = connected_pair(&a, &b);
|
||||
if (ret)
|
||||
errx(1, "connected_pair failed: %d", ret);
|
||||
|
||||
pfd.fd = a;
|
||||
pfd.events = POLLIN;
|
||||
pfd.revents = 0;
|
||||
ret = poll(&pfd, 1, 0);
|
||||
if (ret != 0)
|
||||
errx(1, "poll readable before send returned %d", ret);
|
||||
if (pfd.revents != 0)
|
||||
errx(1, "poll timeout left revents as %#x", pfd.revents);
|
||||
|
||||
ret = send(b, &c, 1, 0);
|
||||
if (rk_IS_SOCKET_ERROR(ret))
|
||||
err(1, "send");
|
||||
|
||||
pfd.fd = a;
|
||||
pfd.events = POLLIN;
|
||||
pfd.revents = 0;
|
||||
ret = poll(&pfd, 1, 5000);
|
||||
if (ret != 1)
|
||||
errx(1, "poll readable after send returned %d", ret);
|
||||
if ((pfd.revents & POLLIN) == 0)
|
||||
errx(1, "poll readable missing POLLIN in %#x", pfd.revents);
|
||||
|
||||
ret = recv(a, &c, 1, 0);
|
||||
if (rk_IS_SOCKET_ERROR(ret))
|
||||
err(1, "recv");
|
||||
if (ret != 1)
|
||||
errx(1, "recv returned %d", ret);
|
||||
|
||||
pfd.fd = b;
|
||||
pfd.events = POLLOUT;
|
||||
pfd.revents = 0;
|
||||
ret = poll(&pfd, 1, 5000);
|
||||
if (ret != 1)
|
||||
errx(1, "poll writable returned %d", ret);
|
||||
if ((pfd.revents & POLLOUT) == 0)
|
||||
errx(1, "poll writable missing POLLOUT in %#x", pfd.revents);
|
||||
|
||||
close_pair(a, b);
|
||||
rk_SOCK_EXIT();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
#include <config.h>
|
||||
#include "roken.h"
|
||||
|
||||
#ifndef HAVE_POLL
|
||||
|
||||
#ifdef HAVE_WINSOCK
|
||||
#include <windows.h>
|
||||
|
||||
static int
|
||||
poll_errno_from_winsock(void)
|
||||
{
|
||||
switch (WSAGetLastError()) {
|
||||
case WSAEINTR:
|
||||
return EINTR;
|
||||
case WSAEINVAL:
|
||||
return EINVAL;
|
||||
case WSAENOTSOCK:
|
||||
return EBADF;
|
||||
default:
|
||||
return EIO;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
poll_timeout(int timeout, struct timeval **tvp, struct timeval *tv)
|
||||
{
|
||||
if (timeout < 0) {
|
||||
*tvp = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
tv->tv_sec = timeout / 1000;
|
||||
tv->tv_usec = (timeout % 1000) * 1000;
|
||||
*tvp = tv;
|
||||
}
|
||||
|
||||
ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
|
||||
poll(struct pollfd fds[], nfds_t nfds, int timeout)
|
||||
{
|
||||
struct timeval tv, *tvp;
|
||||
fd_set rfds, wfds, efds;
|
||||
rk_socket_t maxfd = rk_INVALID_SOCKET;
|
||||
int have_rfds = 0, have_wfds = 0, have_efds = 0;
|
||||
int width, ret, nready = 0;
|
||||
nfds_t i;
|
||||
|
||||
if (timeout < -1) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
poll_timeout(timeout, &tvp, &tv);
|
||||
|
||||
FD_ZERO(&rfds);
|
||||
FD_ZERO(&wfds);
|
||||
FD_ZERO(&efds);
|
||||
|
||||
for (i = 0; i < nfds; i++) {
|
||||
short events;
|
||||
|
||||
fds[i].revents = 0;
|
||||
|
||||
if (rk_IS_BAD_SOCKET(fds[i].fd))
|
||||
continue;
|
||||
|
||||
#ifndef NO_LIMIT_FD_SETSIZE
|
||||
if (fds[i].fd >= FD_SETSIZE) {
|
||||
fds[i].revents = POLLNVAL;
|
||||
nready++;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
events = fds[i].events;
|
||||
|
||||
if (events & (POLLIN | POLLPRI)) {
|
||||
FD_SET(fds[i].fd, &rfds);
|
||||
have_rfds = 1;
|
||||
}
|
||||
if (events & POLLOUT) {
|
||||
FD_SET(fds[i].fd, &wfds);
|
||||
have_wfds = 1;
|
||||
}
|
||||
|
||||
FD_SET(fds[i].fd, &efds);
|
||||
have_efds = 1;
|
||||
|
||||
if (maxfd == rk_INVALID_SOCKET || fds[i].fd > maxfd)
|
||||
maxfd = fds[i].fd;
|
||||
}
|
||||
|
||||
if (nready)
|
||||
return nready;
|
||||
|
||||
if (maxfd == rk_INVALID_SOCKET) {
|
||||
#ifdef HAVE_WINSOCK
|
||||
Sleep(timeout < 0 ? INFINITE : (DWORD)timeout);
|
||||
return 0;
|
||||
#else
|
||||
return select(0, NULL, NULL, NULL, tvp);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_WINSOCK
|
||||
width = 0;
|
||||
#else
|
||||
width = maxfd + 1;
|
||||
#endif
|
||||
|
||||
ret = select(width,
|
||||
have_rfds ? &rfds : NULL,
|
||||
have_wfds ? &wfds : NULL,
|
||||
have_efds ? &efds : NULL,
|
||||
tvp);
|
||||
if (rk_IS_SOCKET_ERROR(ret)) {
|
||||
#ifdef HAVE_WINSOCK
|
||||
errno = poll_errno_from_winsock();
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
if (ret == 0)
|
||||
return 0;
|
||||
|
||||
nready = 0;
|
||||
for (i = 0; i < nfds; i++) {
|
||||
short revents = 0;
|
||||
|
||||
if (rk_IS_BAD_SOCKET(fds[i].fd))
|
||||
continue;
|
||||
|
||||
#ifndef NO_LIMIT_FD_SETSIZE
|
||||
if (fds[i].fd >= FD_SETSIZE)
|
||||
continue;
|
||||
#endif
|
||||
|
||||
if (have_rfds && FD_ISSET(fds[i].fd, &rfds))
|
||||
revents |= fds[i].events & (POLLIN | POLLPRI);
|
||||
if (have_wfds && FD_ISSET(fds[i].fd, &wfds))
|
||||
revents |= POLLOUT;
|
||||
if (have_efds && FD_ISSET(fds[i].fd, &efds))
|
||||
revents |= (fds[i].events & POLLPRI) ? POLLPRI : POLLERR;
|
||||
|
||||
fds[i].revents = revents;
|
||||
if (revents)
|
||||
nready++;
|
||||
}
|
||||
|
||||
return nready;
|
||||
}
|
||||
|
||||
#endif /* !HAVE_POLL */
|
||||
@@ -192,6 +192,46 @@ static inline ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL rk_SOCK_INIT(void) {
|
||||
|
||||
#endif /* WinSock */
|
||||
|
||||
#ifdef HAVE_POLL_H
|
||||
#include <poll.h>
|
||||
#else
|
||||
/*
|
||||
* poll(2) compatibility. Windows may provide struct pollfd and the
|
||||
* POLL* constants through winsock2.h even though it has no <poll.h>.
|
||||
*/
|
||||
typedef unsigned long nfds_t;
|
||||
# ifndef POLLIN
|
||||
struct pollfd {
|
||||
rk_socket_t fd;
|
||||
short events;
|
||||
short revents;
|
||||
};
|
||||
# endif
|
||||
# ifndef POLLIN
|
||||
# define POLLIN 0x0001
|
||||
# endif
|
||||
# ifndef POLLPRI
|
||||
# define POLLPRI 0x0002
|
||||
# endif
|
||||
# ifndef POLLOUT
|
||||
# define POLLOUT 0x0004
|
||||
# endif
|
||||
# ifndef POLLERR
|
||||
# define POLLERR 0x0008
|
||||
# endif
|
||||
# ifndef POLLHUP
|
||||
# define POLLHUP 0x0010
|
||||
# endif
|
||||
# ifndef POLLNVAL
|
||||
# define POLLNVAL 0x0020
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_POLL
|
||||
#define poll rk_poll
|
||||
ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL poll(struct pollfd *, nfds_t, int);
|
||||
#endif
|
||||
|
||||
#ifndef IN_LOOPBACKNET
|
||||
#define IN_LOOPBACKNET 127
|
||||
#endif
|
||||
|
||||
@@ -107,6 +107,7 @@ HEIMDAL_ROKEN_2.0 {
|
||||
rk_pid_file_write;
|
||||
rk_pidfile;
|
||||
rk_pipe_execv;
|
||||
rk_poll;
|
||||
rk_print_flags_table;
|
||||
rk_print_time_table;
|
||||
rk_print_units_table;
|
||||
|
||||
Reference in New Issue
Block a user