xref: /illumos-gate/usr/src/test/os-tests/tests/sockfs/recvmsg.c (revision 221e47fb90c5fcfe7add9a33f6c915ee5253ece9)
1*221e47fbSAndy Fiddaman /*
2*221e47fbSAndy Fiddaman  * This file and its contents are supplied under the terms of the
3*221e47fbSAndy Fiddaman  * Common Development and Distribution License ("CDDL"), version 1.0.
4*221e47fbSAndy Fiddaman  * You may only use this file in accordance with the terms of version
5*221e47fbSAndy Fiddaman  * 1.0 of the CDDL.
6*221e47fbSAndy Fiddaman  *
7*221e47fbSAndy Fiddaman  * A full copy of the text of the CDDL should have accompanied this
8*221e47fbSAndy Fiddaman  * source.  A copy of the CDDL is also available via the Internet at
9*221e47fbSAndy Fiddaman  * http://www.illumos.org/license/CDDL.
10*221e47fbSAndy Fiddaman  */
11*221e47fbSAndy Fiddaman 
12*221e47fbSAndy Fiddaman /*
13*221e47fbSAndy Fiddaman  * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
14*221e47fbSAndy Fiddaman  */
15*221e47fbSAndy Fiddaman 
16*221e47fbSAndy Fiddaman /*
17*221e47fbSAndy Fiddaman  * Test ancillary data receipt via recvmsg()
18*221e47fbSAndy Fiddaman  */
19*221e47fbSAndy Fiddaman 
20*221e47fbSAndy Fiddaman #include <stdio.h>
21*221e47fbSAndy Fiddaman #include <errno.h>
22*221e47fbSAndy Fiddaman #include <fcntl.h>
23*221e47fbSAndy Fiddaman #include <signal.h>
24*221e47fbSAndy Fiddaman #include <stdlib.h>
25*221e47fbSAndy Fiddaman #include <string.h>
26*221e47fbSAndy Fiddaman #include <strings.h>
27*221e47fbSAndy Fiddaman #include <unistd.h>
28*221e47fbSAndy Fiddaman 
29*221e47fbSAndy Fiddaman #include <sys/types.h>
30*221e47fbSAndy Fiddaman #include <sys/param.h>
31*221e47fbSAndy Fiddaman #include <sys/socket.h>
32*221e47fbSAndy Fiddaman #include <sys/stat.h>
33*221e47fbSAndy Fiddaman #include <netinet/in.h>
34*221e47fbSAndy Fiddaman #include <arpa/inet.h>
35*221e47fbSAndy Fiddaman #include <sys/wait.h>
36*221e47fbSAndy Fiddaman #include <pthread.h>
37*221e47fbSAndy Fiddaman #include <err.h>
38*221e47fbSAndy Fiddaman 
39*221e47fbSAndy Fiddaman static boolean_t debug;
40*221e47fbSAndy Fiddaman static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
41*221e47fbSAndy Fiddaman static pthread_cond_t cv = PTHREAD_COND_INITIALIZER;
42*221e47fbSAndy Fiddaman static pthread_mutex_t cmutex = PTHREAD_MUTEX_INITIALIZER;
43*221e47fbSAndy Fiddaman static pthread_cond_t ccv = PTHREAD_COND_INITIALIZER;
44*221e47fbSAndy Fiddaman static boolean_t server_ready = _B_FALSE;
45*221e47fbSAndy Fiddaman static boolean_t client_done = _B_FALSE;
46*221e47fbSAndy Fiddaman 
47*221e47fbSAndy Fiddaman static in_addr_t testip;
48*221e47fbSAndy Fiddaman 
49*221e47fbSAndy Fiddaman #define	DEBUG(x) if (debug) printf x
50*221e47fbSAndy Fiddaman 
51*221e47fbSAndy Fiddaman #define	TESTPORT	32123
52*221e47fbSAndy Fiddaman 
53*221e47fbSAndy Fiddaman #define	RT_RECVTOS	0x1
54*221e47fbSAndy Fiddaman #define	RT_RECVTTL	0x2
55*221e47fbSAndy Fiddaman #define	RT_RECVPKTINFO	0x4
56*221e47fbSAndy Fiddaman #define	RT_RECVMASK	0x7
57*221e47fbSAndy Fiddaman 
58*221e47fbSAndy Fiddaman #define	RT_SETTOS	0x10
59*221e47fbSAndy Fiddaman #define	RT_SETTTL	0x20
60*221e47fbSAndy Fiddaman #define	RT_STREAM	0x40
61*221e47fbSAndy Fiddaman #define	RT_SKIP		0x80
62*221e47fbSAndy Fiddaman 
63*221e47fbSAndy Fiddaman typedef struct recvmsg_test {
64*221e47fbSAndy Fiddaman 	char *name;		/* Name of the test */
65*221e47fbSAndy Fiddaman 	uint8_t tos;		/* TOS to set */
66*221e47fbSAndy Fiddaman 	uint8_t ttl;		/* TTL to set */
67*221e47fbSAndy Fiddaman 	uint8_t flags;		/* Test flags, RT_ */
68*221e47fbSAndy Fiddaman } recvmsg_test_t;
69*221e47fbSAndy Fiddaman 
70*221e47fbSAndy Fiddaman static recvmsg_test_t tests[] = {
71*221e47fbSAndy Fiddaman 	{
72*221e47fbSAndy Fiddaman 		.name = "baseline",
73*221e47fbSAndy Fiddaman 		.flags = 0,
74*221e47fbSAndy Fiddaman 	},
75*221e47fbSAndy Fiddaman 
76*221e47fbSAndy Fiddaman 	/* Combinations of receive flags */
77*221e47fbSAndy Fiddaman 	{
78*221e47fbSAndy Fiddaman 		.name = "recv TOS",
79*221e47fbSAndy Fiddaman 		.flags = RT_RECVTOS,
80*221e47fbSAndy Fiddaman 	},
81*221e47fbSAndy Fiddaman 
82*221e47fbSAndy Fiddaman 	{
83*221e47fbSAndy Fiddaman 		.name = "recv TTL",
84*221e47fbSAndy Fiddaman 		.flags = RT_RECVTTL,
85*221e47fbSAndy Fiddaman 	},
86*221e47fbSAndy Fiddaman 
87*221e47fbSAndy Fiddaman 	{
88*221e47fbSAndy Fiddaman 		.name = "recv PKTINFO",
89*221e47fbSAndy Fiddaman 		.flags = RT_RECVPKTINFO,
90*221e47fbSAndy Fiddaman 	},
91*221e47fbSAndy Fiddaman 
92*221e47fbSAndy Fiddaman 	{
93*221e47fbSAndy Fiddaman 		.name = "recv TOS,TTL",
94*221e47fbSAndy Fiddaman 		.flags = RT_RECVTOS | RT_RECVTTL,
95*221e47fbSAndy Fiddaman 	},
96*221e47fbSAndy Fiddaman 
97*221e47fbSAndy Fiddaman 	{
98*221e47fbSAndy Fiddaman 		.name = "recv TTL,PKTINFO",
99*221e47fbSAndy Fiddaman 		.flags = RT_RECVTTL | RT_RECVPKTINFO,
100*221e47fbSAndy Fiddaman 	},
101*221e47fbSAndy Fiddaman 
102*221e47fbSAndy Fiddaman 	{
103*221e47fbSAndy Fiddaman 		.name = "recv TOS,PKTINFO",
104*221e47fbSAndy Fiddaman 		.flags = RT_RECVTOS | RT_RECVPKTINFO,
105*221e47fbSAndy Fiddaman 	},
106*221e47fbSAndy Fiddaman 
107*221e47fbSAndy Fiddaman 	{
108*221e47fbSAndy Fiddaman 		.name = "recv TOS,TTL,PKTINFO",
109*221e47fbSAndy Fiddaman 		.flags = RT_RECVTOS | RT_RECVTTL | RT_RECVPKTINFO,
110*221e47fbSAndy Fiddaman 	},
111*221e47fbSAndy Fiddaman 
112*221e47fbSAndy Fiddaman 	/* Manually set TTL and TOS */
113*221e47fbSAndy Fiddaman 
114*221e47fbSAndy Fiddaman 	{
115*221e47fbSAndy Fiddaman 		.name = "set TOS,TTL",
116*221e47fbSAndy Fiddaman 		.flags = RT_SETTOS | RT_SETTTL,
117*221e47fbSAndy Fiddaman 		.ttl = 11,
118*221e47fbSAndy Fiddaman 		.tos = 0xe0
119*221e47fbSAndy Fiddaman 	},
120*221e47fbSAndy Fiddaman 
121*221e47fbSAndy Fiddaman 	{
122*221e47fbSAndy Fiddaman 		.name = "set/recv TOS,TTL",
123*221e47fbSAndy Fiddaman 		.flags = RT_SETTOS | RT_SETTTL | RT_RECVTOS | RT_RECVTTL,
124*221e47fbSAndy Fiddaman 		.ttl = 32,
125*221e47fbSAndy Fiddaman 		.tos = 0x48
126*221e47fbSAndy Fiddaman 	},
127*221e47fbSAndy Fiddaman 
128*221e47fbSAndy Fiddaman 	{
129*221e47fbSAndy Fiddaman 		.name = "set TOS,TTL, recv PKTINFO",
130*221e47fbSAndy Fiddaman 		.flags = RT_SETTOS | RT_SETTTL | RT_RECVPKTINFO,
131*221e47fbSAndy Fiddaman 		.ttl = 173,
132*221e47fbSAndy Fiddaman 		.tos = 0x78
133*221e47fbSAndy Fiddaman 	},
134*221e47fbSAndy Fiddaman 
135*221e47fbSAndy Fiddaman 	{
136*221e47fbSAndy Fiddaman 		.name = "set TOS,TTL, recv TOS,TTL,PKTINFO",
137*221e47fbSAndy Fiddaman 		.flags = RT_SETTOS | RT_SETTTL | RT_RECVTOS | RT_RECVTTL |
138*221e47fbSAndy Fiddaman 		    RT_RECVPKTINFO,
139*221e47fbSAndy Fiddaman 		.ttl = 54,
140*221e47fbSAndy Fiddaman 		.tos = 0x90
141*221e47fbSAndy Fiddaman 	},
142*221e47fbSAndy Fiddaman 
143*221e47fbSAndy Fiddaman 	/* STREAM socket */
144*221e47fbSAndy Fiddaman 
145*221e47fbSAndy Fiddaman 	{
146*221e47fbSAndy Fiddaman 		.name = "STREAM set TOS",
147*221e47fbSAndy Fiddaman 		.flags = RT_STREAM | RT_SETTOS,
148*221e47fbSAndy Fiddaman 		.tos = 0xe0
149*221e47fbSAndy Fiddaman 	},
150*221e47fbSAndy Fiddaman 
151*221e47fbSAndy Fiddaman 	/*
152*221e47fbSAndy Fiddaman 	 * The ancillary data are not returned for the loopback TCP path,
153*221e47fbSAndy Fiddaman 	 * so these tests are skipped by default.
154*221e47fbSAndy Fiddaman 	 * To run them, use two different zones (or machines) and run:
155*221e47fbSAndy Fiddaman 	 *	recvmsg.64 -s 'test name'
156*221e47fbSAndy Fiddaman 	 * on the first, and:
157*221e47fbSAndy Fiddaman 	 *	recvmsg.64 -c <first machine IP> 'test name'
158*221e47fbSAndy Fiddaman 	 * on the second.
159*221e47fbSAndy Fiddaman 	 */
160*221e47fbSAndy Fiddaman 	{
161*221e47fbSAndy Fiddaman 		.name = "STREAM recv TOS",
162*221e47fbSAndy Fiddaman 		.flags = RT_STREAM | RT_RECVTOS | RT_SKIP,
163*221e47fbSAndy Fiddaman 	},
164*221e47fbSAndy Fiddaman 
165*221e47fbSAndy Fiddaman 	{
166*221e47fbSAndy Fiddaman 		.name = "STREAM set/recv TOS",
167*221e47fbSAndy Fiddaman 		.flags = RT_STREAM | RT_SETTOS | RT_RECVTOS | RT_SKIP,
168*221e47fbSAndy Fiddaman 		.tos = 0x48
169*221e47fbSAndy Fiddaman 	},
170*221e47fbSAndy Fiddaman 
171*221e47fbSAndy Fiddaman 	/* End of tests */
172*221e47fbSAndy Fiddaman 
173*221e47fbSAndy Fiddaman 	{
174*221e47fbSAndy Fiddaman 		.name = NULL
175*221e47fbSAndy Fiddaman 	}
176*221e47fbSAndy Fiddaman };
177*221e47fbSAndy Fiddaman 
178*221e47fbSAndy Fiddaman static boolean_t
servertest(recvmsg_test_t * t)179*221e47fbSAndy Fiddaman servertest(recvmsg_test_t *t)
180*221e47fbSAndy Fiddaman {
181*221e47fbSAndy Fiddaman 	struct sockaddr_in addr;
182*221e47fbSAndy Fiddaman 	boolean_t pass = _B_TRUE;
183*221e47fbSAndy Fiddaman 	int sockfd, readfd, acceptfd = -1, c = 1;
184*221e47fbSAndy Fiddaman 
185*221e47fbSAndy Fiddaman 	DEBUG(("\nserver %s: starting\n", t->name));
186*221e47fbSAndy Fiddaman 
187*221e47fbSAndy Fiddaman 	sockfd = socket(AF_INET,
188*221e47fbSAndy Fiddaman 	    t->flags & RT_STREAM ? SOCK_STREAM : SOCK_DGRAM, 0);
189*221e47fbSAndy Fiddaman 	if (sockfd == -1)
190*221e47fbSAndy Fiddaman 		err(EXIT_FAILURE, "failed to create server socket");
191*221e47fbSAndy Fiddaman 
192*221e47fbSAndy Fiddaman 	addr.sin_family = AF_INET;
193*221e47fbSAndy Fiddaman 	addr.sin_addr.s_addr = INADDR_ANY;
194*221e47fbSAndy Fiddaman 	addr.sin_port = htons(TESTPORT);
195*221e47fbSAndy Fiddaman 
196*221e47fbSAndy Fiddaman 	if (bind(sockfd, (struct sockaddr *)&addr, sizeof (addr)) == -1)
197*221e47fbSAndy Fiddaman 		err(EXIT_FAILURE, "server socket bind failed");
198*221e47fbSAndy Fiddaman 
199*221e47fbSAndy Fiddaman 	if (t->flags & RT_RECVTOS) {
200*221e47fbSAndy Fiddaman 		DEBUG((" : setting RECVTOS\n"));
201*221e47fbSAndy Fiddaman 		if (setsockopt(sockfd, IPPROTO_IP, IP_RECVTOS, &c,
202*221e47fbSAndy Fiddaman 		    sizeof (c)) == -1) {
203*221e47fbSAndy Fiddaman 			printf("[FAIL] %s - "
204*221e47fbSAndy Fiddaman 			    "couldn't set TOS on server socket: %s\n",
205*221e47fbSAndy Fiddaman 			    t->name, strerror(errno));
206*221e47fbSAndy Fiddaman 			pass = _B_FALSE;
207*221e47fbSAndy Fiddaman 		}
208*221e47fbSAndy Fiddaman 	}
209*221e47fbSAndy Fiddaman 
210*221e47fbSAndy Fiddaman 	if (t->flags & RT_RECVTTL) {
211*221e47fbSAndy Fiddaman 		DEBUG((" : setting RECVTTL\n"));
212*221e47fbSAndy Fiddaman 		if (setsockopt(sockfd, IPPROTO_IP, IP_RECVTTL, &c,
213*221e47fbSAndy Fiddaman 		    sizeof (c)) == -1) {
214*221e47fbSAndy Fiddaman 			printf("[FAIL] %s - "
215*221e47fbSAndy Fiddaman 			    "couldn't set TTL on server socket: %s\n",
216*221e47fbSAndy Fiddaman 			    t->name, strerror(errno));
217*221e47fbSAndy Fiddaman 			pass = _B_FALSE;
218*221e47fbSAndy Fiddaman 		}
219*221e47fbSAndy Fiddaman 	}
220*221e47fbSAndy Fiddaman 
221*221e47fbSAndy Fiddaman 	if (t->flags & RT_RECVPKTINFO) {
222*221e47fbSAndy Fiddaman 		DEBUG((" : setting RECVPKTINFO\n"));
223*221e47fbSAndy Fiddaman 		if (setsockopt(sockfd, IPPROTO_IP, IP_PKTINFO, &c,
224*221e47fbSAndy Fiddaman 		    sizeof (c)) == -1) {
225*221e47fbSAndy Fiddaman 			printf("[FAIL] %s - "
226*221e47fbSAndy Fiddaman 			    "couldn't set PKTINFO on server socket: %s\n",
227*221e47fbSAndy Fiddaman 			    t->name, strerror(errno));
228*221e47fbSAndy Fiddaman 			pass = _B_FALSE;
229*221e47fbSAndy Fiddaman 		}
230*221e47fbSAndy Fiddaman 	}
231*221e47fbSAndy Fiddaman 
232*221e47fbSAndy Fiddaman 	if (t->flags & RT_STREAM) {
233*221e47fbSAndy Fiddaman 		if (listen(sockfd, 1) == -1)
234*221e47fbSAndy Fiddaman 			err(EXIT_FAILURE, "Could not listen on sever socket");
235*221e47fbSAndy Fiddaman 	}
236*221e47fbSAndy Fiddaman 
237*221e47fbSAndy Fiddaman 	/* Signal the client that the server is ready for the next test */
238*221e47fbSAndy Fiddaman 	if (debug)
239*221e47fbSAndy Fiddaman 		printf(" : signalling client\n");
240*221e47fbSAndy Fiddaman 	(void) pthread_mutex_lock(&mutex);
241*221e47fbSAndy Fiddaman 	server_ready = _B_TRUE;
242*221e47fbSAndy Fiddaman 	(void) pthread_cond_signal(&cv);
243*221e47fbSAndy Fiddaman 	(void) pthread_mutex_unlock(&mutex);
244*221e47fbSAndy Fiddaman 
245*221e47fbSAndy Fiddaman 	if (t->flags & RT_STREAM) {
246*221e47fbSAndy Fiddaman 		struct sockaddr_in caddr;
247*221e47fbSAndy Fiddaman 		socklen_t sl = sizeof (caddr);
248*221e47fbSAndy Fiddaman 
249*221e47fbSAndy Fiddaman 		if ((acceptfd = accept(sockfd, (struct sockaddr *)&caddr,
250*221e47fbSAndy Fiddaman 		    &sl)) == -1) {
251*221e47fbSAndy Fiddaman 			err(EXIT_FAILURE, "socket accept failed");
252*221e47fbSAndy Fiddaman 		}
253*221e47fbSAndy Fiddaman 		readfd = acceptfd;
254*221e47fbSAndy Fiddaman 	} else {
255*221e47fbSAndy Fiddaman 		readfd = sockfd;
256*221e47fbSAndy Fiddaman 	}
257*221e47fbSAndy Fiddaman 
258*221e47fbSAndy Fiddaman 	/* Receive the datagram */
259*221e47fbSAndy Fiddaman 
260*221e47fbSAndy Fiddaman 	struct msghdr msg;
261*221e47fbSAndy Fiddaman 	char buf[0x100];
262*221e47fbSAndy Fiddaman 	char cbuf[CMSG_SPACE(0x400)];
263*221e47fbSAndy Fiddaman 	struct iovec iov[1] = {0};
264*221e47fbSAndy Fiddaman 	ssize_t r;
265*221e47fbSAndy Fiddaman 
266*221e47fbSAndy Fiddaman 	iov[0].iov_base = buf;
267*221e47fbSAndy Fiddaman 	iov[0].iov_len = sizeof (buf);
268*221e47fbSAndy Fiddaman 
269*221e47fbSAndy Fiddaman 	bzero(&msg, sizeof (msg));
270*221e47fbSAndy Fiddaman 	msg.msg_iov = iov;
271*221e47fbSAndy Fiddaman 	msg.msg_iovlen = 1;
272*221e47fbSAndy Fiddaman 	msg.msg_control = cbuf;
273*221e47fbSAndy Fiddaman 	msg.msg_controllen = sizeof (cbuf);
274*221e47fbSAndy Fiddaman 
275*221e47fbSAndy Fiddaman 	DEBUG((" : waiting for message\n"));
276*221e47fbSAndy Fiddaman 
277*221e47fbSAndy Fiddaman 	r = recvmsg(readfd, &msg, 0);
278*221e47fbSAndy Fiddaman 	if (r <= 0) {
279*221e47fbSAndy Fiddaman 		printf("[FAIL] %s - recvmsg returned %d (%s)\n",
280*221e47fbSAndy Fiddaman 		    t->name, r, strerror(errno));
281*221e47fbSAndy Fiddaman 		pass = _B_FALSE;
282*221e47fbSAndy Fiddaman 		goto out;
283*221e47fbSAndy Fiddaman 	}
284*221e47fbSAndy Fiddaman 
285*221e47fbSAndy Fiddaman 	DEBUG((" : recvmsg returned %d (flags=0x%x, controllen=%d)\n",
286*221e47fbSAndy Fiddaman 	    r, msg.msg_flags, msg.msg_controllen));
287*221e47fbSAndy Fiddaman 
288*221e47fbSAndy Fiddaman 	if (r != strlen(t->name)) {
289*221e47fbSAndy Fiddaman 		printf("[FAIL] %s - got '%.*s' (%d bytes), expected '%s'\n",
290*221e47fbSAndy Fiddaman 		    t->name, r, buf, r, t->name);
291*221e47fbSAndy Fiddaman 		pass = _B_FALSE;
292*221e47fbSAndy Fiddaman 	}
293*221e47fbSAndy Fiddaman 
294*221e47fbSAndy Fiddaman 	DEBUG((" : Received '%.*s'\n", r, buf));
295*221e47fbSAndy Fiddaman 
296*221e47fbSAndy Fiddaman 	if (msg.msg_flags != 0) {
297*221e47fbSAndy Fiddaman 		printf("[FAIL] %s - received flags 0x%x\n",
298*221e47fbSAndy Fiddaman 		    t->name, msg.msg_flags);
299*221e47fbSAndy Fiddaman 		pass = _B_FALSE;
300*221e47fbSAndy Fiddaman 	}
301*221e47fbSAndy Fiddaman 
302*221e47fbSAndy Fiddaman 	uint8_t flags = 0;
303*221e47fbSAndy Fiddaman 
304*221e47fbSAndy Fiddaman 	for (struct cmsghdr *cm = CMSG_FIRSTHDR(&msg); cm != NULL;
305*221e47fbSAndy Fiddaman 	    cm = CMSG_NXTHDR(&msg, cm)) {
306*221e47fbSAndy Fiddaman 		uint8_t d;
307*221e47fbSAndy Fiddaman 
308*221e47fbSAndy Fiddaman 		DEBUG((" : >> Got cmsg %x/%x - length %u\n",
309*221e47fbSAndy Fiddaman 		    cm->cmsg_level, cm->cmsg_type, cm->cmsg_len));
310*221e47fbSAndy Fiddaman 
311*221e47fbSAndy Fiddaman 		if (cm->cmsg_level != IPPROTO_IP)
312*221e47fbSAndy Fiddaman 			continue;
313*221e47fbSAndy Fiddaman 
314*221e47fbSAndy Fiddaman 		switch (cm->cmsg_type) {
315*221e47fbSAndy Fiddaman 		case IP_PKTINFO:
316*221e47fbSAndy Fiddaman 			flags |= RT_RECVPKTINFO;
317*221e47fbSAndy Fiddaman 			if (debug) {
318*221e47fbSAndy Fiddaman 				struct in_pktinfo *pi =
319*221e47fbSAndy Fiddaman 				    (struct in_pktinfo *)CMSG_DATA(cm);
320*221e47fbSAndy Fiddaman 				printf(" : ifIndex: %u\n", pi->ipi_ifindex);
321*221e47fbSAndy Fiddaman 			}
322*221e47fbSAndy Fiddaman 			break;
323*221e47fbSAndy Fiddaman 		case IP_RECVTTL:
324*221e47fbSAndy Fiddaman 			if (cm->cmsg_len != CMSG_LEN(sizeof (uint8_t))) {
325*221e47fbSAndy Fiddaman 				printf(
326*221e47fbSAndy Fiddaman 				    "[FAIL] %s - cmsg_len was %u expected %u\n",
327*221e47fbSAndy Fiddaman 				    t->name, cm->cmsg_len,
328*221e47fbSAndy Fiddaman 				    CMSG_LEN(sizeof (uint8_t)));
329*221e47fbSAndy Fiddaman 				pass = _B_FALSE;
330*221e47fbSAndy Fiddaman 				break;
331*221e47fbSAndy Fiddaman 			}
332*221e47fbSAndy Fiddaman 			flags |= RT_RECVTTL;
333*221e47fbSAndy Fiddaman 			memcpy(&d, CMSG_DATA(cm), sizeof (d));
334*221e47fbSAndy Fiddaman 			DEBUG((" : RECVTTL = %u\n", d));
335*221e47fbSAndy Fiddaman 			if (t->flags & RT_SETTTL && d != t->ttl) {
336*221e47fbSAndy Fiddaman 				printf("[FAIL] %s - TTL was %u, expected %u\n",
337*221e47fbSAndy Fiddaman 				    t->name, d, t->ttl);
338*221e47fbSAndy Fiddaman 				pass = _B_FALSE;
339*221e47fbSAndy Fiddaman 			}
340*221e47fbSAndy Fiddaman 			break;
341*221e47fbSAndy Fiddaman 		case IP_RECVTOS:
342*221e47fbSAndy Fiddaman 			if (cm->cmsg_len != CMSG_LEN(sizeof (uint8_t))) {
343*221e47fbSAndy Fiddaman 				printf(
344*221e47fbSAndy Fiddaman 				    "[FAIL] %s - cmsg_len was %u expected %u\n",
345*221e47fbSAndy Fiddaman 				    t->name, cm->cmsg_len,
346*221e47fbSAndy Fiddaman 				    CMSG_LEN(sizeof (uint8_t)));
347*221e47fbSAndy Fiddaman 				pass = _B_FALSE;
348*221e47fbSAndy Fiddaman 				break;
349*221e47fbSAndy Fiddaman 			}
350*221e47fbSAndy Fiddaman 			flags |= RT_RECVTOS;
351*221e47fbSAndy Fiddaman 			memcpy(&d, CMSG_DATA(cm), sizeof (d));
352*221e47fbSAndy Fiddaman 			DEBUG((" : RECVTOS = %u\n", d));
353*221e47fbSAndy Fiddaman 			if (t->flags & RT_SETTOS && d != t->tos) {
354*221e47fbSAndy Fiddaman 				printf("[FAIL] %s - TOS was %u, expected %u\n",
355*221e47fbSAndy Fiddaman 				    t->name, d, t->tos);
356*221e47fbSAndy Fiddaman 				pass = _B_FALSE;
357*221e47fbSAndy Fiddaman 			}
358*221e47fbSAndy Fiddaman 			break;
359*221e47fbSAndy Fiddaman 		}
360*221e47fbSAndy Fiddaman 	}
361*221e47fbSAndy Fiddaman 
362*221e47fbSAndy Fiddaman 	if ((t->flags & RT_RECVMASK) != flags) {
363*221e47fbSAndy Fiddaman 		printf("[FAIL] %s - Did not receive everything expected, "
364*221e47fbSAndy Fiddaman 		    "flags %#x vs. %#x\n", t->name,
365*221e47fbSAndy Fiddaman 		    flags, t->flags & RT_RECVMASK);
366*221e47fbSAndy Fiddaman 		pass = _B_FALSE;
367*221e47fbSAndy Fiddaman 	}
368*221e47fbSAndy Fiddaman 
369*221e47fbSAndy Fiddaman 	/* Wait for the client to finish */
370*221e47fbSAndy Fiddaman 	(void) pthread_mutex_lock(&cmutex);
371*221e47fbSAndy Fiddaman 	while (!client_done)
372*221e47fbSAndy Fiddaman 		(void) pthread_cond_wait(&ccv, &cmutex);
373*221e47fbSAndy Fiddaman 	client_done = _B_FALSE;
374*221e47fbSAndy Fiddaman 	(void) pthread_mutex_unlock(&cmutex);
375*221e47fbSAndy Fiddaman 
376*221e47fbSAndy Fiddaman out:
377*221e47fbSAndy Fiddaman 	if (acceptfd != -1)
378*221e47fbSAndy Fiddaman 		(void) close(acceptfd);
379*221e47fbSAndy Fiddaman 	(void) close(sockfd);
380*221e47fbSAndy Fiddaman 
381*221e47fbSAndy Fiddaman 	if (pass)
382*221e47fbSAndy Fiddaman 		printf("[PASS] %s\n", t->name);
383*221e47fbSAndy Fiddaman 
384*221e47fbSAndy Fiddaman 	return (pass);
385*221e47fbSAndy Fiddaman }
386*221e47fbSAndy Fiddaman 
387*221e47fbSAndy Fiddaman static int
server(const char * test)388*221e47fbSAndy Fiddaman server(const char *test)
389*221e47fbSAndy Fiddaman {
390*221e47fbSAndy Fiddaman 	int ret = EXIT_SUCCESS;
391*221e47fbSAndy Fiddaman 	recvmsg_test_t *t;
392*221e47fbSAndy Fiddaman 
393*221e47fbSAndy Fiddaman 	for (t = tests; t->name != NULL; t++) {
394*221e47fbSAndy Fiddaman 		if (test != NULL) {
395*221e47fbSAndy Fiddaman 			if (strcmp(test, t->name) != 0)
396*221e47fbSAndy Fiddaman 				continue;
397*221e47fbSAndy Fiddaman 			client_done = _B_TRUE;
398*221e47fbSAndy Fiddaman 			return (servertest(t));
399*221e47fbSAndy Fiddaman 		}
400*221e47fbSAndy Fiddaman 		if (t->flags & RT_SKIP) {
401*221e47fbSAndy Fiddaman 			printf("[SKIP] %s - (requires two separate zones)\n",
402*221e47fbSAndy Fiddaman 			    t->name);
403*221e47fbSAndy Fiddaman 			continue;
404*221e47fbSAndy Fiddaman 		}
405*221e47fbSAndy Fiddaman 		if (!servertest(t))
406*221e47fbSAndy Fiddaman 			ret = EXIT_FAILURE;
407*221e47fbSAndy Fiddaman 	}
408*221e47fbSAndy Fiddaman 
409*221e47fbSAndy Fiddaman 	return (ret);
410*221e47fbSAndy Fiddaman }
411*221e47fbSAndy Fiddaman 
412*221e47fbSAndy Fiddaman static void
clienttest(recvmsg_test_t * t)413*221e47fbSAndy Fiddaman clienttest(recvmsg_test_t *t)
414*221e47fbSAndy Fiddaman {
415*221e47fbSAndy Fiddaman 	struct sockaddr_in addr;
416*221e47fbSAndy Fiddaman 	int s, ret;
417*221e47fbSAndy Fiddaman 
418*221e47fbSAndy Fiddaman 	DEBUG(("client %s: starting\n", t->name));
419*221e47fbSAndy Fiddaman 
420*221e47fbSAndy Fiddaman 	s = socket(AF_INET, t->flags & RT_STREAM ? SOCK_STREAM : SOCK_DGRAM, 0);
421*221e47fbSAndy Fiddaman 	if (s == -1)
422*221e47fbSAndy Fiddaman 		err(EXIT_FAILURE, "failed to create client socket");
423*221e47fbSAndy Fiddaman 
424*221e47fbSAndy Fiddaman 	addr.sin_family = AF_INET;
425*221e47fbSAndy Fiddaman 	addr.sin_addr.s_addr = testip;
426*221e47fbSAndy Fiddaman 	addr.sin_port = htons(TESTPORT);
427*221e47fbSAndy Fiddaman 
428*221e47fbSAndy Fiddaman 	if (t->flags & RT_STREAM) {
429*221e47fbSAndy Fiddaman 		if (connect(s, (struct sockaddr *)&addr, sizeof (addr)) == -1)
430*221e47fbSAndy Fiddaman 			err(EXIT_FAILURE, "failed to connect to server");
431*221e47fbSAndy Fiddaman 	}
432*221e47fbSAndy Fiddaman 
433*221e47fbSAndy Fiddaman 	if (t->flags & RT_SETTOS) {
434*221e47fbSAndy Fiddaman 		int c = t->tos;
435*221e47fbSAndy Fiddaman 
436*221e47fbSAndy Fiddaman 		DEBUG(("client %s: setting TOS = 0x%x\n", t->name, c));
437*221e47fbSAndy Fiddaman 		if (setsockopt(s, IPPROTO_IP, IP_TOS, &c, sizeof (c)) == -1)
438*221e47fbSAndy Fiddaman 			err(EXIT_FAILURE, "could not set TOS on client socket");
439*221e47fbSAndy Fiddaman 	}
440*221e47fbSAndy Fiddaman 
441*221e47fbSAndy Fiddaman 	if (t->flags & RT_SETTTL) {
442*221e47fbSAndy Fiddaman 		int c = t->ttl;
443*221e47fbSAndy Fiddaman 
444*221e47fbSAndy Fiddaman 		DEBUG(("client %s: setting TTL = 0x%x\n", t->name, c));
445*221e47fbSAndy Fiddaman 		if (setsockopt(s, IPPROTO_IP, IP_TTL, &c, sizeof (c)) == -1)
446*221e47fbSAndy Fiddaman 			err(EXIT_FAILURE, "could not set TTL on client socket");
447*221e47fbSAndy Fiddaman 	}
448*221e47fbSAndy Fiddaman 
449*221e47fbSAndy Fiddaman 	DEBUG(("client %s: sending\n", t->name));
450*221e47fbSAndy Fiddaman 
451*221e47fbSAndy Fiddaman 	if (t->flags & RT_STREAM) {
452*221e47fbSAndy Fiddaman 		ret = send(s, t->name, strlen(t->name), 0);
453*221e47fbSAndy Fiddaman 		shutdown(s, SHUT_RDWR);
454*221e47fbSAndy Fiddaman 	} else {
455*221e47fbSAndy Fiddaman 		ret = sendto(s, t->name, strlen(t->name), 0,
456*221e47fbSAndy Fiddaman 		    (struct sockaddr *)&addr, sizeof (addr));
457*221e47fbSAndy Fiddaman 	}
458*221e47fbSAndy Fiddaman 
459*221e47fbSAndy Fiddaman 	if (ret == -1)
460*221e47fbSAndy Fiddaman 		err(EXIT_FAILURE, "sendto failed to send data to server");
461*221e47fbSAndy Fiddaman 
462*221e47fbSAndy Fiddaman 	DEBUG(("client %s: done\n", t->name));
463*221e47fbSAndy Fiddaman 
464*221e47fbSAndy Fiddaman 	close(s);
465*221e47fbSAndy Fiddaman }
466*221e47fbSAndy Fiddaman 
467*221e47fbSAndy Fiddaman static void *
client(void * arg)468*221e47fbSAndy Fiddaman client(void *arg)
469*221e47fbSAndy Fiddaman {
470*221e47fbSAndy Fiddaman 	char *test = (char *)arg;
471*221e47fbSAndy Fiddaman 	recvmsg_test_t *t;
472*221e47fbSAndy Fiddaman 
473*221e47fbSAndy Fiddaman 	for (t = tests; t->name != NULL; t++) {
474*221e47fbSAndy Fiddaman 		if (test != NULL) {
475*221e47fbSAndy Fiddaman 			if (strcmp(test, t->name) != 0)
476*221e47fbSAndy Fiddaman 				continue;
477*221e47fbSAndy Fiddaman 			clienttest(t);
478*221e47fbSAndy Fiddaman 			return (NULL);
479*221e47fbSAndy Fiddaman 		}
480*221e47fbSAndy Fiddaman 		if (t->flags & RT_SKIP)
481*221e47fbSAndy Fiddaman 			continue;
482*221e47fbSAndy Fiddaman 		/* Wait for the server to be ready to receive */
483*221e47fbSAndy Fiddaman 		(void) pthread_mutex_lock(&mutex);
484*221e47fbSAndy Fiddaman 		while (!server_ready)
485*221e47fbSAndy Fiddaman 			(void) pthread_cond_wait(&cv, &mutex);
486*221e47fbSAndy Fiddaman 		server_ready = _B_FALSE;
487*221e47fbSAndy Fiddaman 		(void) pthread_mutex_unlock(&mutex);
488*221e47fbSAndy Fiddaman 		clienttest(t);
489*221e47fbSAndy Fiddaman 		/* Tell the server we are done */
490*221e47fbSAndy Fiddaman 		(void) pthread_mutex_lock(&cmutex);
491*221e47fbSAndy Fiddaman 		client_done = _B_TRUE;
492*221e47fbSAndy Fiddaman 		(void) pthread_cond_signal(&ccv);
493*221e47fbSAndy Fiddaman 		(void) pthread_mutex_unlock(&cmutex);
494*221e47fbSAndy Fiddaman 	}
495*221e47fbSAndy Fiddaman 
496*221e47fbSAndy Fiddaman 	return (NULL);
497*221e47fbSAndy Fiddaman }
498*221e47fbSAndy Fiddaman 
499*221e47fbSAndy Fiddaman int
main(int argc,const char ** argv)500*221e47fbSAndy Fiddaman main(int argc, const char **argv)
501*221e47fbSAndy Fiddaman {
502*221e47fbSAndy Fiddaman 	int ret = EXIT_SUCCESS;
503*221e47fbSAndy Fiddaman 	pthread_t cthread;
504*221e47fbSAndy Fiddaman 
505*221e47fbSAndy Fiddaman 	if (argc > 1 && strcmp(argv[1], "-d") == 0) {
506*221e47fbSAndy Fiddaman 		debug = _B_TRUE;
507*221e47fbSAndy Fiddaman 		argc--, argv++;
508*221e47fbSAndy Fiddaman 	}
509*221e47fbSAndy Fiddaman 
510*221e47fbSAndy Fiddaman 	/* -c <server IP> <test name> */
511*221e47fbSAndy Fiddaman 	if (argc == 4 && strcmp(argv[1], "-c") == 0) {
512*221e47fbSAndy Fiddaman 		testip = inet_addr(argv[2]);
513*221e47fbSAndy Fiddaman 		printf("TEST IP: %s\n", argv[2]);
514*221e47fbSAndy Fiddaman 		if (testip == INADDR_NONE) {
515*221e47fbSAndy Fiddaman 			err(EXIT_FAILURE,
516*221e47fbSAndy Fiddaman 			    "Could not parse destination IP address");
517*221e47fbSAndy Fiddaman 		}
518*221e47fbSAndy Fiddaman 		client((void *)argv[3]);
519*221e47fbSAndy Fiddaman 		return (ret);
520*221e47fbSAndy Fiddaman 	}
521*221e47fbSAndy Fiddaman 
522*221e47fbSAndy Fiddaman 	/* -s <test name> */
523*221e47fbSAndy Fiddaman 	if (argc == 3 && strcmp(argv[1], "-s") == 0)
524*221e47fbSAndy Fiddaman 		return (server(argv[2]));
525*221e47fbSAndy Fiddaman 
526*221e47fbSAndy Fiddaman 	testip = inet_addr("127.0.0.1");
527*221e47fbSAndy Fiddaman 	if (testip == INADDR_NONE)
528*221e47fbSAndy Fiddaman 		err(EXIT_FAILURE, "Could not parse destination IP address");
529*221e47fbSAndy Fiddaman 
530*221e47fbSAndy Fiddaman 	if (pthread_create(&cthread, NULL, client, NULL) == -1)
531*221e47fbSAndy Fiddaman 		err(EXIT_FAILURE, "Could not create client thread");
532*221e47fbSAndy Fiddaman 
533*221e47fbSAndy Fiddaman 	ret = server(NULL);
534*221e47fbSAndy Fiddaman 
535*221e47fbSAndy Fiddaman 	if (pthread_join(cthread, NULL) != 0)
536*221e47fbSAndy Fiddaman 		err(EXIT_FAILURE, "join client thread failed");
537*221e47fbSAndy Fiddaman 
538*221e47fbSAndy Fiddaman 	return (ret);
539*221e47fbSAndy Fiddaman }
540