blob: 466b602db9e255ad5804038a17f2ee46ede7b787 [file] [log] [blame]
Dmitry V. Levin80bd8e12016-07-18 10:20:06 +00001/*
2 * Check decoding of msg_name* fields of struct msghdr array argument
3 * of sendmmsg and recvmmsg syscalls.
4 *
5 * Copyright (c) 2016 Dmitry V. Levin <ldv@altlinux.org>
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include "tests.h"
32
33#include <limits.h>
34#include <stddef.h>
35#include <stdio.h>
36#include <string.h>
37#include <unistd.h>
38#include <sys/un.h>
39
40#include "msghdr.h"
41
42#define DEFAULT_STRLEN 32
43
44#define IOV_MAX1 (IOV_MAX + 1)
45
46#ifndef TEST_NAME
47# define TEST_NAME "mmsg_name"
48#endif
49
50static void
51print_msghdr(const struct msghdr *const msg, const int user_msg_namelen)
52{
53 const struct sockaddr_un *const un = msg->msg_name;
54 const int offsetof_sun_path = offsetof(struct sockaddr_un, sun_path);
55
56 printf("{msg_name=");
57 if (user_msg_namelen < offsetof_sun_path) {
58 printf("%p", un);
59 } else {
60 printf("{sa_family=AF_UNIX");
61 if (user_msg_namelen > offsetof_sun_path) {
62 int len = user_msg_namelen < (int) msg->msg_namelen ?
63 user_msg_namelen : (int) msg->msg_namelen;
64 printf(", sun_path=\"%.*s\"",
65 len - offsetof_sun_path, un->sun_path);
66 }
67 printf("}");
68 }
69 printf(", msg_namelen=");
70 if (user_msg_namelen != (int) msg->msg_namelen) {
71 printf("%d->", user_msg_namelen);
72 }
73 printf("%d, msg_iov=[{iov_base=\"%c\", iov_len=1}]"
74 ", msg_iovlen=1, msg_controllen=0, msg_flags=0}",
75 (int) msg->msg_namelen, * (char *) msg->msg_iov[0].iov_base);
76}
77
78static void
79test_mmsg_name(const int send_fd, const int recv_fd)
80{
81 char *const send_buf = tail_alloc(sizeof(*send_buf) * IOV_MAX1);
82 struct iovec *const send_iov = tail_alloc(sizeof(*send_iov) * IOV_MAX1);
83 struct mmsghdr *const send_mh = tail_alloc(sizeof(*send_mh) * IOV_MAX1);
84
85 int i, rc;
86
87 for (i = 0; i < IOV_MAX1; ++i) {
88 send_buf[i] = '0' + i % 10;
89
90 send_iov[i].iov_base = &send_buf[i];
91 send_iov[i].iov_len = sizeof(*send_buf);
92
93 send_mh[i].msg_hdr.msg_iov = &send_iov[i];
94 send_mh[i].msg_hdr.msg_iovlen = 1;
95 send_mh[i].msg_hdr.msg_name = 0;
96 send_mh[i].msg_hdr.msg_namelen = 0;
97 send_mh[i].msg_hdr.msg_control = 0;
98 send_mh[i].msg_hdr.msg_controllen = 0;
99 send_mh[i].msg_hdr.msg_flags = 0;
100 }
101
102 rc = send_mmsg(send_fd, send_mh, IOV_MAX1, MSG_DONTWAIT);
103 if (rc < 0)
104 perror_msg_and_skip("sendmmsg");
105
106 printf("sendmmsg(%d, [", send_fd);
Dmitry V. Levin3a161d12016-07-18 16:25:25 +0000107 for (i = 0; i < IOV_MAX1; ++i) {
Dmitry V. Levin80bd8e12016-07-18 10:20:06 +0000108 if (i)
109 printf(", ");
Dmitry V. Levin3a161d12016-07-18 16:25:25 +0000110 if (i >= IOV_MAX
Dmitry V. Levin80bd8e12016-07-18 10:20:06 +0000111#ifndef VERBOSE_MMSGHDR
Dmitry V. Levin3a161d12016-07-18 16:25:25 +0000112 || i >= DEFAULT_STRLEN
113#endif
114 ) {
Dmitry V. Levin80bd8e12016-07-18 10:20:06 +0000115 printf("...");
116 break;
117 }
Dmitry V. Levin80bd8e12016-07-18 10:20:06 +0000118 printf("{msg_hdr={msg_name=NULL, msg_namelen=0"
119 ", msg_iov=[{iov_base=\"%c\", iov_len=1}]"
Dmitry V. Levin3a161d12016-07-18 16:25:25 +0000120 ", msg_iovlen=1, msg_controllen=0, msg_flags=0}%s}",
121 '0' + i % 10,
122 i < rc ? ", msg_len=1" : "");
Dmitry V. Levin80bd8e12016-07-18 10:20:06 +0000123 }
124 printf("], %u, MSG_DONTWAIT) = %d\n", IOV_MAX1, rc);
125
126 struct sockaddr_un *const recv_addr =
127 tail_alloc(sizeof(*recv_addr) * IOV_MAX1);
128 char *const recv_buf = tail_alloc(sizeof(*recv_buf) * IOV_MAX1);
129 struct iovec *const recv_iov = tail_alloc(sizeof(*recv_iov) * IOV_MAX1);
130 struct mmsghdr *const recv_mh = tail_alloc(sizeof(*recv_mh) * IOV_MAX1);
131
132 for (i = 0; i < IOV_MAX1; ++i) {
133 recv_iov[i].iov_base = &recv_buf[i];
134 recv_iov[i].iov_len = sizeof(*recv_buf);
135
136 recv_mh[i].msg_hdr.msg_name = &recv_addr[i];
137 recv_mh[i].msg_hdr.msg_namelen = i;
138 recv_mh[i].msg_hdr.msg_iov = &recv_iov[i];
139 recv_mh[i].msg_hdr.msg_iovlen = 1;
140 recv_mh[i].msg_hdr.msg_control = 0;
141 recv_mh[i].msg_hdr.msg_controllen = 0;
142 recv_mh[i].msg_hdr.msg_flags = 0;
143 }
144
145 rc = recv_mmsg(recv_fd, recv_mh, IOV_MAX1, MSG_DONTWAIT, 0);
146 if (rc < 0)
147 perror_msg_and_skip("recvmmsg");
148
149 printf("recvmmsg(%d, [", recv_fd);
150 for (i = 0; i < rc; ++i) {
151 if (i)
152 printf(", ");
153#ifndef VERBOSE_MMSGHDR
154 if (i >= DEFAULT_STRLEN) {
155 printf("...");
156 break;
157 }
158#endif
159 printf("{msg_hdr=");
160 print_msghdr(&recv_mh[i].msg_hdr, i);
161 printf(", msg_len=1}");
162 }
163 printf("], %u, MSG_DONTWAIT, NULL) = %d\n", IOV_MAX1, rc);
164}
165
166int
167main(void)
168{
169 int fds[2];
170 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds))
171 perror_msg_and_skip("socketpair");
172
173 const struct sockaddr_un un = {
174 .sun_family = AF_UNIX,
175 .sun_path = TEST_NAME "-recvmmsg.test.send.socket"
176 };
177
178 (void) unlink(un.sun_path);
179 if (bind(fds[1], (const void *) &un, sizeof(un)))
180 perror_msg_and_skip("bind");
181 (void) unlink(un.sun_path);
182
183 test_mmsg_name(fds[1], fds[0]);
184
185 puts("+++ exited with 0 +++");
186 return 0;
187}