1 /* $NetBSD: t_recvmmsg.c,v 1.1 2012/06/22 18:45:23 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.1 2012/06/22 18:45:23 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 <stdio.h> 51 #include <stdlib.h> 52 #include <unistd.h> 53 #include <sched.h> 54 55 #define BUFSIZE 65536 56 #define NPKTS 50 57 58 #define min(a, b) ((a) < (b) ? (a) : (b)) 59 static int debug; 60 61 62 ATF_TC(recvmmsg_basic); 63 ATF_TC_HEAD(recvmmsg_basic, tc) 64 { 65 atf_tc_set_md_var(tc, "descr", "A basic test of recvmmsg(2)"); 66 } 67 68 ATF_TC_BODY(recvmmsg_basic, tc) 69 { 70 int fd[2], error, i, cnt; 71 uint8_t *buf; 72 struct mmsghdr *mmsghdr; 73 struct iovec *iov; 74 unsigned int mmsgcnt, n; 75 int status; 76 off_t off; 77 uint8_t DGRAM[1316] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, }; 78 79 error = socketpair(AF_UNIX, SOCK_DGRAM, 0, fd); 80 ATF_REQUIRE_MSG(error != -1, "socketpair failed (%s)", strerror(errno)); 81 82 buf = malloc(BUFSIZE); 83 ATF_REQUIRE_MSG(buf != NULL, "malloc failed (%s)", strerror(errno)); 84 85 mmsgcnt = BUFSIZE / sizeof(DGRAM); 86 mmsghdr = malloc(sizeof(*mmsghdr) * mmsgcnt); 87 ATF_REQUIRE_MSG(mmsghdr != NULL, "malloc failed (%s)", strerror(errno)); 88 iov = malloc(sizeof(*iov) * mmsgcnt); 89 ATF_REQUIRE_MSG(iov != NULL, "malloc failed (%s)", strerror(errno)); 90 91 for (off = 0, n = 0; n < mmsgcnt; n++) { 92 iov[n].iov_base = buf + off; 93 iov[n].iov_len = sizeof(DGRAM); 94 off += iov[n].iov_len; 95 mmsghdr[n].msg_hdr.msg_iov = &iov[n]; 96 mmsghdr[n].msg_hdr.msg_iovlen = 1; 97 mmsghdr[n].msg_hdr.msg_name = NULL; 98 mmsghdr[n].msg_hdr.msg_namelen = 0; 99 } 100 101 switch (fork()) { 102 case -1: 103 ATF_REQUIRE_MSG(0, "fork failed (%s)", strerror(errno)); 104 break; 105 106 case 0: 107 n = NPKTS; 108 if (debug) 109 printf("waiting for %u messages (max %u per syscall)\n", n, 110 mmsgcnt); 111 while (n > 0) { 112 struct timespec ts = { 1, 0 }; 113 cnt = recvmmsg(fd[1], mmsghdr, min(mmsgcnt, n), 114 MSG_WAITALL, &ts); 115 ATF_REQUIRE_MSG(cnt != -1, "recvmmsg failed (%s)", 116 strerror(errno)); 117 ATF_REQUIRE_MSG(cnt != 0, "recvmmsg timeout"); 118 if (debug) 119 printf("recvmmsg: got %u messages\n", cnt); 120 for (i = 0; i < cnt; i++) { 121 ATF_CHECK_EQ_MSG(mmsghdr[i].msg_len, 122 sizeof(DGRAM), "packet length"); 123 ATF_CHECK_EQ_MSG( 124 ((uint8_t *)iov[i].iov_base)[0], 125 NPKTS - n + i, "packet contents"); 126 } 127 n -= cnt; 128 } 129 if (debug) 130 printf("done!\n"); 131 exit(0); 132 /*NOTREACHED*/ 133 default: 134 sched_yield(); 135 136 for (n = 0; n < NPKTS; n++) { 137 if (debug) 138 printf("sending packet %u/%u...\n", (n+1), 139 NPKTS); 140 do { 141 DGRAM[0] = n; 142 error = send(fd[0], DGRAM, sizeof(DGRAM), 0); 143 } while (error == -1 && errno == ENOBUFS); 144 if (error == -1) 145 ATF_REQUIRE_MSG(error != -1, "send failed (%s)", 146 strerror(errno)); 147 } 148 error = wait(&status); 149 ATF_REQUIRE_MSG(error != -1, "wait failed (%s)", 150 strerror(errno)); 151 break; 152 } 153 } 154 155 ATF_TP_ADD_TCS(tp) 156 { 157 158 ATF_TP_ADD_TC(tp, recvmmsg_basic); 159 160 return atf_no_error(); 161 } 162