1/* $NetBSD: t_recvmmsg.c,v 1.4 2018/08/21 10:39:21 christos Exp $ */ 2 3/*- 4 * Copyright (c) 2012 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jared McNeill and Christos Zoulas. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38#include <sys/cdefs.h> 39__RCSID("$NetBSD: t_recvmmsg.c,v 1.4 2018/08/21 10:39:21 christos Exp $"); 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)) 60static int debug; 61static volatile sig_atomic_t rdied; 62 63static void 64handle_sigchld(__unused int pid) 65{ 66 67 rdied = 1; 68} 69 70ATF_TC(recvmmsg_basic); 71ATF_TC_HEAD(recvmmsg_basic, tc) 72{ 73 atf_tc_set_md_var(tc, "descr", "A basic test of recvmmsg(2)"); 74} 75 76ATF_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 183ATF_TP_ADD_TCS(tp) 184{ 185 186 ATF_TP_ADD_TC(tp, recvmmsg_basic); 187 188 return atf_no_error(); 189} 190