]>
Commit | Line | Data |
---|---|---|
c3c9b80d A |
1 | /* |
2 | * Copyright (c) 2020 Apple Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * This file contains Original Code and/or Modifications of Original Code | |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. The rights granted to you under the License | |
10 | * may not be used to create, or enable the creation or redistribution of, | |
11 | * unlawful or unlicensed copies of an Apple operating system, or to | |
12 | * circumvent, violate, or enable the circumvention or violation of, any | |
13 | * terms of an Apple operating system software license agreement. | |
14 | * | |
15 | * Please obtain a copy of the License at | |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
17 | * | |
18 | * The Original Code and all software distributed under the License are | |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
23 | * Please see the License for the specific language governing rights and | |
24 | * limitations under the License. | |
25 | * | |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ | |
27 | */ | |
28 | ||
29 | /* -*- compile-command: "xcrun --sdk iphoneos.internal make recvmsg_x_test" -*- */ | |
30 | ||
31 | ||
32 | #include <sys/errno.h> | |
33 | #include <sys/fcntl.h> | |
34 | #include <sys/socket.h> | |
35 | #include <netinet/in.h> | |
36 | #include <stdbool.h> | |
37 | #include <err.h> | |
38 | #include <stdio.h> | |
39 | #include <stdlib.h> | |
40 | #include <string.h> | |
41 | #include <sysexits.h> | |
42 | #include <unistd.h> | |
43 | ||
44 | #include <darwintest.h> | |
45 | #include <darwintest_utils.h> | |
46 | ||
47 | #define NMSGS 5 | |
48 | #define BUFFERLEN 1000 | |
49 | ||
50 | T_GLOBAL_META(T_META_NAMESPACE("xnu.net")); | |
51 | ||
52 | static void | |
53 | sendPackets(int s, struct sockaddr *dst, unsigned int numMsg, size_t bufferLen) | |
54 | { | |
55 | ssize_t count = 0; | |
56 | struct msghdr msg = {}; | |
57 | struct iovec vec = {}; | |
58 | char *bytes = calloc(1, bufferLen); | |
59 | if (bytes == NULL) { | |
60 | err(EX_OSERR, "calloc()"); | |
61 | } | |
62 | ||
63 | vec.iov_base = bytes; | |
64 | vec.iov_len = bufferLen; | |
65 | ||
66 | msg.msg_name = (void *)dst; | |
67 | msg.msg_namelen = dst->sa_len; | |
68 | msg.msg_iov = &vec; | |
69 | msg.msg_iovlen = 1; | |
70 | msg.msg_flags = 0; | |
71 | ||
72 | for (unsigned int i = 0; i < numMsg; i++) { | |
73 | ssize_t n; | |
74 | T_QUIET; T_EXPECT_POSIX_SUCCESS(n = sendmsg(s, &msg, 0), "sendmsg()"); | |
75 | T_LOG("Sent %ld bytes\n", n); | |
76 | count += 1; | |
77 | } | |
78 | ||
79 | // Wait a bit to make sure the packets reach the receiver | |
80 | usleep(100000); | |
81 | ||
82 | T_LOG("Sent %ld packet\n", count); | |
83 | ||
84 | free(bytes); | |
85 | } | |
86 | ||
87 | static void | |
88 | recvPackets_x(int s, unsigned int numMsg, size_t buflen, socklen_t cmsgLen) | |
89 | { | |
90 | struct msghdr_x *msgList; | |
91 | struct sockaddr_in *srcAddrs; | |
92 | struct iovec *vec; | |
93 | char *buffers; | |
94 | char *cmsgBuf; | |
95 | ||
96 | T_QUIET; T_ASSERT_NOTNULL(msgList = calloc(numMsg, sizeof(struct msghdr_x)), "msgList calloc()"); | |
97 | T_QUIET; T_ASSERT_NOTNULL(srcAddrs = calloc(numMsg, sizeof(struct sockaddr_in)), "srcAddrs calloc()"); | |
98 | T_QUIET; T_ASSERT_NOTNULL(vec = calloc(numMsg, sizeof(struct iovec)), "vec calloc()"); | |
99 | T_QUIET; T_ASSERT_NOTNULL(buffers = calloc(numMsg, buflen), "buffers calloc()"); | |
100 | T_QUIET; T_ASSERT_NOTNULL(cmsgBuf = calloc(numMsg, ALIGN(cmsgLen)), "cmsgBuf calloc()"); | |
101 | ||
102 | u_int count = 0; | |
103 | while (true) { | |
104 | /* | |
105 | * Wrap around when we've exhausted the list | |
106 | */ | |
107 | if ((count % numMsg) == 0) { | |
108 | for (unsigned int i = 0; i < numMsg; i++) { | |
109 | struct msghdr_x *msg = &msgList[i]; | |
110 | msg->msg_name = &srcAddrs[i]; | |
111 | msg->msg_namelen = sizeof(srcAddrs[i]); | |
112 | vec[i].iov_base = buffers + (i * buflen); | |
113 | vec[i].iov_len = buflen; | |
114 | msg->msg_iov = &vec[i]; | |
115 | msg->msg_iovlen = 1; | |
116 | msg->msg_control = cmsgBuf + (i * ALIGN(cmsgLen)); | |
117 | msg->msg_controllen = cmsgLen; | |
118 | msg->msg_flags = 0; | |
119 | ||
120 | T_QUIET; T_EXPECT_TRUE((uintptr_t)msg->msg_control % sizeof(uint32_t) == 0, NULL); | |
121 | } | |
122 | } | |
123 | ||
124 | ssize_t n = recvmsg_x(s, msgList + (count % numMsg), numMsg - (count % numMsg), 0); | |
125 | if (n < 0) { | |
126 | if (errno == EINTR) { | |
127 | T_LOG("recvmsg_x(): %s", strerror(errno)); | |
128 | continue; | |
129 | } | |
130 | if (errno == EWOULDBLOCK) { | |
131 | T_LOG("recvmsg_x(): %s", strerror(errno)); | |
132 | break; | |
133 | } | |
134 | T_FAIL("recvmsg_x() failed: %s", strerror(errno)); | |
135 | } | |
136 | T_LOG("recvmsg_x returned %ld packets\n", n); | |
137 | ||
138 | for (unsigned int i = count; i < count + (u_int)n; i++) { | |
139 | struct msghdr_x *msg = &msgList[i % numMsg]; | |
140 | ||
141 | T_LOG("Received packet #%d %lu bytes with recvmsg_x(), msg_namelen = %u, msg_controllen = %d -> %d, msg_flags = 0x%x\n", | |
142 | i + 1, msg->msg_datalen, msg->msg_namelen, cmsgLen, msg->msg_controllen, msg->msg_flags); | |
143 | ||
144 | struct cmsghdr *cmsg; | |
145 | ||
146 | for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) { | |
147 | T_QUIET; T_EXPECT_TRUE((uintptr_t)cmsg % sizeof(uint32_t) == 0, NULL); | |
148 | ||
149 | T_LOG("level = %d, type = %d, length = %d\n", cmsg->cmsg_level, cmsg->cmsg_type, cmsg->cmsg_len); | |
150 | } | |
151 | } | |
152 | ||
153 | count += (u_int)n; | |
154 | } | |
155 | ||
156 | free(msgList); | |
157 | free(srcAddrs); | |
158 | free(vec); | |
159 | free(buffers); | |
160 | free(cmsgBuf); | |
161 | } | |
162 | ||
163 | T_DECL(recvmsg_x_test, "exercise revcmsg_x() with various parameter") | |
164 | { | |
165 | struct sockaddr_in addr = { | |
166 | .sin_len = sizeof(addr), | |
167 | .sin_family = AF_INET, | |
168 | .sin_addr.s_addr = htonl(0x7f000001), | |
169 | .sin_port = 0 | |
170 | }; | |
171 | ||
172 | int recvSocket; | |
173 | T_QUIET; T_EXPECT_POSIX_SUCCESS(recvSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP), "socket()"); | |
174 | T_QUIET; T_EXPECT_POSIX_SUCCESS(bind(recvSocket, (const struct sockaddr *)&addr, sizeof(addr)), "bind()"); | |
175 | ||
176 | socklen_t addrLen = sizeof(addr); | |
177 | T_QUIET; T_EXPECT_POSIX_SUCCESS(getsockname(recvSocket, (struct sockaddr *)&addr, &addrLen), "getsockname()"); | |
178 | ||
179 | int one = 1; | |
180 | T_QUIET; T_EXPECT_POSIX_SUCCESS(setsockopt(recvSocket, IPPROTO_IP, IP_RECVPKTINFO, (void *)&one, sizeof(one)), "setsockopt(IP_RECVPKTINFO)"); | |
181 | ||
182 | int flags = fcntl(recvSocket, F_GETFL, 0); | |
183 | T_QUIET; T_EXPECT_POSIX_SUCCESS(fcntl(recvSocket, F_SETFL, flags | O_NONBLOCK), "fcntl()"); | |
184 | ||
185 | int sendSocket; | |
186 | T_QUIET; T_EXPECT_POSIX_SUCCESS(sendSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP), "sendSocket socket()"); | |
187 | ||
188 | for (int dontTrunc = 0; dontTrunc <= 1; dontTrunc++) { | |
189 | T_QUIET; T_EXPECT_POSIX_SUCCESS(setsockopt(recvSocket, SOL_SOCKET, SO_DONTTRUNC, (void *)&dontTrunc, sizeof(dontTrunc)), "setsockopt(SO_DONTTRUNC)"); | |
190 | ||
191 | T_LOG("\n================= recvmsg_x() test =================\n"); | |
192 | sendPackets(sendSocket, (struct sockaddr *)&addr, NMSGS, BUFFERLEN); | |
193 | recvPackets_x(recvSocket, NMSGS, BUFFERLEN, 50); | |
194 | ||
195 | T_LOG("\n================= recvmsg_x() test =================\n"); | |
196 | sendPackets(sendSocket, (struct sockaddr *)&addr, NMSGS, BUFFERLEN); | |
197 | recvPackets_x(recvSocket, NMSGS, BUFFERLEN * 2, 50); | |
198 | ||
199 | T_LOG("\n================= recvmsg_x() test =================\n"); | |
200 | sendPackets(sendSocket, (struct sockaddr *)&addr, NMSGS, BUFFERLEN); | |
201 | recvPackets_x(recvSocket, NMSGS, BUFFERLEN / 2, 50); | |
202 | ||
203 | T_LOG("\n================= recvmsg_x() test =================\n"); | |
204 | sendPackets(sendSocket, (struct sockaddr *)&addr, NMSGS, BUFFERLEN); | |
205 | recvPackets_x(recvSocket, NMSGS, BUFFERLEN, 10); | |
206 | ||
207 | T_LOG("\n================= recvmsg_x() test =================\n"); | |
208 | sendPackets(sendSocket, (struct sockaddr *)&addr, NMSGS, BUFFERLEN); | |
209 | recvPackets_x(recvSocket, NMSGS, BUFFERLEN / 2, 10); | |
210 | } | |
211 | ||
212 | close(sendSocket); | |
213 | close(recvSocket); | |
214 | ||
215 | T_LOG("\n================= PASS =================\n"); | |
216 | } |