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