xref: /openbsd/regress/lib/libc/sys/t_sendmmsg.c (revision 613dad15)
1*613dad15Santon /*	$OpenBSD: t_sendmmsg.c,v 1.3 2023/10/27 07:33:06 anton Exp $	*/
22bd2f6f0Smbuhl /*	$NetBSD: t_sendmmsg.c,v 1.3 2019/03/16 21:46:43 christos Exp $	*/
32bd2f6f0Smbuhl 
42bd2f6f0Smbuhl /*-
52bd2f6f0Smbuhl  * Copyright (c) 2018 The NetBSD Foundation, Inc.
62bd2f6f0Smbuhl  * All rights reserved.
72bd2f6f0Smbuhl  *
82bd2f6f0Smbuhl  * This code is derived from software contributed to The NetBSD Foundation
92bd2f6f0Smbuhl  * by Christos Zoulas.
102bd2f6f0Smbuhl  *
112bd2f6f0Smbuhl  * Redistribution and use in source and binary forms, with or without
122bd2f6f0Smbuhl  * modification, are permitted provided that the following conditions
132bd2f6f0Smbuhl  * are met:
142bd2f6f0Smbuhl  * 1. Redistributions of source code must retain the above copyright
152bd2f6f0Smbuhl  *    notice, this list of conditions and the following disclaimer.
162bd2f6f0Smbuhl  * 2. Redistributions in binary form must reproduce the above copyright
172bd2f6f0Smbuhl  *    notice, this list of conditions and the following disclaimer in the
182bd2f6f0Smbuhl  *    documentation and/or other materials provided with the distribution.
192bd2f6f0Smbuhl  *
202bd2f6f0Smbuhl  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
212bd2f6f0Smbuhl  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
222bd2f6f0Smbuhl  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
232bd2f6f0Smbuhl  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
242bd2f6f0Smbuhl  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
252bd2f6f0Smbuhl  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
262bd2f6f0Smbuhl  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
272bd2f6f0Smbuhl  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
282bd2f6f0Smbuhl  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
292bd2f6f0Smbuhl  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
302bd2f6f0Smbuhl  * POSSIBILITY OF SUCH DAMAGE.
312bd2f6f0Smbuhl  */
322bd2f6f0Smbuhl #include <sys/cdefs.h>
332bd2f6f0Smbuhl 
342bd2f6f0Smbuhl #include "atf-c.h"
352bd2f6f0Smbuhl #include <sys/types.h>
362bd2f6f0Smbuhl #include <sys/socket.h>
372bd2f6f0Smbuhl #include <sys/ioctl.h>
382bd2f6f0Smbuhl #include <sys/wait.h>
392bd2f6f0Smbuhl 
402bd2f6f0Smbuhl #include <string.h>
412bd2f6f0Smbuhl #include <time.h>
422bd2f6f0Smbuhl #include <stdint.h>
432bd2f6f0Smbuhl #include <errno.h>
442bd2f6f0Smbuhl #include <signal.h>
452bd2f6f0Smbuhl #include <stdio.h>
462bd2f6f0Smbuhl #include <stdlib.h>
472bd2f6f0Smbuhl #include <unistd.h>
482bd2f6f0Smbuhl #include <sched.h>
492bd2f6f0Smbuhl 
502bd2f6f0Smbuhl #define BUFSIZE	65536
512bd2f6f0Smbuhl 
522bd2f6f0Smbuhl #define min(a, b) ((a) < (b) ? (a) : (b))
532bd2f6f0Smbuhl static int debug;
542bd2f6f0Smbuhl static volatile sig_atomic_t rdied;
552bd2f6f0Smbuhl 
562bd2f6f0Smbuhl static void
handle_sigchld(__unused int pid)572bd2f6f0Smbuhl handle_sigchld(__unused int pid)
582bd2f6f0Smbuhl {
592bd2f6f0Smbuhl 
602bd2f6f0Smbuhl 	rdied = 1;
612bd2f6f0Smbuhl }
622bd2f6f0Smbuhl 
632bd2f6f0Smbuhl ATF_TC(sendmmsg_basic);
ATF_TC_HEAD(sendmmsg_basic,tc)642bd2f6f0Smbuhl ATF_TC_HEAD(sendmmsg_basic, tc)
652bd2f6f0Smbuhl {
662bd2f6f0Smbuhl 	atf_tc_set_md_var(tc, "descr", "A basic test of sendmmsg(2)");
672bd2f6f0Smbuhl }
682bd2f6f0Smbuhl 
692bd2f6f0Smbuhl static void
setsock(int fd,int type)702bd2f6f0Smbuhl setsock(int fd, int type)
712bd2f6f0Smbuhl {
722bd2f6f0Smbuhl 	int buflen = BUFSIZE;
732bd2f6f0Smbuhl 	socklen_t socklen = sizeof(buflen);
742bd2f6f0Smbuhl 
752bd2f6f0Smbuhl 	ATF_REQUIRE_MSG(setsockopt(fd, SOL_SOCKET, type,
762bd2f6f0Smbuhl 	    &buflen, socklen) != -1, "%s (%s)",
772bd2f6f0Smbuhl 	    type == SO_RCVBUF ? "rcv" : "snd", strerror(errno));
782bd2f6f0Smbuhl }
792bd2f6f0Smbuhl 
ATF_TC_BODY(sendmmsg_basic,tc)802bd2f6f0Smbuhl ATF_TC_BODY(sendmmsg_basic, tc)
812bd2f6f0Smbuhl {
822bd2f6f0Smbuhl 	int fd[2], error, cnt;
832bd2f6f0Smbuhl 	uint8_t *buf;
842bd2f6f0Smbuhl 	struct mmsghdr *mmsghdr;
852bd2f6f0Smbuhl 	struct iovec *iov;
862bd2f6f0Smbuhl 	unsigned int mmsgcnt, n;
872bd2f6f0Smbuhl 	int status;
882bd2f6f0Smbuhl 	off_t off;
892bd2f6f0Smbuhl 	uint8_t DGRAM[1316] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, };
902bd2f6f0Smbuhl 	uint8_t rgram[sizeof(DGRAM)];
912bd2f6f0Smbuhl 	struct sigaction sa;
922bd2f6f0Smbuhl 	ssize_t overf = 0;
932bd2f6f0Smbuhl 
942bd2f6f0Smbuhl 	error = socketpair(AF_UNIX, SOCK_DGRAM, 0, fd);
952bd2f6f0Smbuhl 	ATF_REQUIRE_MSG(error != -1, "socketpair failed (%s)", strerror(errno));
962bd2f6f0Smbuhl 
972bd2f6f0Smbuhl 	buf = malloc(BUFSIZE);
982bd2f6f0Smbuhl 	ATF_REQUIRE_MSG(buf != NULL, "malloc failed (%s)", strerror(errno));
992bd2f6f0Smbuhl 
1002bd2f6f0Smbuhl 	setsock(fd[1], SO_SNDBUF);
1012bd2f6f0Smbuhl //	setsock(fd[0], SO_RCVBUF);
1022bd2f6f0Smbuhl 
1032bd2f6f0Smbuhl 	mmsgcnt = BUFSIZE / sizeof(DGRAM);
1042bd2f6f0Smbuhl 	mmsghdr = calloc(mmsgcnt, sizeof(*mmsghdr));
1052bd2f6f0Smbuhl 	ATF_REQUIRE_MSG(mmsghdr != NULL, "malloc failed (%s)", strerror(errno));
1062bd2f6f0Smbuhl 	iov = malloc(sizeof(*iov) * mmsgcnt);
1072bd2f6f0Smbuhl 	ATF_REQUIRE_MSG(iov != NULL, "malloc failed (%s)", strerror(errno));
1082bd2f6f0Smbuhl 
1092bd2f6f0Smbuhl 	for (off = 0, n = 0; n < mmsgcnt; n++) {
1102bd2f6f0Smbuhl 		iov[n].iov_base = buf + off;
1112bd2f6f0Smbuhl 		memcpy(iov[n].iov_base, DGRAM, sizeof(DGRAM));
1122bd2f6f0Smbuhl 		*(buf + off) = n;
1132bd2f6f0Smbuhl 		iov[n].iov_len = sizeof(DGRAM);
1142bd2f6f0Smbuhl 		off += iov[n].iov_len;
1152bd2f6f0Smbuhl 		mmsghdr[n].msg_hdr.msg_iov = &iov[n];
1162bd2f6f0Smbuhl 		mmsghdr[n].msg_hdr.msg_iovlen = 1;
1172bd2f6f0Smbuhl 		mmsghdr[n].msg_hdr.msg_name = NULL;
1182bd2f6f0Smbuhl 		mmsghdr[n].msg_hdr.msg_namelen = 0;
1192bd2f6f0Smbuhl 	}
1202bd2f6f0Smbuhl 
1212bd2f6f0Smbuhl 	memset(&sa, 0, sizeof(sa));
1222bd2f6f0Smbuhl 	sa.sa_flags = SA_RESTART;
1232bd2f6f0Smbuhl 	sa.sa_handler = &handle_sigchld;
1242bd2f6f0Smbuhl 	sigemptyset(&sa.sa_mask);
1252bd2f6f0Smbuhl 	error = sigaction(SIGCHLD, &sa, 0);
1262bd2f6f0Smbuhl 	ATF_REQUIRE_MSG(error != -1, "sigaction failed (%s)",
1272bd2f6f0Smbuhl 	    strerror(errno));
1282bd2f6f0Smbuhl 
1292bd2f6f0Smbuhl 	switch (fork()) {
1302bd2f6f0Smbuhl 	case -1:
1312bd2f6f0Smbuhl 		ATF_REQUIRE_MSG(0, "fork failed (%s)", strerror(errno));
1322bd2f6f0Smbuhl 		break;
1332bd2f6f0Smbuhl 	case 0:
1342bd2f6f0Smbuhl 		sched_yield();
1352bd2f6f0Smbuhl 		if (debug)
1362bd2f6f0Smbuhl 		    printf("sending %u messages (max %u per syscall)\n", n,
1372bd2f6f0Smbuhl 			mmsgcnt);
1382bd2f6f0Smbuhl 		for (n = 0; n < mmsgcnt;) {
1392bd2f6f0Smbuhl 			if (debug)
1402bd2f6f0Smbuhl 				printf("sending packet %u/%u...\n", n,
1412bd2f6f0Smbuhl 				    mmsgcnt);
1422bd2f6f0Smbuhl #ifdef __OpenBSD__
1432bd2f6f0Smbuhl 			int npkt = min(1024, mmsgcnt - n);
1442bd2f6f0Smbuhl #else
1452bd2f6f0Smbuhl 			// XXX: ENOBUFS bug, on the receive side!!!
1462bd2f6f0Smbuhl 			// in npkt = min(mmsgsize, mmsgcnt - n);
1472bd2f6f0Smbuhl 			int npkt = min(3, mmsgcnt - n), a;
1482bd2f6f0Smbuhl 			do {
1492bd2f6f0Smbuhl 				a = 0;
1502bd2f6f0Smbuhl 				ATF_REQUIRE(ioctl(fd[1], FIONSPACE, &a) != -1);
1512bd2f6f0Smbuhl 				printf("1 %d\n", a);
1522bd2f6f0Smbuhl 				ATF_REQUIRE(ioctl(fd[0], FIONSPACE, &a) != -1);
1532bd2f6f0Smbuhl 				printf("0 %d\n", a);
1542bd2f6f0Smbuhl 			} while ((size_t)a < sizeof(DGRAM));
1552bd2f6f0Smbuhl #endif
1562bd2f6f0Smbuhl 			cnt = sendmmsg(fd[1], mmsghdr + n, npkt, 0);
1572bd2f6f0Smbuhl 			if (cnt == -1 && errno == ENOBUFS) {
1582bd2f6f0Smbuhl 				overf++;
1592bd2f6f0Smbuhl 				if (debug)
1602bd2f6f0Smbuhl 					printf("send buffer overflowed"
1612bd2f6f0Smbuhl 					    " (%zu)\n",overf);
1622bd2f6f0Smbuhl 				if (overf > 100)
1632bd2f6f0Smbuhl 					exit(1);
1642bd2f6f0Smbuhl 				sched_yield();
1652bd2f6f0Smbuhl 				sched_yield();
1662bd2f6f0Smbuhl 				sched_yield();
1672bd2f6f0Smbuhl 				continue;
1682bd2f6f0Smbuhl 			}
1692bd2f6f0Smbuhl 			ATF_REQUIRE_MSG(cnt != -1, "sendmmsg %u failed (%s)",
1702bd2f6f0Smbuhl 			    n, strerror(errno));
1712bd2f6f0Smbuhl 			if (debug)
1722bd2f6f0Smbuhl 				printf("sendmmsg: sent %u messages\n", cnt);
1732bd2f6f0Smbuhl 			n += cnt;
1742bd2f6f0Smbuhl 			sched_yield();
1752bd2f6f0Smbuhl 			sched_yield();
1762bd2f6f0Smbuhl 			sched_yield();
1772bd2f6f0Smbuhl 		}
1782bd2f6f0Smbuhl 		if (debug)
1792bd2f6f0Smbuhl 			printf("done!\n");
1802bd2f6f0Smbuhl 		exit(0);
1812bd2f6f0Smbuhl 		/*NOTREACHED*/
1822bd2f6f0Smbuhl 	default:
1832bd2f6f0Smbuhl 		for (n = 0; n < mmsgcnt; n++) {
1842bd2f6f0Smbuhl 			if (debug)
1852bd2f6f0Smbuhl 				printf("receiving packet %u/%u...\n", n,
1862bd2f6f0Smbuhl 				    mmsgcnt);
1872bd2f6f0Smbuhl 			do {
1882bd2f6f0Smbuhl 				if (rdied)
1892bd2f6f0Smbuhl 					break;
1902bd2f6f0Smbuhl 				cnt = recv(fd[0], rgram, sizeof(rgram), 0);
1912bd2f6f0Smbuhl 				ATF_REQUIRE_MSG(cnt != -1 || errno != ENOBUFS,
1922bd2f6f0Smbuhl 				    "recv failed (%s)", strerror(errno));
1932bd2f6f0Smbuhl 				ATF_CHECK_EQ_MSG(cnt, sizeof(rgram),
1942bd2f6f0Smbuhl 				    "packet length");
1952bd2f6f0Smbuhl 				ATF_CHECK_EQ_MSG(rgram[0], n,
1962bd2f6f0Smbuhl 				    "number %u != %u", rgram[0], n);
1972bd2f6f0Smbuhl 				ATF_REQUIRE_MSG(memcmp(rgram + 1, DGRAM + 1,
1982bd2f6f0Smbuhl 				    sizeof(rgram) - 1) == 0, "bad data");
1992bd2f6f0Smbuhl 			} while (cnt == -1 && errno == ENOBUFS);
2002bd2f6f0Smbuhl 		}
2012bd2f6f0Smbuhl 		error = wait(&status);
2022bd2f6f0Smbuhl 		ATF_REQUIRE_MSG(error != -1, "wait failed (%s)",
2032bd2f6f0Smbuhl 		    strerror(errno));
2042bd2f6f0Smbuhl 		ATF_REQUIRE_MSG(WIFEXITED(status) && WEXITSTATUS(status) == 0,
205*613dad15Santon 		    "receiver died, status %d", status);
2062bd2f6f0Smbuhl 		break;
2072bd2f6f0Smbuhl 	}
2082bd2f6f0Smbuhl }
2092bd2f6f0Smbuhl 
ATF_TP_ADD_TCS(tp)2102bd2f6f0Smbuhl ATF_TP_ADD_TCS(tp)
2112bd2f6f0Smbuhl {
2122bd2f6f0Smbuhl 
2132bd2f6f0Smbuhl 	ATF_TP_ADD_TC(tp, sendmmsg_basic);
2142bd2f6f0Smbuhl 
2152bd2f6f0Smbuhl 	return atf_no_error();
2162bd2f6f0Smbuhl }
217