#include <errno.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <linux/rds.h>
#include "../../kselftest_harness.h"
#ifndef AF_RDS
#define AF_RDS 21
#endif
FIXTURE(rds) {
int fd;
};
FIXTURE_SETUP(rds)
{
self->fd = socket(AF_RDS, SOCK_SEQPACKET, 0);
if (self->fd < 0)
SKIP(return, "AF_RDS unavailable (errno %d) - load the rds module",
errno);
}
FIXTURE_TEARDOWN(rds)
{
if (self->fd >= 0)
close(self->fd);
}
TEST_F(rds, recverr_default)
{
socklen_t len = sizeof(int);
int val = 0xdeadbeef;
ASSERT_EQ(0, getsockopt(self->fd, SOL_RDS, RDS_RECVERR, &val, &len));
EXPECT_EQ(sizeof(int), len);
EXPECT_EQ(0, val);
}
TEST_F(rds, recverr_set_get)
{
socklen_t len = sizeof(int);
int val = 1;
ASSERT_EQ(0, setsockopt(self->fd, SOL_RDS, RDS_RECVERR, &val, len));
val = 0;
ASSERT_EQ(0, getsockopt(self->fd, SOL_RDS, RDS_RECVERR, &val, &len));
EXPECT_EQ(sizeof(int), len);
EXPECT_EQ(1, val);
}
TEST_F(rds, recverr_short_buffer)
{
socklen_t len = sizeof(int) - 1;
char buf[sizeof(int)];
EXPECT_EQ(-1, getsockopt(self->fd, SOL_RDS, RDS_RECVERR, buf, &len));
EXPECT_EQ(EINVAL, errno);
}
TEST_F(rds, transport_unbound)
{
socklen_t len = sizeof(int);
int val = 0;
ASSERT_EQ(0, getsockopt(self->fd, SOL_RDS, SO_RDS_TRANSPORT, &val,
&len));
EXPECT_EQ(sizeof(int), len);
EXPECT_EQ(RDS_TRANS_NONE, (unsigned int)val);
}
TEST_F(rds, transport_short_buffer)
{
socklen_t len = sizeof(int) - 1;
char buf[sizeof(int)];
EXPECT_EQ(-1, getsockopt(self->fd, SOL_RDS, SO_RDS_TRANSPORT, buf,
&len));
EXPECT_EQ(EINVAL, errno);
}
TEST_F(rds, info_counters_probe)
{
socklen_t len = 0;
EXPECT_EQ(-1, getsockopt(self->fd, SOL_RDS, RDS_INFO_COUNTERS, NULL,
&len));
EXPECT_EQ(ENOSPC, errno);
EXPECT_GT(len, 0);
EXPECT_EQ(0, len % (socklen_t)sizeof(struct rds_info_counter));
}
TEST_F(rds, info_counters_snapshot)
{
struct rds_info_counter *ctr;
socklen_t need = 0, len;
long pagesz = sysconf(_SC_PAGESIZE);
size_t offset, map_len;
unsigned int i, n;
char *region, *buf;
int ret;
getsockopt(self->fd, SOL_RDS, RDS_INFO_COUNTERS, NULL, &need);
ASSERT_GT(need, 0);
offset = pagesz - 64;
map_len = ((offset + need + pagesz - 1) / pagesz) * pagesz;
region = mmap(NULL, map_len, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
ASSERT_NE(MAP_FAILED, region);
buf = region + offset;
len = need;
ret = getsockopt(self->fd, SOL_RDS, RDS_INFO_COUNTERS, buf, &len);
ASSERT_GE(ret, 0) {
TH_LOG("getsockopt snapshot failed: errno %d", errno);
}
EXPECT_EQ(sizeof(struct rds_info_counter), ret);
EXPECT_EQ(need, len);
ctr = (struct rds_info_counter *)buf;
n = len / sizeof(*ctr);
ASSERT_GT(n, 0);
for (i = 0; i < n; i++) {
size_t namelen = strnlen((char *)ctr[i].name,
sizeof(ctr[i].name));
EXPECT_GT(namelen, 0);
EXPECT_LT(namelen, sizeof(ctr[i].name));
}
munmap(region, map_len);
}
TEST_F(rds, info_counters_short_buffer)
{
socklen_t need = 0, len;
char small[sizeof(struct rds_info_counter)];
getsockopt(self->fd, SOL_RDS, RDS_INFO_COUNTERS, NULL, &need);
ASSERT_GT(need, 0);
if (need <= (socklen_t)sizeof(small))
SKIP(return, "snapshot fits in one record; nothing to test");
len = 1;
EXPECT_EQ(-1, getsockopt(self->fd, SOL_RDS, RDS_INFO_COUNTERS, small,
&len));
EXPECT_EQ(ENOSPC, errno);
EXPECT_EQ(need, len);
}
TEST_HARNESS_MAIN