#define _GNU_SOURCE
#include <errno.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include "kselftest_harness.h"
#define SK_NAME "unix_listen_sk"
#define SRV_NAME "unix_listen_srv"
FIXTURE(unix_listen)
{
int sk;
int server;
struct sockaddr_un addr, srv_addr;
socklen_t addrlen, srv_addrlen;
};
FIXTURE_VARIANT(unix_listen)
{
int type;
int abstract;
};
FIXTURE_VARIANT_ADD(unix_listen, stream_pathname)
{
.type = SOCK_STREAM,
.abstract = 0,
};
FIXTURE_VARIANT_ADD(unix_listen, stream_abstract)
{
.type = SOCK_STREAM,
.abstract = 1,
};
FIXTURE_VARIANT_ADD(unix_listen, seqpacket_pathname)
{
.type = SOCK_SEQPACKET,
.abstract = 0,
};
FIXTURE_VARIANT_ADD(unix_listen, seqpacket_abstract)
{
.type = SOCK_SEQPACKET,
.abstract = 1,
};
static socklen_t unix_set_addr(struct sockaddr_un *addr, const char *name,
int abstract)
{
size_t len = strlen(name);
memset(addr, 0, sizeof(*addr));
addr->sun_family = AF_UNIX;
memcpy(addr->sun_path + (abstract ? 1 : 0), name, len);
return offsetof(struct sockaddr_un, sun_path) + len + 1;
}
FIXTURE_SETUP(unix_listen)
{
self->sk = -1;
self->server = -1;
self->addrlen = unix_set_addr(&self->addr, SK_NAME, variant->abstract);
self->srv_addrlen = unix_set_addr(&self->srv_addr, SRV_NAME,
variant->abstract);
}
FIXTURE_TEARDOWN(unix_listen)
{
if (self->sk >= 0)
close(self->sk);
if (self->server >= 0)
close(self->server);
if (!variant->abstract) {
remove(SK_NAME);
remove(SRV_NAME);
}
}
TEST_F(unix_listen, bound_is_ok)
{
int err;
self->sk = socket(AF_UNIX, variant->type, 0);
ASSERT_LE(0, self->sk);
err = bind(self->sk, (struct sockaddr *)&self->addr, self->addrlen);
ASSERT_EQ(0, err);
err = listen(self->sk, 8);
EXPECT_EQ(0, err);
}
TEST_F(unix_listen, relisten_is_ok)
{
int err;
self->sk = socket(AF_UNIX, variant->type, 0);
ASSERT_LE(0, self->sk);
err = bind(self->sk, (struct sockaddr *)&self->addr, self->addrlen);
ASSERT_EQ(0, err);
err = listen(self->sk, 8);
ASSERT_EQ(0, err);
err = listen(self->sk, 16);
EXPECT_EQ(0, err);
}
TEST_F(unix_listen, unbound_is_einval)
{
int err;
self->sk = socket(AF_UNIX, variant->type, 0);
ASSERT_LE(0, self->sk);
err = listen(self->sk, 8);
EXPECT_EQ(-1, err);
EXPECT_EQ(EINVAL, errno);
}
TEST_F(unix_listen, connected_is_einval)
{
int err;
self->server = socket(AF_UNIX, variant->type, 0);
ASSERT_LE(0, self->server);
err = bind(self->server, (struct sockaddr *)&self->srv_addr,
self->srv_addrlen);
ASSERT_EQ(0, err);
err = listen(self->server, 8);
ASSERT_EQ(0, err);
self->sk = socket(AF_UNIX, variant->type, 0);
ASSERT_LE(0, self->sk);
err = bind(self->sk, (struct sockaddr *)&self->addr, self->addrlen);
ASSERT_EQ(0, err);
err = connect(self->sk, (struct sockaddr *)&self->srv_addr,
self->srv_addrlen);
ASSERT_EQ(0, err);
err = listen(self->sk, 8);
EXPECT_EQ(-1, err);
EXPECT_EQ(EINVAL, errno);
}
TEST_HARNESS_MAIN