Added
Link Here
|
1 |
/*- |
2 |
* SPDX-License-Identifier: BSD-2-Clause |
3 |
* |
4 |
* Copyright (c) 2023 The FreeBSD Foundation |
5 |
* |
6 |
* This software was developed by Mark Johnston under sponsorship from |
7 |
* the FreeBSD Foundation. |
8 |
*/ |
9 |
|
10 |
#include <sys/types.h> |
11 |
#include <sys/socket.h> |
12 |
#include <sys/un.h> |
13 |
|
14 |
#include <netinet/in.h> |
15 |
|
16 |
#include <errno.h> |
17 |
#include <pthread.h> |
18 |
#include <stdlib.h> |
19 |
#include <unistd.h> |
20 |
|
21 |
#include <atf-c.h> |
22 |
|
23 |
struct close_test_params { |
24 |
struct sockaddr_storage sa; |
25 |
size_t msglen; |
26 |
int count; |
27 |
int af, type, proto; |
28 |
}; |
29 |
|
30 |
static void * |
31 |
close_test_client(void *arg) |
32 |
{ |
33 |
struct close_test_params *p = arg; |
34 |
char *buf; |
35 |
size_t buflen; |
36 |
|
37 |
buflen = p->msglen + 1; |
38 |
buf = malloc(buflen); |
39 |
ATF_REQUIRE(buf != NULL); |
40 |
|
41 |
while (p->count-- > 0) { |
42 |
ssize_t n; |
43 |
int error, s; |
44 |
|
45 |
s = socket(p->af, p->type, p->proto); |
46 |
ATF_REQUIRE_MSG(s >= 0, "socket: %s", strerror(errno)); |
47 |
|
48 |
error = connect(s, (struct sockaddr *)&p->sa, p->sa.ss_len); |
49 |
ATF_REQUIRE_MSG(error == 0, "connect: %s", strerror(errno)); |
50 |
|
51 |
n = recv(s, buf, buflen, MSG_WAITALL); |
52 |
ATF_REQUIRE_MSG(n == (ssize_t)p->msglen, |
53 |
"recv: %s", strerror(errno)); |
54 |
|
55 |
ATF_REQUIRE(close(s) == 0); |
56 |
} |
57 |
|
58 |
return (NULL); |
59 |
} |
60 |
|
61 |
static void |
62 |
close_test(struct sockaddr *sa, unsigned int count, int af, int type, int proto) |
63 |
{ |
64 |
struct close_test_params p; |
65 |
const char *msg; |
66 |
pthread_t t; |
67 |
size_t msglen; |
68 |
int error, s; |
69 |
|
70 |
s = socket(af, type, proto); |
71 |
ATF_REQUIRE_MSG(s >= 0, "socket %s", strerror(errno)); |
72 |
|
73 |
ATF_REQUIRE_MSG(bind(s, sa, sa->sa_len) == 0, |
74 |
"bind: %s", strerror(errno)); |
75 |
ATF_REQUIRE_MSG(listen(s, 1) == 0, |
76 |
"listen: %s", strerror(errno)); |
77 |
ATF_REQUIRE_MSG(getsockname(s, sa, &(socklen_t){ sa->sa_len }) == 0, |
78 |
"getsockname: %s", strerror(errno)); |
79 |
|
80 |
msg = "hello bonjour"; |
81 |
msglen = strlen(msg) + 1; |
82 |
p = (struct close_test_params){ |
83 |
.count = count, |
84 |
.msglen = msglen, |
85 |
.af = af, |
86 |
.type = type, |
87 |
.proto = proto, |
88 |
}; |
89 |
memcpy(&p.sa, sa, sa->sa_len); |
90 |
error = pthread_create(&t, NULL, close_test_client, &p); |
91 |
ATF_REQUIRE_MSG(error == 0, "pthread_create: %s", strerror(error)); |
92 |
|
93 |
while (count-- > 0) { |
94 |
ssize_t n; |
95 |
int cs; |
96 |
|
97 |
cs = accept(s, NULL, NULL); |
98 |
ATF_REQUIRE_MSG(cs >= 0, "accept: %s", strerror(errno)); |
99 |
|
100 |
n = send(cs, msg, msglen, 0); |
101 |
ATF_REQUIRE_MSG(n == (ssize_t)msglen, |
102 |
"send: %s", strerror(errno)); |
103 |
|
104 |
ATF_REQUIRE(close(cs) == 0); |
105 |
} |
106 |
|
107 |
ATF_REQUIRE(close(s) == 0); |
108 |
ATF_REQUIRE(pthread_join(t, NULL) == 0); |
109 |
} |
110 |
|
111 |
/* |
112 |
* Make sure that closing a connection kicks a MSG_WAITALL recv() out of the |
113 |
* syscall. See bugzilla PR 212716. |
114 |
*/ |
115 |
ATF_TC(close_tcp); |
116 |
ATF_TC_HEAD(close_tcp, tc) |
117 |
{ |
118 |
atf_tc_set_md_var(tc, "timeout", "10"); |
119 |
} |
120 |
ATF_TC_BODY(close_tcp, tc) |
121 |
{ |
122 |
struct sockaddr_in sin; |
123 |
|
124 |
sin = (struct sockaddr_in){ |
125 |
.sin_len = sizeof(sin), |
126 |
.sin_family = AF_INET, |
127 |
.sin_addr = { htonl(INADDR_LOOPBACK) }, |
128 |
.sin_port = htons(0), |
129 |
}; |
130 |
close_test((struct sockaddr *)&sin, 1000, AF_INET, SOCK_STREAM, |
131 |
IPPROTO_TCP); |
132 |
} |
133 |
|
134 |
/* A variant of the above test for UNIX domain stream sockets. */ |
135 |
ATF_TC(close_unix_stream); |
136 |
ATF_TC_HEAD(close_unix_stream, tc) |
137 |
{ |
138 |
atf_tc_set_md_var(tc, "timeout", "10"); |
139 |
} |
140 |
ATF_TC_BODY(close_unix_stream, tc) |
141 |
{ |
142 |
struct sockaddr_un sun; |
143 |
|
144 |
sun = (struct sockaddr_un){ |
145 |
.sun_len = sizeof(sun), |
146 |
.sun_family = AF_UNIX, |
147 |
.sun_path = "socket_msg_waitall_unix", |
148 |
}; |
149 |
close_test((struct sockaddr *)&sun, 1000, AF_UNIX, SOCK_STREAM, 0); |
150 |
ATF_REQUIRE_MSG(unlink(sun.sun_path) == 0, |
151 |
"unlink: %s", strerror(errno)); |
152 |
} |
153 |
|
154 |
/* A variant of the above test for UNIX domain seqpacket sockets. */ |
155 |
ATF_TC(close_unix_seqpacket); |
156 |
ATF_TC_HEAD(close_unix_seqpacket, tc) |
157 |
{ |
158 |
atf_tc_set_md_var(tc, "timeout", "10"); |
159 |
} |
160 |
ATF_TC_BODY(close_unix_seqpacket, tc) |
161 |
{ |
162 |
struct sockaddr_un sun; |
163 |
|
164 |
sun = (struct sockaddr_un){ |
165 |
.sun_len = sizeof(sun), |
166 |
.sun_family = AF_UNIX, |
167 |
.sun_path = "socket_msg_waitall_unix", |
168 |
}; |
169 |
close_test((struct sockaddr *)&sun, 1000, AF_UNIX, SOCK_SEQPACKET, 0); |
170 |
ATF_REQUIRE_MSG(unlink(sun.sun_path) == 0, |
171 |
"unlink: %s", strerror(errno)); |
172 |
} |
173 |
|
174 |
ATF_TP_ADD_TCS(tp) |
175 |
{ |
176 |
ATF_TP_ADD_TC(tp, close_tcp); |
177 |
ATF_TP_ADD_TC(tp, close_unix_stream); |
178 |
ATF_TP_ADD_TC(tp, close_unix_seqpacket); |
179 |
|
180 |
return (atf_no_error()); |
181 |
} |