1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
2f08c3bdfSopenharmony_ci/*
3f08c3bdfSopenharmony_ci * Copyright (C) 2023 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
4f08c3bdfSopenharmony_ci */
5f08c3bdfSopenharmony_ci
6f08c3bdfSopenharmony_ci/*\
7f08c3bdfSopenharmony_ci * [Description]
8f08c3bdfSopenharmony_ci *
9f08c3bdfSopenharmony_ci * Verify that epoll receives EPOLLRDHUP event when we hang a reading
10f08c3bdfSopenharmony_ci * half-socket we are polling on.
11f08c3bdfSopenharmony_ci */
12f08c3bdfSopenharmony_ci
13f08c3bdfSopenharmony_ci#include "tst_test.h"
14f08c3bdfSopenharmony_ci#include "tst_net.h"
15f08c3bdfSopenharmony_ci#include "tst_epoll.h"
16f08c3bdfSopenharmony_ci
17f08c3bdfSopenharmony_cistatic int epfd;
18f08c3bdfSopenharmony_cistatic int sockfd_client;
19f08c3bdfSopenharmony_cistatic int sockfd_server;
20f08c3bdfSopenharmony_cistatic in_port_t *sock_port;
21f08c3bdfSopenharmony_ci
22f08c3bdfSopenharmony_cistatic void create_server(void)
23f08c3bdfSopenharmony_ci{
24f08c3bdfSopenharmony_ci	int sockfd_server;
25f08c3bdfSopenharmony_ci	socklen_t len;
26f08c3bdfSopenharmony_ci	struct sockaddr_in serv_addr;
27f08c3bdfSopenharmony_ci	struct sockaddr_in sin;
28f08c3bdfSopenharmony_ci
29f08c3bdfSopenharmony_ci	tst_init_sockaddr_inet_bin(&serv_addr, INADDR_ANY, 0);
30f08c3bdfSopenharmony_ci
31f08c3bdfSopenharmony_ci	sockfd_server = SAFE_SOCKET(AF_INET, SOCK_STREAM, 0);
32f08c3bdfSopenharmony_ci	SAFE_BIND(sockfd_server, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
33f08c3bdfSopenharmony_ci	SAFE_LISTEN(sockfd_server, 10);
34f08c3bdfSopenharmony_ci
35f08c3bdfSopenharmony_ci	len = sizeof(sin);
36f08c3bdfSopenharmony_ci	memset(&sin, 0, sizeof(struct sockaddr_in));
37f08c3bdfSopenharmony_ci	SAFE_GETSOCKNAME(sockfd_server, (struct sockaddr *)&sin, &len);
38f08c3bdfSopenharmony_ci
39f08c3bdfSopenharmony_ci	*sock_port = ntohs(sin.sin_port);
40f08c3bdfSopenharmony_ci
41f08c3bdfSopenharmony_ci	tst_res(TINFO, "Listening on port %d", *sock_port);
42f08c3bdfSopenharmony_ci
43f08c3bdfSopenharmony_ci	TST_CHECKPOINT_WAKE_AND_WAIT(0);
44f08c3bdfSopenharmony_ci
45f08c3bdfSopenharmony_ci	SAFE_CLOSE(sockfd_server);
46f08c3bdfSopenharmony_ci}
47f08c3bdfSopenharmony_ci
48f08c3bdfSopenharmony_cistatic void run(void)
49f08c3bdfSopenharmony_ci{
50f08c3bdfSopenharmony_ci	struct sockaddr_in client_addr;
51f08c3bdfSopenharmony_ci	struct epoll_event evt_req;
52f08c3bdfSopenharmony_ci	struct epoll_event evt_rec;
53f08c3bdfSopenharmony_ci	int ret;
54f08c3bdfSopenharmony_ci
55f08c3bdfSopenharmony_ci	if (!SAFE_FORK()) {
56f08c3bdfSopenharmony_ci		create_server();
57f08c3bdfSopenharmony_ci		return;
58f08c3bdfSopenharmony_ci	}
59f08c3bdfSopenharmony_ci
60f08c3bdfSopenharmony_ci	TST_CHECKPOINT_WAIT(0);
61f08c3bdfSopenharmony_ci
62f08c3bdfSopenharmony_ci	tst_res(TINFO, "Connecting to port %d", *sock_port);
63f08c3bdfSopenharmony_ci
64f08c3bdfSopenharmony_ci	sockfd_client = SAFE_SOCKET(AF_INET, SOCK_STREAM, 0);
65f08c3bdfSopenharmony_ci
66f08c3bdfSopenharmony_ci	tst_init_sockaddr_inet(&client_addr, "127.0.0.1", *sock_port);
67f08c3bdfSopenharmony_ci
68f08c3bdfSopenharmony_ci	SAFE_CONNECT(sockfd_client,
69f08c3bdfSopenharmony_ci		(struct sockaddr *)&client_addr,
70f08c3bdfSopenharmony_ci		sizeof(client_addr));
71f08c3bdfSopenharmony_ci
72f08c3bdfSopenharmony_ci	tst_res(TINFO, "Polling on socket");
73f08c3bdfSopenharmony_ci
74f08c3bdfSopenharmony_ci	epfd = SAFE_EPOLL_CREATE1(0);
75f08c3bdfSopenharmony_ci	evt_req.events = EPOLLRDHUP;
76f08c3bdfSopenharmony_ci	SAFE_EPOLL_CTL(epfd, EPOLL_CTL_ADD, sockfd_client, &evt_req);
77f08c3bdfSopenharmony_ci
78f08c3bdfSopenharmony_ci	tst_res(TINFO, "Hang socket");
79f08c3bdfSopenharmony_ci
80f08c3bdfSopenharmony_ci	TST_EXP_PASS_SILENT(shutdown(sockfd_client, SHUT_RD));
81f08c3bdfSopenharmony_ci	ret = SAFE_EPOLL_WAIT(epfd, &evt_rec, 1, 2000);
82f08c3bdfSopenharmony_ci	if (ret != 1) {
83f08c3bdfSopenharmony_ci		tst_res(TFAIL, "Wrong number of events reported %i", ret);
84f08c3bdfSopenharmony_ci		goto exit;
85f08c3bdfSopenharmony_ci	}
86f08c3bdfSopenharmony_ci
87f08c3bdfSopenharmony_ci	if (evt_rec.events & EPOLLRDHUP)
88f08c3bdfSopenharmony_ci		tst_res(TPASS, "Received EPOLLRDHUP");
89f08c3bdfSopenharmony_ci	else
90f08c3bdfSopenharmony_ci		tst_res(TFAIL, "EPOLLRDHUP has not been received");
91f08c3bdfSopenharmony_ci
92f08c3bdfSopenharmony_ciexit:
93f08c3bdfSopenharmony_ci	SAFE_CLOSE(epfd);
94f08c3bdfSopenharmony_ci	SAFE_CLOSE(sockfd_client);
95f08c3bdfSopenharmony_ci
96f08c3bdfSopenharmony_ci	TST_CHECKPOINT_WAKE(0);
97f08c3bdfSopenharmony_ci}
98f08c3bdfSopenharmony_ci
99f08c3bdfSopenharmony_cistatic void setup(void)
100f08c3bdfSopenharmony_ci{
101f08c3bdfSopenharmony_ci	sock_port = SAFE_MMAP(NULL, sizeof(in_port_t), PROT_READ | PROT_WRITE,
102f08c3bdfSopenharmony_ci		MAP_SHARED | MAP_ANONYMOUS, -1, 0);
103f08c3bdfSopenharmony_ci}
104f08c3bdfSopenharmony_ci
105f08c3bdfSopenharmony_cistatic void cleanup(void)
106f08c3bdfSopenharmony_ci{
107f08c3bdfSopenharmony_ci	if (sock_port)
108f08c3bdfSopenharmony_ci		SAFE_MUNMAP(sock_port, sizeof(in_port_t));
109f08c3bdfSopenharmony_ci
110f08c3bdfSopenharmony_ci	if (fcntl(sockfd_client, F_GETFD) > 0)
111f08c3bdfSopenharmony_ci		SAFE_CLOSE(sockfd_client);
112f08c3bdfSopenharmony_ci
113f08c3bdfSopenharmony_ci	if (fcntl(sockfd_server, F_GETFD) > 0)
114f08c3bdfSopenharmony_ci		SAFE_CLOSE(sockfd_server);
115f08c3bdfSopenharmony_ci
116f08c3bdfSopenharmony_ci	if (fcntl(epfd, F_GETFD) > 0)
117f08c3bdfSopenharmony_ci		SAFE_CLOSE(epfd);
118f08c3bdfSopenharmony_ci}
119f08c3bdfSopenharmony_ci
120f08c3bdfSopenharmony_cistatic struct tst_test test = {
121f08c3bdfSopenharmony_ci	.setup = setup,
122f08c3bdfSopenharmony_ci	.cleanup = cleanup,
123f08c3bdfSopenharmony_ci	.test_all = run,
124f08c3bdfSopenharmony_ci	.forks_child = 1,
125f08c3bdfSopenharmony_ci	.needs_checkpoints = 1,
126f08c3bdfSopenharmony_ci};
127