xref: /freebsd/tests/sys/kern/socket_msg_trunc.c (revision edf8578117e8844e02c0121147f45e4609b30680)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
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 #include <stdio.h>
30 #include <stdlib.h>
31 #include <sys/errno.h>
32 #include <sys/socket.h>
33 #include <sys/un.h>
34 #include <netinet/in.h>
35 #include <poll.h>
36 
37 #include <atf-c.h>
38 
39 static void
40 check_recvmsg(const char *test_name)
41 {
42 	int ss, cs, rc;
43 	struct sockaddr *sa;
44 	struct sockaddr_in sin;
45 	struct sockaddr_in6 sin6;
46 	struct sockaddr_un saun;
47 	int *sizes, sizes_count;
48 	int one = 1;
49 
50 
51 	if (!strcmp(test_name, "udp")) {
52 		ss = socket(PF_INET, SOCK_DGRAM, 0);
53 		ATF_CHECK(ss >= 0);
54 		rc = setsockopt(ss, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one));
55 		ATF_CHECK_EQ(0, rc);
56 		bzero(&sin, sizeof(sin));
57 		sin.sin_family = AF_INET;
58 		sin.sin_len = sizeof(sin);
59 		sin.sin_port = htons(6666);
60 		sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
61 		sa = (struct sockaddr *)&sin;
62 		rc = bind(ss, sa, sa->sa_len);
63 		ATF_CHECK_EQ(0, rc);
64 
65 		cs = socket(PF_INET, SOCK_DGRAM, 0);
66 		ATF_CHECK(cs >= 0);
67 		int inet_sizes[] = {80, 255, 256, 1024, 4096, 9000};
68 		sizes_count = sizeof(inet_sizes) / sizeof(int);
69 		sizes = malloc(sizeof(inet_sizes));
70 		memcpy(sizes, inet_sizes, sizeof(inet_sizes));
71 
72 	} else if (!strcmp(test_name, "udp6")) {
73 		ss = socket(PF_INET6, SOCK_DGRAM, 0);
74 		ATF_CHECK(ss >= 0);
75 		rc = setsockopt(ss, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one));
76 		ATF_CHECK_EQ(0, rc);
77 		bzero(&sin6, sizeof(sin6));
78 		sin6.sin6_family = AF_INET6;
79 		sin6.sin6_len = sizeof(sin6);
80 		sin6.sin6_port = htons(6666);
81 		const struct in6_addr in6loopback = IN6ADDR_LOOPBACK_INIT;
82 		sin6.sin6_addr = in6loopback;
83 		sa = (struct sockaddr *)&sin6;
84 		rc = bind(ss, sa, sa->sa_len);
85 		ATF_CHECK_EQ(0, rc);
86 
87 		cs = socket(PF_INET6, SOCK_DGRAM, 0);
88 		ATF_CHECK(cs >= 0);
89 		int inet_sizes[] = {80, 255, 256, 1024, 4096, 9000};
90 		sizes_count = sizeof(inet_sizes) / sizeof(int);
91 		sizes = malloc(sizeof(inet_sizes));
92 		memcpy(sizes, inet_sizes, sizeof(inet_sizes));
93 
94 	} else if (!strcmp(test_name, "unix")) {
95 		const char *PATH = "/tmp/test_check_recvmsg_socket";
96 		ss = socket(PF_UNIX, SOCK_DGRAM, 0);
97 		ATF_CHECK(ss >= 0);
98 		rc = setsockopt(ss, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one));
99 		ATF_CHECK_EQ(0, rc);
100 		bzero(&saun, sizeof(saun));
101 		saun.sun_family = AF_UNIX;
102 		strcpy(saun.sun_path, PATH);
103 		saun.sun_len = sizeof(saun);
104 		sa = (struct sockaddr *)&saun;
105 		unlink(PATH);
106 		rc = bind(ss, sa, sa->sa_len);
107 		ATF_CHECK_EQ(0, rc);
108 
109 		cs = socket(PF_UNIX, SOCK_DGRAM, 0);
110 		ATF_CHECK(cs >= 0);
111 		int unix_sizes[] = {80, 255, 256, 1024, 2000};
112 		sizes_count = sizeof(unix_sizes) / sizeof(int);
113 		sizes = malloc(sizeof(unix_sizes));
114 		memcpy(sizes, unix_sizes, sizeof(unix_sizes));
115 	} else
116 		return;
117 
118 	char buf[4096];
119 	memset(buf, 0xFF, sizeof(buf));
120 	for (int i = 0; i < sizes_count; i++) {
121 		int sz = sizes[i];
122 		char tbuf[1];
123 		rc = sendto(cs, buf, sz, 0, sa, sa->sa_len);
124 		ATF_REQUIRE_EQ(rc, sz);
125 
126 		rc = recv(ss, NULL, 0, MSG_PEEK | MSG_TRUNC);
127 		ATF_CHECK_EQ(rc, sz);
128 
129 		rc = recv(ss, tbuf, sizeof(tbuf), MSG_PEEK | MSG_TRUNC);
130 		ATF_CHECK_EQ(rc, sz);
131 
132 		rc = recv(ss, tbuf, sizeof(tbuf), MSG_TRUNC);
133 		ATF_CHECK_EQ(rc, sz);
134 	}
135 
136 	close(ss);
137 	close(cs);
138 }
139 
140 ATF_TC_WITHOUT_HEAD(socket_afinet_udp_recv_trunc);
141 ATF_TC_BODY(socket_afinet_udp_recv_trunc, tc)
142 {
143 	check_recvmsg("udp");
144 }
145 
146 ATF_TC_WITHOUT_HEAD(socket_afinet6_udp_recv_trunc);
147 ATF_TC_BODY(socket_afinet6_udp_recv_trunc, tc)
148 {
149 	check_recvmsg("udp6");
150 }
151 
152 ATF_TC_WITHOUT_HEAD(socket_afunix_recv_trunc);
153 ATF_TC_BODY(socket_afunix_recv_trunc, tc)
154 {
155 	check_recvmsg("unix");
156 }
157 
158 
159 ATF_TP_ADD_TCS(tp)
160 {
161 
162 	ATF_TP_ADD_TC(tp, socket_afinet_udp_recv_trunc);
163 	ATF_TP_ADD_TC(tp, socket_afinet6_udp_recv_trunc);
164 	ATF_TP_ADD_TC(tp, socket_afunix_recv_trunc);
165 
166 	return atf_no_error();
167 }
168