1 /* $OpenBSD: t_recvmmsg.c,v 1.2 2022/09/11 20:51:44 mbuhl Exp $ */ 2 /* $NetBSD: t_recvmmsg.c,v 1.4 2018/08/21 10:39:21 christos Exp $ */ 3 4 /*- 5 * Copyright (c) 2012 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Jared McNeill and Christos Zoulas. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the NetBSD 22 * Foundation, Inc. and its contributors. 23 * 4. Neither the name of The NetBSD Foundation nor the names of its 24 * contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 #include <sys/cdefs.h> 40 41 #include "atf-c.h" 42 #include <sys/types.h> 43 #include <sys/socket.h> 44 #include <sys/wait.h> 45 46 #include <string.h> 47 #include <time.h> 48 #include <stdint.h> 49 #include <errno.h> 50 #include <signal.h> 51 #include <stdio.h> 52 #include <stdlib.h> 53 #include <unistd.h> 54 #include <sched.h> 55 56 #define BUFSIZE 65536 57 #define NPKTS 50 58 59 #define min(a, b) ((a) < (b) ? (a) : (b)) 60 static int debug; 61 static volatile sig_atomic_t rdied; 62 63 static void 64 handle_sigchld(__unused int pid) 65 { 66 67 rdied = 1; 68 } 69 70 ATF_TC(recvmmsg_basic); 71 ATF_TC_HEAD(recvmmsg_basic, tc) 72 { 73 atf_tc_set_md_var(tc, "descr", "A basic test of recvmmsg(2)"); 74 } 75 76 ATF_TC_BODY(recvmmsg_basic, tc) 77 { 78 int fd[2], error, i, cnt; 79 uint8_t *buf; 80 struct mmsghdr *mmsghdr; 81 struct iovec *iov; 82 unsigned int mmsgcnt, n; 83 int status; 84 off_t off; 85 uint8_t DGRAM[1316] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, }; 86 struct sigaction sa; 87 ssize_t overf = 0; 88 89 error = socketpair(AF_UNIX, SOCK_DGRAM, 0, fd); 90 ATF_REQUIRE_MSG(error != -1, "socketpair failed (%s)", strerror(errno)); 91 92 buf = malloc(BUFSIZE); 93 ATF_REQUIRE_MSG(buf != NULL, "malloc failed (%s)", strerror(errno)); 94 95 mmsgcnt = BUFSIZE / sizeof(DGRAM); 96 mmsghdr = malloc(sizeof(*mmsghdr) * mmsgcnt); 97 ATF_REQUIRE_MSG(mmsghdr != NULL, "malloc failed (%s)", strerror(errno)); 98 iov = malloc(sizeof(*iov) * mmsgcnt); 99 ATF_REQUIRE_MSG(iov != NULL, "malloc failed (%s)", strerror(errno)); 100 101 for (off = 0, n = 0; n < mmsgcnt; n++) { 102 iov[n].iov_base = buf + off; 103 iov[n].iov_len = sizeof(DGRAM); 104 off += iov[n].iov_len; 105 mmsghdr[n].msg_hdr.msg_iov = &iov[n]; 106 mmsghdr[n].msg_hdr.msg_iovlen = 1; 107 mmsghdr[n].msg_hdr.msg_name = NULL; 108 mmsghdr[n].msg_hdr.msg_namelen = 0; 109 } 110 111 memset(&sa, 0, sizeof(sa)); 112 sa.sa_flags = SA_RESTART; 113 sa.sa_handler = &handle_sigchld; 114 sigemptyset(&sa.sa_mask); 115 error = sigaction(SIGCHLD, &sa, 0); 116 ATF_REQUIRE_MSG(error != -1, "sigaction failed (%s)", 117 strerror(errno)); 118 119 switch (fork()) { 120 case -1: 121 ATF_REQUIRE_MSG(0, "fork failed (%s)", strerror(errno)); 122 break; 123 124 case 0: 125 n = NPKTS; 126 if (debug) 127 printf("waiting for %u messages (max %u per syscall)\n", n, 128 mmsgcnt); 129 while (n > 0) { 130 struct timespec ts = { 1, 0 }; 131 cnt = recvmmsg(fd[1], mmsghdr, min(mmsgcnt, n), 132 MSG_WAITALL, &ts); 133 if (cnt == -1 && errno == ENOBUFS) { 134 overf++; 135 if (debug) 136 printf("receive buffer overflowed" 137 " (%zu)\n",overf); 138 continue; 139 } 140 ATF_REQUIRE_MSG(cnt != -1, "recvmmsg failed (%s)", 141 strerror(errno)); 142 ATF_REQUIRE_MSG(cnt != 0, "recvmmsg timeout"); 143 if (debug) 144 printf("recvmmsg: got %u messages\n", cnt); 145 for (i = 0; i < cnt; i++) { 146 ATF_CHECK_EQ_MSG(mmsghdr[i].msg_len, 147 sizeof(DGRAM), "packet length"); 148 ATF_CHECK_EQ_MSG( 149 ((uint8_t *)iov[i].iov_base)[0], 150 NPKTS - n + i, "packet contents"); 151 } 152 n -= cnt; 153 } 154 if (debug) 155 printf("done!\n"); 156 exit(0); 157 /*NOTREACHED*/ 158 default: 159 sched_yield(); 160 161 for (n = 0; n < NPKTS; n++) { 162 if (debug) 163 printf("sending packet %u/%u...\n", (n+1), 164 NPKTS); 165 do { 166 if (rdied) 167 break; 168 DGRAM[0] = n; 169 error = send(fd[0], DGRAM, sizeof(DGRAM), 0); 170 } while (error == -1 && errno == ENOBUFS); 171 ATF_REQUIRE_MSG(error != -1, "send failed (%s)", 172 strerror(errno)); 173 } 174 error = wait(&status); 175 ATF_REQUIRE_MSG(error != -1, "wait failed (%s)", 176 strerror(errno)); 177 ATF_REQUIRE_MSG(WIFEXITED(status) && WEXITSTATUS(status) == 0, 178 "receiver died"); 179 break; 180 } 181 } 182 183 ATF_TP_ADD_TCS(tp) 184 { 185 186 ATF_TP_ADD_TC(tp, recvmmsg_basic); 187 188 return atf_no_error(); 189 } 190