xref: /illumos-gate/usr/src/test/os-tests/tests/sockfs/timeouts.c (revision 1c1f30a61162b465dc08830707c1c2509ecfc872)
1*1c1f30a6SAndy Fiddaman /*
2*1c1f30a6SAndy Fiddaman  * This file and its contents are supplied under the terms of the
3*1c1f30a6SAndy Fiddaman  * Common Development and Distribution License ("CDDL"), version 1.0.
4*1c1f30a6SAndy Fiddaman  * You may only use this file in accordance with the terms of version
5*1c1f30a6SAndy Fiddaman  * 1.0 of the CDDL.
6*1c1f30a6SAndy Fiddaman  *
7*1c1f30a6SAndy Fiddaman  * A full copy of the text of the CDDL should have accompanied this
8*1c1f30a6SAndy Fiddaman  * source.  A copy of the CDDL is also available via the Internet at
9*1c1f30a6SAndy Fiddaman  * http://www.illumos.org/license/CDDL.
10*1c1f30a6SAndy Fiddaman  */
11*1c1f30a6SAndy Fiddaman 
12*1c1f30a6SAndy Fiddaman /*
13*1c1f30a6SAndy Fiddaman  * Copyright 2024 Oxide Computer Company
14*1c1f30a6SAndy Fiddaman  */
15*1c1f30a6SAndy Fiddaman 
16*1c1f30a6SAndy Fiddaman /*
17*1c1f30a6SAndy Fiddaman  * Test that setting timeout options on a UNIX stream socket after connection
18*1c1f30a6SAndy Fiddaman  * works, in that the timeout values are accepted and subsequently returned.
19*1c1f30a6SAndy Fiddaman  */
20*1c1f30a6SAndy Fiddaman 
21*1c1f30a6SAndy Fiddaman #include <err.h>
22*1c1f30a6SAndy Fiddaman #include <errno.h>
23*1c1f30a6SAndy Fiddaman #include <fcntl.h>
24*1c1f30a6SAndy Fiddaman #include <stdio.h>
25*1c1f30a6SAndy Fiddaman #include <stdlib.h>
26*1c1f30a6SAndy Fiddaman #include <string.h>
27*1c1f30a6SAndy Fiddaman #include <strings.h>
28*1c1f30a6SAndy Fiddaman #include <unistd.h>
29*1c1f30a6SAndy Fiddaman 
30*1c1f30a6SAndy Fiddaman #include <sys/param.h>
31*1c1f30a6SAndy Fiddaman #include <sys/socket.h>
32*1c1f30a6SAndy Fiddaman #include <sys/stdbool.h>
33*1c1f30a6SAndy Fiddaman #include <sys/sysmacros.h>
34*1c1f30a6SAndy Fiddaman #include <sys/time.h>
35*1c1f30a6SAndy Fiddaman #include <sys/types.h>
36*1c1f30a6SAndy Fiddaman #include <sys/un.h>
37*1c1f30a6SAndy Fiddaman 
38*1c1f30a6SAndy Fiddaman static bool pass = true;
39*1c1f30a6SAndy Fiddaman 
40*1c1f30a6SAndy Fiddaman typedef struct to_test {
41*1c1f30a6SAndy Fiddaman 	char *name;		/* Name of the test */
42*1c1f30a6SAndy Fiddaman 	int option;		/* Socket option */
43*1c1f30a6SAndy Fiddaman 	time_t sec;		/* Number of seconds */
44*1c1f30a6SAndy Fiddaman 	suseconds_t usec;	/* and microseconds */
45*1c1f30a6SAndy Fiddaman } to_test_t;
46*1c1f30a6SAndy Fiddaman 
47*1c1f30a6SAndy Fiddaman static to_test_t tests[] = {
48*1c1f30a6SAndy Fiddaman 	{
49*1c1f30a6SAndy Fiddaman 		.name = "Set 5s receive",
50*1c1f30a6SAndy Fiddaman 		.option = SO_RCVTIMEO,
51*1c1f30a6SAndy Fiddaman 		.sec = 5,
52*1c1f30a6SAndy Fiddaman 		.usec = 0
53*1c1f30a6SAndy Fiddaman 	}, {
54*1c1f30a6SAndy Fiddaman 		.name = "Set 5s send",
55*1c1f30a6SAndy Fiddaman 		.option = SO_SNDTIMEO,
56*1c1f30a6SAndy Fiddaman 		.sec = 5,
57*1c1f30a6SAndy Fiddaman 		.usec = 0
58*1c1f30a6SAndy Fiddaman 	}, {
59*1c1f30a6SAndy Fiddaman 		.name = "Set 15410s receive",
60*1c1f30a6SAndy Fiddaman 		.option = SO_RCVTIMEO,
61*1c1f30a6SAndy Fiddaman 		.sec = 15410,
62*1c1f30a6SAndy Fiddaman 		.usec = 0
63*1c1f30a6SAndy Fiddaman 	}, {
64*1c1f30a6SAndy Fiddaman 		.name = "Set 15410s send",
65*1c1f30a6SAndy Fiddaman 		.option = SO_SNDTIMEO,
66*1c1f30a6SAndy Fiddaman 		.sec = 15410,
67*1c1f30a6SAndy Fiddaman 		.usec = 0
68*1c1f30a6SAndy Fiddaman 	}, {
69*1c1f30a6SAndy Fiddaman 		.name = "Set 0s receive",
70*1c1f30a6SAndy Fiddaman 		.option = SO_RCVTIMEO,
71*1c1f30a6SAndy Fiddaman 		.sec = 0,
72*1c1f30a6SAndy Fiddaman 		.usec = 0
73*1c1f30a6SAndy Fiddaman 	}, {
74*1c1f30a6SAndy Fiddaman 		.name = "Set 0s send",
75*1c1f30a6SAndy Fiddaman 		.option = SO_SNDTIMEO,
76*1c1f30a6SAndy Fiddaman 		.sec = 0,
77*1c1f30a6SAndy Fiddaman 		.usec = 0
78*1c1f30a6SAndy Fiddaman 	}, {
79*1c1f30a6SAndy Fiddaman 		.name = "Set 5.5s receive",
80*1c1f30a6SAndy Fiddaman 		.option = SO_RCVTIMEO,
81*1c1f30a6SAndy Fiddaman 		.sec = 5,
82*1c1f30a6SAndy Fiddaman 		.usec = MICROSEC / 2,
83*1c1f30a6SAndy Fiddaman 	}, {
84*1c1f30a6SAndy Fiddaman 		.name = "Set 5.5s send",
85*1c1f30a6SAndy Fiddaman 		.option = SO_SNDTIMEO,
86*1c1f30a6SAndy Fiddaman 		.sec = 5,
87*1c1f30a6SAndy Fiddaman 		.usec = MICROSEC / 2,
88*1c1f30a6SAndy Fiddaman 	}
89*1c1f30a6SAndy Fiddaman };
90*1c1f30a6SAndy Fiddaman 
91*1c1f30a6SAndy Fiddaman static int
server(const char * sockpath)92*1c1f30a6SAndy Fiddaman server(const char *sockpath)
93*1c1f30a6SAndy Fiddaman {
94*1c1f30a6SAndy Fiddaman 	struct sockaddr_un addr;
95*1c1f30a6SAndy Fiddaman 	int sock;
96*1c1f30a6SAndy Fiddaman 
97*1c1f30a6SAndy Fiddaman 	sock = socket(PF_LOCAL, SOCK_STREAM, 0);
98*1c1f30a6SAndy Fiddaman 	if (sock == -1)
99*1c1f30a6SAndy Fiddaman 		err(EXIT_FAILURE, "failed to create socket");
100*1c1f30a6SAndy Fiddaman 	addr.sun_family = AF_UNIX;
101*1c1f30a6SAndy Fiddaman 	strlcpy(addr.sun_path, sockpath, sizeof (addr.sun_path));
102*1c1f30a6SAndy Fiddaman 	if (bind(sock, (struct sockaddr *)&addr, sizeof (addr)) == -1)
103*1c1f30a6SAndy Fiddaman 		err(EXIT_FAILURE, "bind failed");
104*1c1f30a6SAndy Fiddaman 	if (listen(sock, 0) == -1)
105*1c1f30a6SAndy Fiddaman 		err(EXIT_FAILURE, "listen failed");
106*1c1f30a6SAndy Fiddaman 
107*1c1f30a6SAndy Fiddaman 	return (sock);
108*1c1f30a6SAndy Fiddaman }
109*1c1f30a6SAndy Fiddaman 
110*1c1f30a6SAndy Fiddaman static int
client(const char * sockpath)111*1c1f30a6SAndy Fiddaman client(const char *sockpath)
112*1c1f30a6SAndy Fiddaman {
113*1c1f30a6SAndy Fiddaman 	struct sockaddr_un addr;
114*1c1f30a6SAndy Fiddaman 	int sock;
115*1c1f30a6SAndy Fiddaman 
116*1c1f30a6SAndy Fiddaman 	sock = socket(PF_LOCAL, SOCK_STREAM, 0);
117*1c1f30a6SAndy Fiddaman 	if (sock == -1)
118*1c1f30a6SAndy Fiddaman 		err(EXIT_FAILURE, "failed to create socket");
119*1c1f30a6SAndy Fiddaman 	addr.sun_family = AF_UNIX;
120*1c1f30a6SAndy Fiddaman 	strlcpy(addr.sun_path, sockpath, sizeof (addr.sun_path));
121*1c1f30a6SAndy Fiddaman 	if (connect(sock, (struct sockaddr *)&addr, sizeof (addr)) == -1)
122*1c1f30a6SAndy Fiddaman 		err(EXIT_FAILURE, "could not connect to server socket");
123*1c1f30a6SAndy Fiddaman 
124*1c1f30a6SAndy Fiddaman 	return (sock);
125*1c1f30a6SAndy Fiddaman }
126*1c1f30a6SAndy Fiddaman 
127*1c1f30a6SAndy Fiddaman static void __PRINTFLIKE(2)
fail(const to_test_t * t,const char * fmt,...)128*1c1f30a6SAndy Fiddaman fail(const to_test_t *t, const char *fmt, ...)
129*1c1f30a6SAndy Fiddaman {
130*1c1f30a6SAndy Fiddaman 	va_list ap;
131*1c1f30a6SAndy Fiddaman 
132*1c1f30a6SAndy Fiddaman 	fprintf(stderr, "[FAIL] %s: ", t->name);
133*1c1f30a6SAndy Fiddaman 	va_start(ap, fmt);
134*1c1f30a6SAndy Fiddaman 	vfprintf(stderr, fmt, ap);
135*1c1f30a6SAndy Fiddaman 	va_end(ap);
136*1c1f30a6SAndy Fiddaman 	fprintf(stderr, "\n");
137*1c1f30a6SAndy Fiddaman 	pass = false;
138*1c1f30a6SAndy Fiddaman }
139*1c1f30a6SAndy Fiddaman 
140*1c1f30a6SAndy Fiddaman int
main(int argc,const char ** argv)141*1c1f30a6SAndy Fiddaman main(int argc, const char **argv)
142*1c1f30a6SAndy Fiddaman {
143*1c1f30a6SAndy Fiddaman 	char sockpath[] = "/tmp/to.testsock.XXXXXX";
144*1c1f30a6SAndy Fiddaman 	int sfd, cfd;
145*1c1f30a6SAndy Fiddaman 
146*1c1f30a6SAndy Fiddaman 	if (mktemp(sockpath) == NULL)
147*1c1f30a6SAndy Fiddaman 		err(EXIT_FAILURE, "Failed to make temporary socket path");
148*1c1f30a6SAndy Fiddaman 
149*1c1f30a6SAndy Fiddaman 	sfd = server(sockpath);
150*1c1f30a6SAndy Fiddaman 	cfd = client(sockpath);
151*1c1f30a6SAndy Fiddaman 
152*1c1f30a6SAndy Fiddaman 	for (uint_t i = 0; i < ARRAY_SIZE(tests); i++) {
153*1c1f30a6SAndy Fiddaman 		const to_test_t *t = &tests[i];
154*1c1f30a6SAndy Fiddaman 		struct timeval tv = { 0 };
155*1c1f30a6SAndy Fiddaman 		socklen_t optlen;
156*1c1f30a6SAndy Fiddaman 
157*1c1f30a6SAndy Fiddaman 		tv.tv_sec = t->sec;
158*1c1f30a6SAndy Fiddaman 		tv.tv_usec = t->usec;
159*1c1f30a6SAndy Fiddaman 		optlen = sizeof (tv);
160*1c1f30a6SAndy Fiddaman 		if (setsockopt(cfd, SOL_SOCKET, t->option, &tv, optlen) != 0) {
161*1c1f30a6SAndy Fiddaman 			fail(t, "setsockopt error: %s", strerror(errno));
162*1c1f30a6SAndy Fiddaman 			pass = false;
163*1c1f30a6SAndy Fiddaman 			continue;
164*1c1f30a6SAndy Fiddaman 		}
165*1c1f30a6SAndy Fiddaman 
166*1c1f30a6SAndy Fiddaman 		bzero(&tv, sizeof (tv));
167*1c1f30a6SAndy Fiddaman 		if (getsockopt(cfd, SOL_SOCKET, t->option, &tv, &optlen) != 0) {
168*1c1f30a6SAndy Fiddaman 			fail(t, "getsockopt error: %s", strerror(errno));
169*1c1f30a6SAndy Fiddaman 			pass = false;
170*1c1f30a6SAndy Fiddaman 			continue;
171*1c1f30a6SAndy Fiddaman 		}
172*1c1f30a6SAndy Fiddaman 
173*1c1f30a6SAndy Fiddaman 		if (optlen != sizeof (tv)) {
174*1c1f30a6SAndy Fiddaman 			fail(t,
175*1c1f30a6SAndy Fiddaman 			    "getsockopt returned incorrect length: %ld"
176*1c1f30a6SAndy Fiddaman 			    " vs. %zd", (long)optlen, sizeof (tv));
177*1c1f30a6SAndy Fiddaman 			continue;
178*1c1f30a6SAndy Fiddaman 		}
179*1c1f30a6SAndy Fiddaman 
180*1c1f30a6SAndy Fiddaman 		if (tv.tv_sec != t->sec) {
181*1c1f30a6SAndy Fiddaman 			fail(t, "returned tv_sec value mismatch: %ld "
182*1c1f30a6SAndy Fiddaman 			    "vs. expected %ld", tv.tv_sec, t->sec);
183*1c1f30a6SAndy Fiddaman 			continue;
184*1c1f30a6SAndy Fiddaman 		}
185*1c1f30a6SAndy Fiddaman 		if (tv.tv_usec != t->usec) {
186*1c1f30a6SAndy Fiddaman 			fail(t, "returned tv_usec value mismatch: %ld "
187*1c1f30a6SAndy Fiddaman 			    "vs. expected %ld", tv.tv_usec, t->usec);
188*1c1f30a6SAndy Fiddaman 			continue;
189*1c1f30a6SAndy Fiddaman 		}
190*1c1f30a6SAndy Fiddaman 
191*1c1f30a6SAndy Fiddaman 		printf("[PASS] %s\n", t->name);
192*1c1f30a6SAndy Fiddaman 	}
193*1c1f30a6SAndy Fiddaman 
194*1c1f30a6SAndy Fiddaman 	close(cfd);
195*1c1f30a6SAndy Fiddaman 	close(sfd);
196*1c1f30a6SAndy Fiddaman 	unlink(sockpath);
197*1c1f30a6SAndy Fiddaman 
198*1c1f30a6SAndy Fiddaman 	return (pass ? 0 : EXIT_FAILURE);
199*1c1f30a6SAndy Fiddaman }
200