xref: /freebsd-src/tests/sys/netinet/udp_io.c (revision 3f3d19d80288f4b10384d1c84eb2a4c93f9faf9b)
18d3d9ca8SGleb Smirnoff /*-
28d3d9ca8SGleb Smirnoff  * SPDX-License-Identifier: BSD-2-Clause
38d3d9ca8SGleb Smirnoff  *
48d3d9ca8SGleb Smirnoff  * Copyright (c) 2024 Gleb Smirnoff <glebius@FreeBSD.org>
58d3d9ca8SGleb Smirnoff  *
68d3d9ca8SGleb Smirnoff  * Redistribution and use in source and binary forms, with or without
78d3d9ca8SGleb Smirnoff  * modification, are permitted provided that the following conditions
88d3d9ca8SGleb Smirnoff  * are met:
98d3d9ca8SGleb Smirnoff  * 1. Redistributions of source code must retain the above copyright
108d3d9ca8SGleb Smirnoff  *    notice, this list of conditions and the following disclaimer.
118d3d9ca8SGleb Smirnoff  * 2. Redistributions in binary form must reproduce the above copyright
128d3d9ca8SGleb Smirnoff  *    notice, this list of conditions and the following disclaimer in the
138d3d9ca8SGleb Smirnoff  *    documentation and/or other materials provided with the distribution.
148d3d9ca8SGleb Smirnoff  *
158d3d9ca8SGleb Smirnoff  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
168d3d9ca8SGleb Smirnoff  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
178d3d9ca8SGleb Smirnoff  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
188d3d9ca8SGleb Smirnoff  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
198d3d9ca8SGleb Smirnoff  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
208d3d9ca8SGleb Smirnoff  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
218d3d9ca8SGleb Smirnoff  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
228d3d9ca8SGleb Smirnoff  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
238d3d9ca8SGleb Smirnoff  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
248d3d9ca8SGleb Smirnoff  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
258d3d9ca8SGleb Smirnoff  * SUCH DAMAGE.
268d3d9ca8SGleb Smirnoff  */
278d3d9ca8SGleb Smirnoff 
288d3d9ca8SGleb Smirnoff #include <sys/socket.h>
298d3d9ca8SGleb Smirnoff #include <netinet/in.h>
308d3d9ca8SGleb Smirnoff #include <errno.h>
318d3d9ca8SGleb Smirnoff #include <stdlib.h>
328d3d9ca8SGleb Smirnoff #include <string.h>
338d3d9ca8SGleb Smirnoff #include <unistd.h>
348d3d9ca8SGleb Smirnoff 
358d3d9ca8SGleb Smirnoff #include <atf-c.h>
368d3d9ca8SGleb Smirnoff 
378d3d9ca8SGleb Smirnoff /*
388d3d9ca8SGleb Smirnoff  * Create a pair of UDP sockets.  The first one is bound to a local
398d3d9ca8SGleb Smirnoff  * address and the second one is connected to it.
408d3d9ca8SGleb Smirnoff  */
418d3d9ca8SGleb Smirnoff static void
udp_socketpair(int * s)428d3d9ca8SGleb Smirnoff udp_socketpair(int *s)
438d3d9ca8SGleb Smirnoff {
448d3d9ca8SGleb Smirnoff 	struct sockaddr_in sin = {
458d3d9ca8SGleb Smirnoff 		.sin_family = AF_INET,
468d3d9ca8SGleb Smirnoff 		.sin_len = sizeof(sin),
478d3d9ca8SGleb Smirnoff 	};
488d3d9ca8SGleb Smirnoff 	socklen_t slen = sizeof(sin);
498d3d9ca8SGleb Smirnoff 	int b, c;
508d3d9ca8SGleb Smirnoff 
518d3d9ca8SGleb Smirnoff 	ATF_REQUIRE((b = socket(PF_INET, SOCK_DGRAM, 0)) > 0);
528d3d9ca8SGleb Smirnoff 	ATF_REQUIRE((c = socket(PF_INET, SOCK_DGRAM, 0)) > 0);
538d3d9ca8SGleb Smirnoff 	ATF_REQUIRE(bind(b, (struct sockaddr *)&sin, sizeof(sin)) == 0);
548d3d9ca8SGleb Smirnoff 	ATF_REQUIRE(getsockname(b, (struct sockaddr *)&sin, &slen) == 0);
558d3d9ca8SGleb Smirnoff 	ATF_REQUIRE(connect(c, (struct sockaddr *)&sin, sizeof(sin)) == 0);
568d3d9ca8SGleb Smirnoff 
578d3d9ca8SGleb Smirnoff 	s[0] = b;
588d3d9ca8SGleb Smirnoff 	s[1] = c;
598d3d9ca8SGleb Smirnoff }
608d3d9ca8SGleb Smirnoff 
618d3d9ca8SGleb Smirnoff /*
628d3d9ca8SGleb Smirnoff  * Check MSG_TRUNC.
638d3d9ca8SGleb Smirnoff  */
648d3d9ca8SGleb Smirnoff ATF_TC_WITHOUT_HEAD(trunc);
ATF_TC_BODY(trunc,tc)658d3d9ca8SGleb Smirnoff ATF_TC_BODY(trunc, tc)
668d3d9ca8SGleb Smirnoff {
678d3d9ca8SGleb Smirnoff 	char sbuf[] = "Hello, peer!", rbuf[sizeof(sbuf)];
688d3d9ca8SGleb Smirnoff 	struct iovec iov = {
698d3d9ca8SGleb Smirnoff 		.iov_base = sbuf,
708d3d9ca8SGleb Smirnoff 		.iov_len = sizeof(sbuf),
718d3d9ca8SGleb Smirnoff 	};
728d3d9ca8SGleb Smirnoff 	struct msghdr msg = {
738d3d9ca8SGleb Smirnoff 		.msg_iov = &iov,
748d3d9ca8SGleb Smirnoff 		.msg_iovlen = 1,
758d3d9ca8SGleb Smirnoff 	};
768d3d9ca8SGleb Smirnoff 	int s[2];
778d3d9ca8SGleb Smirnoff 	u_int n;
788d3d9ca8SGleb Smirnoff 
798d3d9ca8SGleb Smirnoff 	udp_socketpair(s);
808d3d9ca8SGleb Smirnoff 
818d3d9ca8SGleb Smirnoff 	ATF_REQUIRE(sendmsg(s[1], &msg, 0) == sizeof(sbuf));
828d3d9ca8SGleb Smirnoff 	n = (arc4random() % (sizeof(sbuf) - 1)) + 1;
838d3d9ca8SGleb Smirnoff 	iov.iov_base = rbuf;
848d3d9ca8SGleb Smirnoff 	iov.iov_len = n;
85*3f3d19d8SGleb Smirnoff 	ATF_REQUIRE(recvmsg(s[0], &msg, 0) == (ssize_t)n);
868d3d9ca8SGleb Smirnoff 	ATF_REQUIRE(msg.msg_flags == MSG_TRUNC);
878d3d9ca8SGleb Smirnoff 	ATF_REQUIRE(strncmp(sbuf, rbuf, n) == 0);
888d3d9ca8SGleb Smirnoff 	iov.iov_len = sizeof(rbuf);
898d3d9ca8SGleb Smirnoff 	ATF_REQUIRE(recvmsg(s[0], &msg, MSG_DONTWAIT) == -1);
908d3d9ca8SGleb Smirnoff 	ATF_REQUIRE(errno == EAGAIN);
918d3d9ca8SGleb Smirnoff 
928d3d9ca8SGleb Smirnoff 	close(s[0]);
938d3d9ca8SGleb Smirnoff 	close(s[1]);
948d3d9ca8SGleb Smirnoff }
958d3d9ca8SGleb Smirnoff 
968d3d9ca8SGleb Smirnoff /*
978d3d9ca8SGleb Smirnoff  * Check MSG_PEEK.
988d3d9ca8SGleb Smirnoff  */
998d3d9ca8SGleb Smirnoff ATF_TC_WITHOUT_HEAD(peek);
ATF_TC_BODY(peek,tc)1008d3d9ca8SGleb Smirnoff ATF_TC_BODY(peek, tc)
1018d3d9ca8SGleb Smirnoff {
1028d3d9ca8SGleb Smirnoff 	char sbuf[] = "Hello, peer!", rbuf[sizeof(sbuf)];
1038d3d9ca8SGleb Smirnoff 	struct iovec iov = {
1048d3d9ca8SGleb Smirnoff 		.iov_base = sbuf,
1058d3d9ca8SGleb Smirnoff 		.iov_len = sizeof(sbuf),
1068d3d9ca8SGleb Smirnoff 	};
1078d3d9ca8SGleb Smirnoff 	struct msghdr msg = {
1088d3d9ca8SGleb Smirnoff 		.msg_iov = &iov,
1098d3d9ca8SGleb Smirnoff 		.msg_iovlen = 1,
1108d3d9ca8SGleb Smirnoff 	};
1118d3d9ca8SGleb Smirnoff 	int s[2];
1128d3d9ca8SGleb Smirnoff 	u_int n;
1138d3d9ca8SGleb Smirnoff 
1148d3d9ca8SGleb Smirnoff 	udp_socketpair(s);
1158d3d9ca8SGleb Smirnoff 
1168d3d9ca8SGleb Smirnoff 	ATF_REQUIRE(sendmsg(s[1], &msg, 0) == sizeof(sbuf));
1178d3d9ca8SGleb Smirnoff 	iov.iov_base = rbuf;
1188d3d9ca8SGleb Smirnoff 	for (int i = 0; i < 10; i++) {
1198d3d9ca8SGleb Smirnoff 		n = (arc4random() % sizeof(sbuf)) + 1;
1208d3d9ca8SGleb Smirnoff 		iov.iov_len = n;
121*3f3d19d8SGleb Smirnoff 		ATF_REQUIRE(recvmsg(s[0], &msg, MSG_PEEK) == (ssize_t)n);
1228d3d9ca8SGleb Smirnoff 		if (n < sizeof(sbuf))
1238d3d9ca8SGleb Smirnoff 			ATF_REQUIRE(msg.msg_flags == (MSG_PEEK | MSG_TRUNC));
1248d3d9ca8SGleb Smirnoff 		else
1258d3d9ca8SGleb Smirnoff 			ATF_REQUIRE(msg.msg_flags == MSG_PEEK);
1268d3d9ca8SGleb Smirnoff 		ATF_REQUIRE(strncmp(sbuf, rbuf, n) == 0);
1278d3d9ca8SGleb Smirnoff 	}
1288d3d9ca8SGleb Smirnoff 
1298d3d9ca8SGleb Smirnoff 	close(s[0]);
1308d3d9ca8SGleb Smirnoff 	close(s[1]);
1318d3d9ca8SGleb Smirnoff }
1328d3d9ca8SGleb Smirnoff 
ATF_TP_ADD_TCS(tp)1338d3d9ca8SGleb Smirnoff ATF_TP_ADD_TCS(tp)
1348d3d9ca8SGleb Smirnoff {
1358d3d9ca8SGleb Smirnoff 	ATF_TP_ADD_TC(tp, trunc);
1368d3d9ca8SGleb Smirnoff 	ATF_TP_ADD_TC(tp, peek);
1378d3d9ca8SGleb Smirnoff 
1388d3d9ca8SGleb Smirnoff 	return (atf_no_error());
1398d3d9ca8SGleb Smirnoff }
140