#include <sys/cdefs.h>
#ifdef __NetBSD__
__RCSID("$NetBSD: t_socket_afinet.c,v 1.2 2022/11/17 08:34:39 ozaki-r Exp $");
#define USE_RUMPKERNEL 1
#else
__FBSDID("$FreeBSD$");
#endif
#include <sys/errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <poll.h>
#include <atf-c.h>
#ifdef USE_RUMPKERNEL
#include <rump/rump.h>
#include <rump/rump_syscalls.h>
#define socket rump_sys_socket
#define bind rump_sys_bind
#define listen rump_sys_listen
#define connect rump_sys_connect
#define write rump_sys_write
#define poll rump_sys_poll
#define close rump_sys_close
#define RUMP_INIT() rump_init()
#else
#define RUMP_INIT() do { } while (0)
#endif
ATF_TC_WITHOUT_HEAD(socket_afinet);
ATF_TC_BODY(socket_afinet, tc)
{
int sd;
RUMP_INIT();
sd = socket(PF_INET, SOCK_DGRAM, 0);
ATF_CHECK(sd >= 0);
close(sd);
}
ATF_TC_WITHOUT_HEAD(socket_afinet_bind_zero);
ATF_TC_BODY(socket_afinet_bind_zero, tc)
{
int sd, rc;
struct sockaddr_in sin;
RUMP_INIT();
#ifdef __NetBSD__
atf_tc_expect_fail("NetBSD doesn't allow sin_family == 0 (sin_len == 0 too)");
#endif
if (atf_tc_get_config_var_as_bool_wd(tc, "ci", false))
atf_tc_skip("doesn't work when mac_portacl(4) loaded (https://bugs.freebsd.org/238781)");
sd = socket(PF_INET, SOCK_DGRAM, 0);
ATF_CHECK(sd >= 0);
bzero(&sin, sizeof(sin));
rc = bind(sd, (struct sockaddr *)&sin, sizeof(sin));
ATF_CHECK_EQ(0, rc);
close(sd);
}
ATF_TC_WITHOUT_HEAD(socket_afinet_bind_ok);
ATF_TC_BODY(socket_afinet_bind_ok, tc)
{
int sd, rc;
struct sockaddr_in sin;
RUMP_INIT();
sd = socket(PF_INET, SOCK_DGRAM, 0);
ATF_CHECK(sd >= 0);
bzero(&sin, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_len = sizeof(sin);
sin.sin_port = htons(6666);
sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
rc = bind(sd, (struct sockaddr *)&sin, sizeof(sin));
ATF_CHECK_EQ(0, rc);
close(sd);
}
#ifdef POLLRDHUP
ATF_TC_WITHOUT_HEAD(socket_afinet_poll_no_rdhup);
ATF_TC_BODY(socket_afinet_poll_no_rdhup, tc)
{
int ss, ss2, cs, rc;
struct sockaddr_in sin;
struct pollfd pfd;
int one = 1;
RUMP_INIT();
ss = socket(PF_INET, SOCK_STREAM, 0);
ATF_CHECK(ss >= 0);
rc = setsockopt(ss, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one));
ATF_CHECK_EQ(0, rc);
bzero(&sin, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_len = sizeof(sin);
sin.sin_port = htons(6666);
sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
rc = bind(ss, (struct sockaddr *)&sin, sizeof(sin));
ATF_CHECK_EQ(0, rc);
rc = listen(ss, 1);
ATF_CHECK_EQ(0, rc);
cs = socket(PF_INET, SOCK_STREAM, 0);
ATF_CHECK(cs >= 0);
rc = connect(cs, (struct sockaddr *)&sin, sizeof(sin));
ATF_CHECK_EQ(0, rc);
ss2 = accept(ss, NULL, NULL);
ATF_CHECK(ss2 >= 0);
pfd.fd = ss2;
pfd.events = POLLIN | POLLOUT;
rc = poll(&pfd, 1, 0);
ATF_CHECK_EQ(1, rc);
ATF_CHECK_EQ(POLLOUT, pfd.revents);
rc = close(cs);
ATF_CHECK_EQ(0, rc);
pfd.fd = ss2;
pfd.events = POLLIN;
rc = poll(&pfd, 1, 60000);
ATF_CHECK_EQ(1, rc);
ATF_CHECK_EQ(POLLIN, pfd.revents);
close(ss2);
close(ss);
}
ATF_TC_WITHOUT_HEAD(socket_afinet_poll_rdhup);
ATF_TC_BODY(socket_afinet_poll_rdhup, tc)
{
int ss, ss2, cs, rc;
struct sockaddr_in sin;
struct pollfd pfd;
char buffer;
int one = 1;
RUMP_INIT();
ss = socket(PF_INET, SOCK_STREAM, 0);
ATF_CHECK(ss >= 0);
rc = setsockopt(ss, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one));
ATF_CHECK_EQ(0, rc);
bzero(&sin, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_len = sizeof(sin);
sin.sin_port = htons(6666);
sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
rc = bind(ss, (struct sockaddr *)&sin, sizeof(sin));
ATF_CHECK_EQ(0, rc);
rc = listen(ss, 1);
ATF_CHECK_EQ(0, rc);
cs = socket(PF_INET, SOCK_STREAM, 0);
ATF_CHECK(cs >= 0);
rc = connect(cs, (struct sockaddr *)&sin, sizeof(sin));
ATF_CHECK_EQ(0, rc);
ss2 = accept(ss, NULL, NULL);
ATF_CHECK(ss2 >= 0);
pfd.fd = ss2;
pfd.events = POLLIN | POLLOUT | POLLRDHUP;
rc = poll(&pfd, 1, 0);
ATF_CHECK_EQ(1, rc);
ATF_CHECK_EQ(POLLOUT, pfd.revents);
rc = write(cs, "xx", 2);
ATF_CHECK_EQ(2, rc);
rc = read(ss2, &buffer, 1);
ATF_CHECK_EQ(1, rc);
pfd.fd = ss2;
pfd.events = POLLIN | POLLOUT | POLLRDHUP;
rc = poll(&pfd, 1, 0);
ATF_CHECK_EQ(1, rc);
ATF_CHECK_EQ(POLLIN | POLLOUT, pfd.revents);
rc = close(cs);
ATF_CHECK_EQ(0, rc);
pfd.fd = ss2;
pfd.events = POLLRDHUP;
rc = poll(&pfd, 1, 60000);
ATF_CHECK_EQ(1, rc);
ATF_CHECK_EQ(POLLRDHUP, pfd.revents);
close(ss2);
close(ss);
}
#endif
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, socket_afinet);
ATF_TP_ADD_TC(tp, socket_afinet_bind_zero);
ATF_TP_ADD_TC(tp, socket_afinet_bind_ok);
#ifdef POLLRDHUP
ATF_TP_ADD_TC(tp, socket_afinet_poll_no_rdhup);
ATF_TP_ADD_TC(tp, socket_afinet_poll_rdhup);
#endif
return atf_no_error();
}