* Copyright (C) 2024 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
*/
* This test verifies the following shutdown() functionalities:
*
* - SHUT_RD should enable send() ops but disable recv() ops
* - SHUT_WR should enable recv() ops but disable send() ops
* - SHUT_RDWR should disable both recv() and send() ops
*/
#include "tst_test.h"
#include "tst_safe_net.h"
#define MSGSIZE 4
#define SOCKETFILE "socket"
#define OP_DESC(x) .shutdown_op = x, .desc = #x
static struct tcase {
int shutdown_op;
int recv_flag;
int recv_err;
int send_flag;
int send_err;
char *desc;
} tcases[] = {
{OP_DESC(SHUT_RD)},
{OP_DESC(SHUT_WR), .recv_flag = MSG_DONTWAIT, .recv_err = EWOULDBLOCK,
.send_flag = MSG_NOSIGNAL, .send_err = EPIPE},
{OP_DESC(SHUT_RDWR), .send_flag = MSG_NOSIGNAL, .send_err = EPIPE}
};
static struct sockaddr_un *sock_addr;
static void run_server(void)
{
int server_sock;
server_sock = SAFE_SOCKET(sock_addr->sun_family, SOCK_STREAM, 0);
SAFE_BIND(server_sock,
(struct sockaddr *)sock_addr,
sizeof(struct sockaddr_un));
SAFE_LISTEN(server_sock, 10);
tst_res(TINFO, "Running server on socket file");
TST_CHECKPOINT_WAKE_AND_WAIT(0);
SAFE_CLOSE(server_sock);
SAFE_UNLINK(SOCKETFILE);
}
static int start_test(void)
{
int client_sock;
if (!SAFE_FORK()) {
run_server();
_exit(0);
}
TST_CHECKPOINT_WAIT(0);
tst_res(TINFO, "Connecting to the server");
client_sock = SAFE_SOCKET(sock_addr->sun_family, SOCK_STREAM, 0);
SAFE_CONNECT(client_sock,
(struct sockaddr *)sock_addr,
sizeof(struct sockaddr_un));
return client_sock;
}
static void run(unsigned int n)
{
struct tcase *tc = &tcases[n];
int client_sock;
char buff[MSGSIZE] = {0};
client_sock = start_test();
tst_res(TINFO, "Testing %s flag", tc->desc);
TST_EXP_PASS(shutdown(client_sock, tc->shutdown_op));
if (tc->recv_err)
TST_EXP_FAIL(recv(client_sock, buff, MSGSIZE, tc->recv_flag), tc->recv_err);
else
SAFE_RECV(0, client_sock, buff, MSGSIZE, tc->recv_flag);
if (tc->send_err)
TST_EXP_FAIL(send(client_sock, buff, MSGSIZE, tc->send_flag), tc->send_err);
else
SAFE_SEND(MSGSIZE, client_sock, buff, MSGSIZE, tc->send_flag);
SAFE_CLOSE(client_sock);
TST_CHECKPOINT_WAKE(0);
}
static void setup(void)
{
sock_addr->sun_family = AF_UNIX;
memcpy(sock_addr->sun_path, SOCKETFILE, sizeof(SOCKETFILE));
}
static struct tst_test test = {
.test = run,
.tcnt = ARRAY_SIZE(tcases),
.setup = setup,
.forks_child = 1,
.needs_checkpoints = 1,
.bufs = (struct tst_buffers []) {
{&sock_addr, .size = sizeof(struct sockaddr_un)},
{}
}
};