xref: /freebsd-src/tests/sys/kern/socket_msg_waitall.c (revision 702c481847181005c9717ad04ec79efb32627089)
138426b32SMark Johnston /*-
238426b32SMark Johnston  * SPDX-License-Identifier: BSD-2-Clause
338426b32SMark Johnston  *
438426b32SMark Johnston  * Copyright (c) 2023 The FreeBSD Foundation
538426b32SMark Johnston  *
638426b32SMark Johnston  * This software was developed by Mark Johnston under sponsorship from
738426b32SMark Johnston  * the FreeBSD Foundation.
838426b32SMark Johnston  */
938426b32SMark Johnston 
1038426b32SMark Johnston #include <sys/types.h>
1138426b32SMark Johnston #include <sys/socket.h>
1238426b32SMark Johnston #include <sys/un.h>
1338426b32SMark Johnston 
1438426b32SMark Johnston #include <netinet/in.h>
1538426b32SMark Johnston 
1638426b32SMark Johnston #include <errno.h>
1738426b32SMark Johnston #include <pthread.h>
1838426b32SMark Johnston #include <stdlib.h>
1938426b32SMark Johnston #include <unistd.h>
2038426b32SMark Johnston 
2138426b32SMark Johnston #include <atf-c.h>
2238426b32SMark Johnston 
2338426b32SMark Johnston struct close_test_params {
2438426b32SMark Johnston 	struct sockaddr_storage sa;
2538426b32SMark Johnston 	size_t msglen;
2638426b32SMark Johnston 	int count;
2738426b32SMark Johnston 	int af, type, proto;
2838426b32SMark Johnston };
2938426b32SMark Johnston 
3038426b32SMark Johnston static void *
close_test_client(void * arg)3138426b32SMark Johnston close_test_client(void *arg)
3238426b32SMark Johnston {
3338426b32SMark Johnston 	struct close_test_params *p = arg;
3438426b32SMark Johnston 	char *buf;
3538426b32SMark Johnston 	size_t buflen;
3638426b32SMark Johnston 
3738426b32SMark Johnston 	buflen = p->msglen + 1;
3838426b32SMark Johnston 	buf = malloc(buflen);
3938426b32SMark Johnston 	ATF_REQUIRE(buf != NULL);
4038426b32SMark Johnston 
4138426b32SMark Johnston 	while (p->count-- > 0) {
4238426b32SMark Johnston 		ssize_t n;
4338426b32SMark Johnston 		int error, s;
4438426b32SMark Johnston 
4538426b32SMark Johnston 		s = socket(p->af, p->type, p->proto);
4638426b32SMark Johnston 		ATF_REQUIRE_MSG(s >= 0, "socket: %s", strerror(errno));
4738426b32SMark Johnston 
4838426b32SMark Johnston 		error = connect(s, (struct sockaddr *)&p->sa, p->sa.ss_len);
4938426b32SMark Johnston 		ATF_REQUIRE_MSG(error == 0, "connect: %s", strerror(errno));
5038426b32SMark Johnston 
5138426b32SMark Johnston 		n = recv(s, buf, buflen, MSG_WAITALL);
5238426b32SMark Johnston 		ATF_REQUIRE_MSG(n == (ssize_t)p->msglen,
53*702c4818SGleb Smirnoff 		    "recv: got %zd expected %zd", n, (ssize_t)p->msglen);
5438426b32SMark Johnston 
5538426b32SMark Johnston 		ATF_REQUIRE(close(s) == 0);
5638426b32SMark Johnston 	}
57a3074ff2SMark Johnston 	free(buf);
5838426b32SMark Johnston 
5938426b32SMark Johnston 	return (NULL);
6038426b32SMark Johnston }
6138426b32SMark Johnston 
6238426b32SMark Johnston static void
close_test(struct sockaddr * sa,unsigned int count,int af,int type,int proto)6338426b32SMark Johnston close_test(struct sockaddr *sa, unsigned int count, int af, int type, int proto)
6438426b32SMark Johnston {
6538426b32SMark Johnston 	struct close_test_params p;
6638426b32SMark Johnston 	const char *msg;
6738426b32SMark Johnston 	pthread_t t;
6838426b32SMark Johnston 	size_t msglen;
6938426b32SMark Johnston 	int error, s;
7038426b32SMark Johnston 
7138426b32SMark Johnston 	s = socket(af, type, proto);
7238426b32SMark Johnston 	ATF_REQUIRE_MSG(s >= 0, "socket %s", strerror(errno));
7338426b32SMark Johnston 
7438426b32SMark Johnston 	ATF_REQUIRE_MSG(bind(s, sa, sa->sa_len) == 0,
7538426b32SMark Johnston 	    "bind: %s", strerror(errno));
7638426b32SMark Johnston 	ATF_REQUIRE_MSG(listen(s, 1) == 0,
7738426b32SMark Johnston 	    "listen: %s", strerror(errno));
7838426b32SMark Johnston 	ATF_REQUIRE_MSG(getsockname(s, sa, &(socklen_t){ sa->sa_len }) == 0,
7938426b32SMark Johnston 	    "getsockname: %s", strerror(errno));
8038426b32SMark Johnston 
8138426b32SMark Johnston 	msg = "hello bonjour";
8238426b32SMark Johnston 	msglen = strlen(msg) + 1;
8338426b32SMark Johnston 	p = (struct close_test_params){
8438426b32SMark Johnston 		.count = count,
8538426b32SMark Johnston 		.msglen = msglen,
8638426b32SMark Johnston 		.af = af,
8738426b32SMark Johnston 		.type = type,
8838426b32SMark Johnston 		.proto = proto,
8938426b32SMark Johnston 	};
9038426b32SMark Johnston 	memcpy(&p.sa, sa, sa->sa_len);
9138426b32SMark Johnston 	error = pthread_create(&t, NULL, close_test_client, &p);
9238426b32SMark Johnston 	ATF_REQUIRE_MSG(error == 0, "pthread_create: %s", strerror(error));
9338426b32SMark Johnston 
9438426b32SMark Johnston 	while (count-- > 0) {
9538426b32SMark Johnston 		ssize_t n;
9638426b32SMark Johnston 		int cs;
9738426b32SMark Johnston 
9838426b32SMark Johnston 		cs = accept(s, NULL, NULL);
9938426b32SMark Johnston 		ATF_REQUIRE_MSG(cs >= 0, "accept: %s", strerror(errno));
10038426b32SMark Johnston 
10138426b32SMark Johnston 		n = send(cs, msg, msglen, 0);
10238426b32SMark Johnston 		ATF_REQUIRE_MSG(n == (ssize_t)msglen,
10338426b32SMark Johnston 		    "send: %s", strerror(errno));
10438426b32SMark Johnston 
10538426b32SMark Johnston 		ATF_REQUIRE(close(cs) == 0);
10638426b32SMark Johnston 	}
10738426b32SMark Johnston 
10838426b32SMark Johnston 	ATF_REQUIRE(close(s) == 0);
10938426b32SMark Johnston 	ATF_REQUIRE(pthread_join(t, NULL) == 0);
11038426b32SMark Johnston }
11138426b32SMark Johnston 
11238426b32SMark Johnston /*
11338426b32SMark Johnston  * Make sure that closing a connection kicks a MSG_WAITALL recv() out of the
11438426b32SMark Johnston  * syscall.  See bugzilla PR 212716.
11538426b32SMark Johnston  */
11638426b32SMark Johnston ATF_TC(close_tcp);
ATF_TC_HEAD(close_tcp,tc)11738426b32SMark Johnston ATF_TC_HEAD(close_tcp, tc)
11838426b32SMark Johnston {
11938426b32SMark Johnston 	atf_tc_set_md_var(tc, "timeout", "10");
12038426b32SMark Johnston }
ATF_TC_BODY(close_tcp,tc)12138426b32SMark Johnston ATF_TC_BODY(close_tcp, tc)
12238426b32SMark Johnston {
12338426b32SMark Johnston 	struct sockaddr_in sin;
12438426b32SMark Johnston 
12538426b32SMark Johnston 	sin = (struct sockaddr_in){
12638426b32SMark Johnston 		.sin_len = sizeof(sin),
12738426b32SMark Johnston 		.sin_family = AF_INET,
12838426b32SMark Johnston 		.sin_addr = { htonl(INADDR_LOOPBACK) },
12938426b32SMark Johnston 		.sin_port = htons(0),
13038426b32SMark Johnston 	};
13138426b32SMark Johnston 	close_test((struct sockaddr *)&sin, 1000, AF_INET, SOCK_STREAM,
13238426b32SMark Johnston 	    IPPROTO_TCP);
13338426b32SMark Johnston }
13438426b32SMark Johnston 
13538426b32SMark Johnston /* A variant of the above test for UNIX domain stream sockets. */
13638426b32SMark Johnston ATF_TC(close_unix_stream);
ATF_TC_HEAD(close_unix_stream,tc)13738426b32SMark Johnston ATF_TC_HEAD(close_unix_stream, tc)
13838426b32SMark Johnston {
13938426b32SMark Johnston 	atf_tc_set_md_var(tc, "timeout", "10");
14038426b32SMark Johnston }
ATF_TC_BODY(close_unix_stream,tc)14138426b32SMark Johnston ATF_TC_BODY(close_unix_stream, tc)
14238426b32SMark Johnston {
14338426b32SMark Johnston 	struct sockaddr_un sun;
14438426b32SMark Johnston 
14538426b32SMark Johnston 	sun = (struct sockaddr_un){
14638426b32SMark Johnston 		.sun_len = sizeof(sun),
14738426b32SMark Johnston 		.sun_family = AF_UNIX,
14838426b32SMark Johnston 		.sun_path = "socket_msg_waitall_unix",
14938426b32SMark Johnston 	};
15038426b32SMark Johnston 	close_test((struct sockaddr *)&sun, 1000, AF_UNIX, SOCK_STREAM, 0);
15138426b32SMark Johnston 	ATF_REQUIRE_MSG(unlink(sun.sun_path) == 0,
15238426b32SMark Johnston 	    "unlink: %s", strerror(errno));
15338426b32SMark Johnston }
15438426b32SMark Johnston 
15538426b32SMark Johnston /* A variant of the above test for UNIX domain seqpacket sockets. */
15638426b32SMark Johnston ATF_TC(close_unix_seqpacket);
ATF_TC_HEAD(close_unix_seqpacket,tc)15738426b32SMark Johnston ATF_TC_HEAD(close_unix_seqpacket, tc)
15838426b32SMark Johnston {
15938426b32SMark Johnston 	atf_tc_set_md_var(tc, "timeout", "10");
16038426b32SMark Johnston }
ATF_TC_BODY(close_unix_seqpacket,tc)16138426b32SMark Johnston ATF_TC_BODY(close_unix_seqpacket, tc)
16238426b32SMark Johnston {
16338426b32SMark Johnston 	struct sockaddr_un sun;
16438426b32SMark Johnston 
16538426b32SMark Johnston 	sun = (struct sockaddr_un){
16638426b32SMark Johnston 		.sun_len = sizeof(sun),
16738426b32SMark Johnston 		.sun_family = AF_UNIX,
16838426b32SMark Johnston 		.sun_path = "socket_msg_waitall_unix",
16938426b32SMark Johnston 	};
17038426b32SMark Johnston 	close_test((struct sockaddr *)&sun, 1000, AF_UNIX, SOCK_SEQPACKET, 0);
17138426b32SMark Johnston 	ATF_REQUIRE_MSG(unlink(sun.sun_path) == 0,
17238426b32SMark Johnston 	    "unlink: %s", strerror(errno));
17338426b32SMark Johnston }
17438426b32SMark Johnston 
ATF_TP_ADD_TCS(tp)17538426b32SMark Johnston ATF_TP_ADD_TCS(tp)
17638426b32SMark Johnston {
17738426b32SMark Johnston 	ATF_TP_ADD_TC(tp, close_tcp);
17838426b32SMark Johnston 	ATF_TP_ADD_TC(tp, close_unix_stream);
17938426b32SMark Johnston 	ATF_TP_ADD_TC(tp, close_unix_seqpacket);
18038426b32SMark Johnston 
18138426b32SMark Johnston 	return (atf_no_error());
18238426b32SMark Johnston }
183