blob: e90cafdb086b4e527e076e1763c887e72ede9b24 [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);
107 for (i = 0; i < rc; ++i) {
108 if (i)
109 printf(", ");
110#ifndef VERBOSE_MMSGHDR
111 if (i >= DEFAULT_STRLEN) {
112 printf("...");
113 break;
114 }
115#endif
116 printf("{msg_hdr={msg_name=NULL, msg_namelen=0"
117 ", msg_iov=[{iov_base=\"%c\", iov_len=1}]"
118 ", msg_iovlen=1, msg_controllen=0, msg_flags=0}"
119 ", msg_len=1}", '0' + i % 10);
120 }
121 printf("], %u, MSG_DONTWAIT) = %d\n", IOV_MAX1, rc);
122
123 struct sockaddr_un *const recv_addr =
124 tail_alloc(sizeof(*recv_addr) * IOV_MAX1);
125 char *const recv_buf = tail_alloc(sizeof(*recv_buf) * IOV_MAX1);
126 struct iovec *const recv_iov = tail_alloc(sizeof(*recv_iov) * IOV_MAX1);
127 struct mmsghdr *const recv_mh = tail_alloc(sizeof(*recv_mh) * IOV_MAX1);
128
129 for (i = 0; i < IOV_MAX1; ++i) {
130 recv_iov[i].iov_base = &recv_buf[i];
131 recv_iov[i].iov_len = sizeof(*recv_buf);
132
133 recv_mh[i].msg_hdr.msg_name = &recv_addr[i];
134 recv_mh[i].msg_hdr.msg_namelen = i;
135 recv_mh[i].msg_hdr.msg_iov = &recv_iov[i];
136 recv_mh[i].msg_hdr.msg_iovlen = 1;
137 recv_mh[i].msg_hdr.msg_control = 0;
138 recv_mh[i].msg_hdr.msg_controllen = 0;
139 recv_mh[i].msg_hdr.msg_flags = 0;
140 }
141
142 rc = recv_mmsg(recv_fd, recv_mh, IOV_MAX1, MSG_DONTWAIT, 0);
143 if (rc < 0)
144 perror_msg_and_skip("recvmmsg");
145
146 printf("recvmmsg(%d, [", recv_fd);
147 for (i = 0; i < rc; ++i) {
148 if (i)
149 printf(", ");
150#ifndef VERBOSE_MMSGHDR
151 if (i >= DEFAULT_STRLEN) {
152 printf("...");
153 break;
154 }
155#endif
156 printf("{msg_hdr=");
157 print_msghdr(&recv_mh[i].msg_hdr, i);
158 printf(", msg_len=1}");
159 }
160 printf("], %u, MSG_DONTWAIT, NULL) = %d\n", IOV_MAX1, rc);
161}
162
163int
164main(void)
165{
166 int fds[2];
167 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds))
168 perror_msg_and_skip("socketpair");
169
170 const struct sockaddr_un un = {
171 .sun_family = AF_UNIX,
172 .sun_path = TEST_NAME "-recvmmsg.test.send.socket"
173 };
174
175 (void) unlink(un.sun_path);
176 if (bind(fds[1], (const void *) &un, sizeof(un)))
177 perror_msg_and_skip("bind");
178 (void) unlink(un.sun_path);
179
180 test_mmsg_name(fds[1], fds[0]);
181
182 puts("+++ exited with 0 +++");
183 return 0;
184}