xref: /freebsd/tests/sys/kern/unix_dgram.c (revision aa9f97af93fc9df5596654fc11f2720878c81e1a)
16d317723SGleb Smirnoff /*-
26d317723SGleb Smirnoff  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
36d317723SGleb Smirnoff  *
46d317723SGleb Smirnoff  * Copyright (c) 2022 Gleb Smirnoff <glebius@FreeBSD.org>
56d317723SGleb Smirnoff  *
66d317723SGleb Smirnoff  * Redistribution and use in source and binary forms, with or without
76d317723SGleb Smirnoff  * modification, are permitted provided that the following conditions
86d317723SGleb Smirnoff  * are met:
96d317723SGleb Smirnoff  * 1. Redistributions of source code must retain the above copyright
106d317723SGleb Smirnoff  *    notice, this list of conditions and the following disclaimer.
116d317723SGleb Smirnoff  * 2. Redistributions in binary form must reproduce the above copyright
126d317723SGleb Smirnoff  *    notice, this list of conditions and the following disclaimer in the
136d317723SGleb Smirnoff  *    documentation and/or other materials provided with the distribution.
146d317723SGleb Smirnoff  *
156d317723SGleb Smirnoff  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
166d317723SGleb Smirnoff  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
176d317723SGleb Smirnoff  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
186d317723SGleb Smirnoff  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
196d317723SGleb Smirnoff  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
206d317723SGleb Smirnoff  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
216d317723SGleb Smirnoff  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
226d317723SGleb Smirnoff  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
236d317723SGleb Smirnoff  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
246d317723SGleb Smirnoff  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
256d317723SGleb Smirnoff  * SUCH DAMAGE.
266d317723SGleb Smirnoff  */
276d317723SGleb Smirnoff 
286d317723SGleb Smirnoff #include <sys/time.h>
296d317723SGleb Smirnoff #include <sys/socket.h>
306d317723SGleb Smirnoff #include <sys/sysctl.h>
316d317723SGleb Smirnoff #include <sys/un.h>
326d317723SGleb Smirnoff #include <errno.h>
336d317723SGleb Smirnoff #include <fcntl.h>
346d317723SGleb Smirnoff #include <signal.h>
356d317723SGleb Smirnoff #include <stdlib.h>
366d317723SGleb Smirnoff 
376d317723SGleb Smirnoff #include <atf-c.h>
386d317723SGleb Smirnoff 
396d317723SGleb Smirnoff static struct itimerval itv = {
406d317723SGleb Smirnoff 	.it_interval = { 0, 0 },
416d317723SGleb Smirnoff 	.it_value = { 1, 0 },	/* one second */
426d317723SGleb Smirnoff };
436d317723SGleb Smirnoff static sig_atomic_t timer_done = 0;
446d317723SGleb Smirnoff static void
456d317723SGleb Smirnoff sigalarm(int sig __unused)
466d317723SGleb Smirnoff {
476d317723SGleb Smirnoff 
486d317723SGleb Smirnoff 	timer_done = 1;
496d317723SGleb Smirnoff }
506d317723SGleb Smirnoff 
516d317723SGleb Smirnoff static struct sigaction sigact = {
526d317723SGleb Smirnoff 	.sa_handler = sigalarm,
536d317723SGleb Smirnoff };
546d317723SGleb Smirnoff 
556d317723SGleb Smirnoff /*
566d317723SGleb Smirnoff  * Fill socket to a state when next send(len) would fail.
57*aa9f97afSGleb Smirnoff  *
58*aa9f97afSGleb Smirnoff  * Note that every datagram is prepended with sender address,
59*aa9f97afSGleb Smirnoff  * size of struct sockaddr.
606d317723SGleb Smirnoff  */
616d317723SGleb Smirnoff static void
626d317723SGleb Smirnoff fill(int fd, void *buf, ssize_t len)
636d317723SGleb Smirnoff {
646d317723SGleb Smirnoff 	unsigned long recvspace;
656d317723SGleb Smirnoff 	size_t llen = sizeof(unsigned long);
666d317723SGleb Smirnoff 	ssize_t sent;
676d317723SGleb Smirnoff 
686d317723SGleb Smirnoff 	ATF_REQUIRE(sysctlbyname("net.local.dgram.recvspace", &recvspace,
696d317723SGleb Smirnoff 	    &llen, NULL, 0) == 0);
70*aa9f97afSGleb Smirnoff 	for (sent = 0;
71*aa9f97afSGleb Smirnoff 	    sent + len + sizeof(struct sockaddr) < recvspace;
72*aa9f97afSGleb Smirnoff 	    sent += len + sizeof(struct sockaddr))
736d317723SGleb Smirnoff 		ATF_REQUIRE(send(fd, buf, len, 0) == len);
746d317723SGleb Smirnoff }
756d317723SGleb Smirnoff 
766d317723SGleb Smirnoff ATF_TC_WITHOUT_HEAD(basic);
776d317723SGleb Smirnoff ATF_TC_BODY(basic, tc)
786d317723SGleb Smirnoff {
796d317723SGleb Smirnoff 	struct msghdr msg;
806d317723SGleb Smirnoff 	struct iovec iov[1];
816d317723SGleb Smirnoff 	unsigned long maxdgram;
826d317723SGleb Smirnoff 	size_t llen = sizeof(unsigned long);
836d317723SGleb Smirnoff 	int fd[2];
846d317723SGleb Smirnoff 	char *buf;
856d317723SGleb Smirnoff 
866d317723SGleb Smirnoff 	/* Allocate and initialize:
876d317723SGleb Smirnoff 	 * - fd[0] to send, fd[1] to receive
886d317723SGleb Smirnoff 	 * - buf[maxdgram] for data
896d317723SGleb Smirnoff 	 */
906d317723SGleb Smirnoff 	ATF_REQUIRE(sysctlbyname("net.local.dgram.maxdgram", &maxdgram,
916d317723SGleb Smirnoff 	    &llen, NULL, 0) == 0);
926d317723SGleb Smirnoff 	ATF_REQUIRE(socketpair(PF_UNIX, SOCK_DGRAM, 0, fd) != -1);
936d317723SGleb Smirnoff 	buf = malloc(maxdgram + 1);
946d317723SGleb Smirnoff 	ATF_REQUIRE(buf);
956d317723SGleb Smirnoff 	msg = (struct msghdr ){
966d317723SGleb Smirnoff 		.msg_iov = iov,
976d317723SGleb Smirnoff 		.msg_iovlen = 1,
986d317723SGleb Smirnoff 	};
996d317723SGleb Smirnoff 	iov[0] = (struct iovec ){
1006d317723SGleb Smirnoff 		.iov_base = buf,
1016d317723SGleb Smirnoff 	};
1026d317723SGleb Smirnoff 
1036d317723SGleb Smirnoff 	/* Fail to send > maxdgram. */
1046d317723SGleb Smirnoff 	ATF_REQUIRE(send(fd[0], buf, maxdgram + 1, 0) == -1);
1056d317723SGleb Smirnoff 	ATF_REQUIRE(errno == EMSGSIZE);
1066d317723SGleb Smirnoff 
1076d317723SGleb Smirnoff 	/* Send maxdgram. */
1086d317723SGleb Smirnoff 	ATF_REQUIRE(send(fd[0], buf, maxdgram, 0) == (ssize_t)maxdgram);
1096d317723SGleb Smirnoff 
1106d317723SGleb Smirnoff 	/* Exercise MSG_PEEK, full and truncated.. */
1116d317723SGleb Smirnoff 	ATF_REQUIRE(recv(fd[1], buf, maxdgram, MSG_PEEK) == (ssize_t)maxdgram);
1126d317723SGleb Smirnoff 	iov[0].iov_len = 42;
1136d317723SGleb Smirnoff 	ATF_REQUIRE(recvmsg(fd[1], &msg, MSG_PEEK) == 42);
1146d317723SGleb Smirnoff 	ATF_REQUIRE(msg.msg_flags == (MSG_PEEK | MSG_TRUNC));
1156d317723SGleb Smirnoff 
1166d317723SGleb Smirnoff 	/* Receive maxdgram. */
1176d317723SGleb Smirnoff 	iov[0].iov_len = maxdgram;
1186d317723SGleb Smirnoff 	ATF_REQUIRE(recvmsg(fd[1], &msg, 0) == (ssize_t)maxdgram);
1196d317723SGleb Smirnoff 	ATF_REQUIRE(msg.msg_flags == 0);
1206d317723SGleb Smirnoff 
1216d317723SGleb Smirnoff 	/* Receive truncated message. */
1226d317723SGleb Smirnoff 	ATF_REQUIRE(send(fd[0], buf, maxdgram, 0) == (ssize_t)maxdgram);
1236d317723SGleb Smirnoff 	iov[0].iov_len = maxdgram / 2;
1246d317723SGleb Smirnoff 	ATF_REQUIRE(recvmsg(fd[1], &msg, 0) == (ssize_t)maxdgram / 2);
1256d317723SGleb Smirnoff 	ATF_REQUIRE(msg.msg_flags == MSG_TRUNC);
1266d317723SGleb Smirnoff 
1276d317723SGleb Smirnoff 	/* Empty: block. */
1286d317723SGleb Smirnoff 	ATF_REQUIRE(sigaction(SIGALRM, &sigact, NULL) == 0);
1296d317723SGleb Smirnoff 	ATF_REQUIRE(timer_done == 0);
1306d317723SGleb Smirnoff 	ATF_REQUIRE(setitimer(ITIMER_REAL, &itv, NULL) == 0);
1316d317723SGleb Smirnoff 	ATF_REQUIRE(recv(fd[1], buf, maxdgram, 0) == -1);
1326d317723SGleb Smirnoff 	ATF_REQUIRE(errno == EINTR);
1336d317723SGleb Smirnoff 	ATF_REQUIRE(timer_done == 1);
1346d317723SGleb Smirnoff 
1356d317723SGleb Smirnoff 	/* Don't block with MSG_DONTWAIT. */
1366d317723SGleb Smirnoff 	ATF_REQUIRE(recv(fd[1], buf, maxdgram, MSG_DONTWAIT) == -1);
1376d317723SGleb Smirnoff 	ATF_REQUIRE(errno == EAGAIN);
1386d317723SGleb Smirnoff 
1396d317723SGleb Smirnoff 	/* Don't block with O_NONBLOCK. */
1406d317723SGleb Smirnoff 	ATF_REQUIRE(fcntl(fd[1], F_SETFL, O_NONBLOCK) != -1);
1416d317723SGleb Smirnoff 	ATF_REQUIRE(recv(fd[1], buf, maxdgram, 0) == -1);
1426d317723SGleb Smirnoff 	ATF_REQUIRE(errno == EAGAIN);
1436d317723SGleb Smirnoff 
1446d317723SGleb Smirnoff 	/* Fail with ENOBUFS on full socket. */
1456d317723SGleb Smirnoff 	fill(fd[0], buf, maxdgram);
1466d317723SGleb Smirnoff 	ATF_REQUIRE(send(fd[0], buf, maxdgram, 0) == -1);
1476d317723SGleb Smirnoff 	ATF_REQUIRE(errno == ENOBUFS);
1486d317723SGleb Smirnoff 
1496d317723SGleb Smirnoff 	/* Fail with EAGAIN with O_NONBLOCK set. */
1506d317723SGleb Smirnoff 	ATF_REQUIRE(fcntl(fd[0], F_SETFL, O_NONBLOCK) != -1);
1516d317723SGleb Smirnoff 	ATF_REQUIRE(send(fd[0], buf, maxdgram, 0) == -1);
1526d317723SGleb Smirnoff 	ATF_REQUIRE(errno == EAGAIN);
1536d317723SGleb Smirnoff 
1546d317723SGleb Smirnoff 	/* Remote side closed -> ECONNRESET. */
1556d317723SGleb Smirnoff 	close(fd[1]);
1566d317723SGleb Smirnoff 	ATF_REQUIRE(send(fd[0], buf, maxdgram, 0) == -1);
1576d317723SGleb Smirnoff 	ATF_REQUIRE(errno == ECONNRESET);
1586d317723SGleb Smirnoff }
1596d317723SGleb Smirnoff 
1606d317723SGleb Smirnoff ATF_TC_WITHOUT_HEAD(one2many);
1616d317723SGleb Smirnoff ATF_TC_BODY(one2many, tc)
1626d317723SGleb Smirnoff {
1636d317723SGleb Smirnoff 	struct sockaddr_un sun;
1646d317723SGleb Smirnoff 	const char *path = "unix_dgram_listener";
1656d317723SGleb Smirnoff 	int one, many[2], two;
1666d317723SGleb Smirnoff 	char buf[1024];
1676d317723SGleb Smirnoff 
1686d317723SGleb Smirnoff 	/* Establish one to many connection. */
1696d317723SGleb Smirnoff 	ATF_REQUIRE((one = socket(PF_UNIX, SOCK_DGRAM, 0)) > 0);
1706d317723SGleb Smirnoff 	bzero(&sun, sizeof(sun));
1716d317723SGleb Smirnoff 	sun.sun_family = AF_LOCAL;
1726d317723SGleb Smirnoff 	sun.sun_len = sizeof(sun);
1736d317723SGleb Smirnoff 	strlcpy(sun.sun_path, path, sizeof(sun.sun_path));
1746d317723SGleb Smirnoff 	ATF_REQUIRE(bind(one, (struct sockaddr *)&sun, sizeof(sun)) == 0);
1756d317723SGleb Smirnoff 	/* listen(2) shall fail. */
1766d317723SGleb Smirnoff 	ATF_REQUIRE(listen(one, -1) != 0);
1776d317723SGleb Smirnoff 	for (int i = 0; i < 2; i++) {
1786d317723SGleb Smirnoff 		ATF_REQUIRE((many[i] = socket(PF_UNIX, SOCK_DGRAM, 0)) > 0);
1796d317723SGleb Smirnoff 		ATF_REQUIRE(connect(many[i], (struct sockaddr *)&sun,
1806d317723SGleb Smirnoff 		    sizeof(sun)) == 0);
1816d317723SGleb Smirnoff 	}
1826d317723SGleb Smirnoff 
1836d317723SGleb Smirnoff 	/* accept() on UNIX/DGRAM is invalid. */
1846d317723SGleb Smirnoff 	ATF_REQUIRE(accept(one, NULL, NULL) == -1);
1856d317723SGleb Smirnoff 	ATF_REQUIRE(errno == EINVAL);
1866d317723SGleb Smirnoff 
1876d317723SGleb Smirnoff 	/*
1886d317723SGleb Smirnoff 	 * Connecting a bound socket to self: a strange, useless, but
1896d317723SGleb Smirnoff 	 * historically existing edge case that is not explicitly described
1906d317723SGleb Smirnoff 	 * in SuS, neither is forbidden there. Works on FreeBSD and Linux.
1916d317723SGleb Smirnoff 	 */
1926d317723SGleb Smirnoff 	ATF_REQUIRE(connect(one, (struct sockaddr *)&sun, sizeof(sun)) == 0);
1936d317723SGleb Smirnoff 	ATF_REQUIRE(send(one, buf, 42, 0) == 42);
1946d317723SGleb Smirnoff 	ATF_REQUIRE(recv(one, buf, sizeof(buf), 0) == 42);
1956d317723SGleb Smirnoff 
1966d317723SGleb Smirnoff 	/*
1976d317723SGleb Smirnoff 	 * Sending from an unconnected socket to a bound socket.  Connection is
1986d317723SGleb Smirnoff 	 * created for the duration of the syscall.
1996d317723SGleb Smirnoff 	 */
2006d317723SGleb Smirnoff 	ATF_REQUIRE((two = socket(PF_UNIX, SOCK_DGRAM, 0)) > 0);
2016d317723SGleb Smirnoff 	ATF_REQUIRE(sendto(two, buf, 43, 0, (struct sockaddr *)&sun,
2026d317723SGleb Smirnoff 	    sizeof(sun)) == 43);
2036d317723SGleb Smirnoff 	ATF_REQUIRE(recv(one, buf, sizeof(buf), 0) == 43);
2046d317723SGleb Smirnoff 
2056d317723SGleb Smirnoff 	/* One sender can fill the receive side.
2066d317723SGleb Smirnoff 	 * Current behavior which needs improvement.
2076d317723SGleb Smirnoff 	 */
2086d317723SGleb Smirnoff 	fill(many[0], buf, sizeof(buf));
2096d317723SGleb Smirnoff 	ATF_REQUIRE(send(many[1], buf, sizeof(buf), 0) == -1);
2106d317723SGleb Smirnoff 	ATF_REQUIRE(errno == ENOBUFS);
2116d317723SGleb Smirnoff 	ATF_REQUIRE(recv(one, buf, sizeof(buf), 0) == sizeof(buf));
2126d317723SGleb Smirnoff 	ATF_REQUIRE(send(many[1], buf, sizeof(buf), 0) == sizeof(buf));
2136d317723SGleb Smirnoff }
2146d317723SGleb Smirnoff 
2156d317723SGleb Smirnoff ATF_TP_ADD_TCS(tp)
2166d317723SGleb Smirnoff {
2176d317723SGleb Smirnoff 
2186d317723SGleb Smirnoff 	ATF_TP_ADD_TC(tp, basic);
2196d317723SGleb Smirnoff 	ATF_TP_ADD_TC(tp, one2many);
2206d317723SGleb Smirnoff 
2216d317723SGleb Smirnoff 	return (atf_no_error());
2226d317723SGleb Smirnoff }
223