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