1 /*
2  * Copyright 2016 Jeremy Allison
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included
12  * in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20  * DEALINGS IN THE SOFTWARE.
21  */
22 
23 /*
24  * Copyright 2019 Joyent, Inc.
25  */
26 
27 #include <sys/param.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <sys/socket.h>
31 #include <sys/un.h>
32 #include <stdio.h>
33 #include <unistd.h>
34 #include <string.h>
35 #include <errno.h>
36 #include <stdint.h>
37 #include <stdlib.h>
38 #include <pthread.h>
39 
40 extern const char *__progname;
41 
42 static void *
server(void * varg)43 server(void *varg)
44 {
45 	int ret;
46 	int sock = (int)varg;
47 	unsigned int i;
48 
49 	for (i = 0; i < 5; i++) {
50 		struct iovec iov;
51 		struct msghdr msg;
52 		uint8_t buf[4096];
53 
54 		iov = (struct iovec) {
55 			.iov_base = buf,
56 			.iov_len = sizeof (buf)
57 		};
58 
59 		msg = (struct msghdr) {
60 			.msg_iov = &iov,
61 			.msg_iovlen = 1,
62 		};
63 
64 		ret = recvmsg(sock, &msg, 0);
65 		if (ret == -1) {
66 			fprintf(stderr, "server - recvmsg fail %s\n",
67 			    strerror(errno));
68 			exit(1);
69 		}
70 
71 		printf("SERVER:%s\n", (char *)msg.msg_iov->iov_base);
72 		fflush(stdout);
73 	}
74 
75 	exit(0);
76 }
77 
78 static void *
listener(void * varg)79 listener(void *varg)
80 {
81 	struct sockaddr_un *addr = varg;
82 	int ret;
83 	int lsock;
84 	int asock;
85 
86 	/* Child. */
87 	lsock = socket(AF_UNIX, SOCK_STREAM, 0);
88 	if (lsock == -1) {
89 		fprintf(stderr, "listener - socket fail %s\n", strerror(errno));
90 		exit(1);
91 	}
92 
93 	ret = bind(lsock, (struct sockaddr *)addr, sizeof (*addr));
94 	if (ret == -1) {
95 		fprintf(stderr, "listener - bind fail %s\n", strerror(errno));
96 		exit(1);
97 	}
98 
99 	ret = listen(lsock, 5);
100 	if (ret == -1) {
101 		fprintf(stderr, "listener - listen fail %s\n", strerror(errno));
102 		exit(1);
103 	}
104 
105 	for (;;) {
106 		asock = accept(lsock, NULL, 0);
107 		if (asock == -1) {
108 			fprintf(stderr, "listener - accept fail %s\n",
109 			    strerror(errno));
110 			exit(1);
111 		}
112 
113 		/* start worker */
114 		ret = pthread_create(NULL, NULL, server, (void *)asock);
115 		if (ret == -1) {
116 			fprintf(stderr, "%s - thread create fail %s\n",
117 			    __progname, strerror(errno));
118 			exit(1);
119 		}
120 	}
121 }
122 
123 /*
124  * This should be a place only root is allowed to write.
125  * The test will create and destroy this directory.
126  */
127 char testdir[100] = "/var/run/os-tests-sockfs";
128 struct sockaddr_un addr;
129 int test_uid = UID_NOBODY;
130 
131 int
main(int argc,char ** argv)132 main(int argc, char **argv)
133 {
134 	int ret;
135 	int sock;
136 	unsigned int i;
137 
138 	if (argc > 1) {
139 		ret = strlcpy(testdir, argv[1], sizeof (testdir));
140 		if (ret >= sizeof (testdir)) {
141 			fprintf(stderr, "%s: too long\n", argv[1]);
142 			exit(1);
143 		}
144 	}
145 
146 	addr.sun_family = AF_UNIX;
147 	(void) sprintf(addr.sun_path, "%s/s", testdir);
148 
149 	if (mkdir(testdir, 0700) != 0) {
150 		switch (errno) {
151 		case EEXIST:
152 		case EISDIR:
153 			break;
154 		default:
155 			perror(testdir);
156 			exit(1);
157 		}
158 	}
159 	(void) unlink(addr.sun_path);
160 
161 	/* Set up the listener. */
162 	ret = pthread_create(NULL, NULL, listener, &addr);
163 	if (ret == -1) {
164 		fprintf(stderr, "%s - thread create fail %s\n",
165 		    argv[0], strerror(errno));
166 		exit(1);
167 	}
168 
169 	sleep(1);
170 
171 	/* Create and connect the socket endpoint. */
172 
173 	sock = socket(AF_UNIX, SOCK_STREAM, 0);
174 	if (sock == -1) {
175 		fprintf(stderr, "%s - socket fail %s\n",
176 		    argv[0], strerror(errno));
177 		exit(1);
178 	}
179 
180 	ret = connect(sock, (struct sockaddr *)&addr, sizeof (addr));
181 	if (ret == -1) {
182 		fprintf(stderr, "%s - connect fail %s\n",
183 		    argv[0], strerror(errno));
184 		exit(1);
185 	}
186 
187 	/* Send some messages */
188 	for (i = 0; i < 5; i++) {
189 		struct iovec iov;
190 		struct msghdr msg;
191 		uint8_t buf[4096];
192 
193 		memcpy(buf, "TEST0", sizeof ("TEST0"));
194 		buf[4] = '0' + i;
195 
196 		printf("CLIENT:%s\n", buf);
197 
198 		iov = (struct iovec) {
199 			.iov_base = buf,
200 			.iov_len = sizeof (buf),
201 		};
202 
203 		msg = (struct msghdr) {
204 			.msg_iov = &iov,
205 			.msg_iovlen = 1,
206 		};
207 
208 		ret = sendmsg(sock, &msg, 0);
209 
210 		if (ret == -1) {
211 			fprintf(stderr, "%s - sendmsg fail %s\n",
212 			    argv[0], strerror(errno));
213 			exit(1);
214 		}
215 
216 		fflush(stdout);
217 		sleep(1);
218 	}
219 
220 	close(sock);
221 	return (0);
222 }
223