xref: /freebsd/tests/sys/kern/socket_msg_trunc.c (revision b197d4b893974c9eb4d7b38704c6d5c486235d6f)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2022 Alexander V. Chernikov
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <sys/errno.h>
34 #include <sys/socket.h>
35 #include <sys/un.h>
36 #include <netinet/in.h>
37 #include <poll.h>
38 
39 #include <atf-c.h>
40 
41 static void
42 check_recvmsg(const char *test_name)
43 {
44 	int ss, cs, rc;
45 	struct sockaddr *sa;
46 	struct sockaddr_in sin;
47 	struct sockaddr_in6 sin6;
48 	struct sockaddr_un saun;
49 	int *sizes, sizes_count;
50 	int one = 1;
51 
52 
53 	if (!strcmp(test_name, "udp")) {
54 		ss = socket(PF_INET, SOCK_DGRAM, 0);
55 		ATF_CHECK(ss >= 0);
56 		rc = setsockopt(ss, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one));
57 		ATF_CHECK_EQ(0, rc);
58 		bzero(&sin, sizeof(sin));
59 		sin.sin_family = AF_INET;
60 		sin.sin_len = sizeof(sin);
61 		sin.sin_port = htons(6666);
62 		sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
63 		sa = (struct sockaddr *)&sin;
64 		rc = bind(ss, sa, sa->sa_len);
65 		ATF_CHECK_EQ(0, rc);
66 
67 		cs = socket(PF_INET, SOCK_DGRAM, 0);
68 		ATF_CHECK(cs >= 0);
69 		int inet_sizes[] = {80, 255, 256, 1024, 4096, 9000};
70 		sizes_count = sizeof(inet_sizes) / sizeof(int);
71 		sizes = malloc(sizeof(inet_sizes));
72 		memcpy(sizes, inet_sizes, sizeof(inet_sizes));
73 
74 	} else if (!strcmp(test_name, "udp6")) {
75 		ss = socket(PF_INET6, SOCK_DGRAM, 0);
76 		ATF_CHECK(ss >= 0);
77 		rc = setsockopt(ss, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one));
78 		ATF_CHECK_EQ(0, rc);
79 		bzero(&sin6, sizeof(sin6));
80 		sin6.sin6_family = AF_INET6;
81 		sin6.sin6_len = sizeof(sin6);
82 		sin6.sin6_port = htons(6666);
83 		const struct in6_addr in6loopback = IN6ADDR_LOOPBACK_INIT;
84 		sin6.sin6_addr = in6loopback;
85 		sa = (struct sockaddr *)&sin6;
86 		rc = bind(ss, sa, sa->sa_len);
87 		ATF_CHECK_EQ(0, rc);
88 
89 		cs = socket(PF_INET6, SOCK_DGRAM, 0);
90 		ATF_CHECK(cs >= 0);
91 		int inet_sizes[] = {80, 255, 256, 1024, 4096, 9000};
92 		sizes_count = sizeof(inet_sizes) / sizeof(int);
93 		sizes = malloc(sizeof(inet_sizes));
94 		memcpy(sizes, inet_sizes, sizeof(inet_sizes));
95 
96 	} else if (!strcmp(test_name, "unix")) {
97 		const char *PATH = "/tmp/test_check_recvmsg_socket";
98 		ss = socket(PF_UNIX, SOCK_DGRAM, 0);
99 		ATF_CHECK(ss >= 0);
100 		rc = setsockopt(ss, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one));
101 		ATF_CHECK_EQ(0, rc);
102 		bzero(&saun, sizeof(saun));
103 		saun.sun_family = AF_UNIX;
104 		strcpy(saun.sun_path, PATH);
105 		saun.sun_len = sizeof(saun);
106 		sa = (struct sockaddr *)&saun;
107 		unlink(PATH);
108 		rc = bind(ss, sa, sa->sa_len);
109 		ATF_CHECK_EQ(0, rc);
110 
111 		cs = socket(PF_UNIX, SOCK_DGRAM, 0);
112 		ATF_CHECK(cs >= 0);
113 		int unix_sizes[] = {80, 255, 256, 1024, 2000};
114 		sizes_count = sizeof(unix_sizes) / sizeof(int);
115 		sizes = malloc(sizeof(unix_sizes));
116 		memcpy(sizes, unix_sizes, sizeof(unix_sizes));
117 	} else
118 		return;
119 
120 	char buf[4096];
121 	memset(buf, 0xFF, sizeof(buf));
122 	for (int i = 0; i < sizes_count; i++) {
123 		int sz = sizes[i];
124 		char tbuf[1];
125 		rc = sendto(cs, buf, sz, 0, sa, sa->sa_len);
126 		ATF_REQUIRE_EQ(rc, sz);
127 
128 		rc = recv(ss, NULL, 0, MSG_PEEK | MSG_TRUNC);
129 		ATF_CHECK_EQ(rc, sz);
130 
131 		rc = recv(ss, tbuf, sizeof(tbuf), MSG_PEEK | MSG_TRUNC);
132 		ATF_CHECK_EQ(rc, sz);
133 
134 		rc = recv(ss, tbuf, sizeof(tbuf), MSG_TRUNC);
135 		ATF_CHECK_EQ(rc, sz);
136 	}
137 
138 	close(ss);
139 	close(cs);
140 }
141 
142 ATF_TC_WITHOUT_HEAD(socket_afinet_udp_recv_trunc);
143 ATF_TC_BODY(socket_afinet_udp_recv_trunc, tc)
144 {
145 	check_recvmsg("udp");
146 }
147 
148 ATF_TC_WITHOUT_HEAD(socket_afinet6_udp_recv_trunc);
149 ATF_TC_BODY(socket_afinet6_udp_recv_trunc, tc)
150 {
151 	check_recvmsg("udp6");
152 }
153 
154 ATF_TC_WITHOUT_HEAD(socket_afunix_recv_trunc);
155 ATF_TC_BODY(socket_afunix_recv_trunc, tc)
156 {
157 	check_recvmsg("unix");
158 }
159 
160 
161 ATF_TP_ADD_TCS(tp)
162 {
163 
164 	ATF_TP_ADD_TC(tp, socket_afinet_udp_recv_trunc);
165 	ATF_TP_ADD_TC(tp, socket_afinet6_udp_recv_trunc);
166 	ATF_TP_ADD_TC(tp, socket_afunix_recv_trunc);
167 
168 	return atf_no_error();
169 }
170