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 #include <sys/param.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <sys/socket.h>
27 #include <sys/un.h>
28 #include <stdio.h>
29 #include <unistd.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <stdint.h>
33 #include <stdlib.h>
34 #include <pthread.h>
35 
36 extern const char *__progname;
37 
38 static void *
39 server(void *varg)
40 {
41 	int ret;
42 	int sock = (int)varg;
43 	unsigned int i;
44 
45 	for (i = 0; i < 5; i++) {
46 		struct iovec iov;
47 		struct msghdr msg;
48 		uint8_t buf[4096];
49 
50 		iov = (struct iovec) {
51 			.iov_base = buf,
52 			.iov_len = sizeof (buf)
53 		};
54 
55 		msg = (struct msghdr) {
56 			.msg_iov = &iov,
57 			.msg_iovlen = 1,
58 		};
59 
60 		ret = recvmsg(sock, &msg, 0);
61 		if (ret == -1) {
62 			fprintf(stderr, "server - recvmsg fail %s\n",
63 			    strerror(errno));
64 			exit(1);
65 		}
66 
67 		printf("SERVER:%s\n", (char *)msg.msg_iov->iov_base);
68 		fflush(stdout);
69 	}
70 
71 	exit(0);
72 }
73 
74 static void *
75 listener(void *varg)
76 {
77 	struct sockaddr_un *addr = varg;
78 	int ret;
79 	int lsock;
80 	int asock;
81 
82 	/* Child. */
83 	lsock = socket(AF_UNIX, SOCK_STREAM, 0);
84 	if (lsock == -1) {
85 		fprintf(stderr, "listener - socket fail %s\n", strerror(errno));
86 		exit(1);
87 	}
88 
89 	ret = bind(lsock, (struct sockaddr *)addr, sizeof (*addr));
90 	if (ret == -1) {
91 		fprintf(stderr, "listener - bind fail %s\n", strerror(errno));
92 		exit(1);
93 	}
94 
95 	ret = listen(lsock, 5);
96 	if (ret == -1) {
97 		fprintf(stderr, "listener - listen fail %s\n", strerror(errno));
98 		exit(1);
99 	}
100 
101 	for (;;) {
102 		asock = accept(lsock, NULL, 0);
103 		if (asock == -1) {
104 			fprintf(stderr, "listener - accept fail %s\n",
105 			    strerror(errno));
106 			exit(1);
107 		}
108 
109 		/* start worker */
110 		ret = pthread_create(NULL, NULL, server, (void *)asock);
111 		if (ret == -1) {
112 			fprintf(stderr, "%s - thread create fail %s\n",
113 			    __progname, strerror(errno));
114 			exit(1);
115 		}
116 	}
117 
118 	exit(0);
119 }
120 
121 /*
122  * This should be a place only root is allowed to write.
123  * The test will create and destroy this directory.
124  */
125 char testdir[100] = "/var/run/os-tests-sockfs";
126 struct sockaddr_un addr;
127 int test_uid = UID_NOBODY;
128 
129 int
130 main(int argc, char **argv)
131 {
132 	int ret;
133 	int sock;
134 	unsigned int i;
135 
136 	if (argc > 1) {
137 		ret = strlcpy(testdir, argv[1], sizeof (testdir));
138 		if (ret >= sizeof (testdir)) {
139 			fprintf(stderr, "%s: too long\n", argv[1]);
140 			exit(1);
141 		}
142 	}
143 
144 	addr.sun_family = AF_UNIX;
145 	(void) sprintf(addr.sun_path, "%s/s", testdir);
146 
147 	if (mkdir(testdir, 0700) != 0) {
148 		switch (errno) {
149 		case EEXIST:
150 		case EISDIR:
151 			break;
152 		default:
153 			perror(testdir);
154 			exit(1);
155 		}
156 	}
157 	(void) unlink(addr.sun_path);
158 
159 	/* Set up the listener. */
160 	ret = pthread_create(NULL, NULL, listener, &addr);
161 	if (ret == -1) {
162 		fprintf(stderr, "%s - thread create fail %s\n",
163 		    argv[0], strerror(errno));
164 		exit(1);
165 	}
166 
167 	sleep(1);
168 
169 	/* Create and connect the socket endpoint. */
170 
171 	sock = socket(AF_UNIX, SOCK_STREAM, 0);
172 	if (sock == -1) {
173 		fprintf(stderr, "%s - socket fail %s\n",
174 		    argv[0], strerror(errno));
175 		exit(1);
176 	}
177 
178 	ret = connect(sock, (struct sockaddr *)&addr, sizeof (addr));
179 	if (ret == -1) {
180 		fprintf(stderr, "%s - connect fail %s\n",
181 		    argv[0], strerror(errno));
182 		exit(1);
183 	}
184 
185 	/* Send some messages */
186 	for (i = 0; i < 5; i++) {
187 		struct iovec iov;
188 		struct msghdr msg;
189 		uint8_t buf[4096];
190 
191 		memcpy(buf, "TEST0", sizeof ("TEST0"));
192 		buf[4] = '0' + i;
193 
194 		printf("CLIENT:%s\n", buf);
195 
196 		iov = (struct iovec) {
197 			.iov_base = buf,
198 			.iov_len = sizeof (buf),
199 		};
200 
201 		msg = (struct msghdr) {
202 			.msg_iov = &iov,
203 			.msg_iovlen = 1,
204 		};
205 
206 		ret = sendmsg(sock, &msg, 0);
207 
208 		if (ret == -1) {
209 			fprintf(stderr, "%s - sendmsg fail %s\n",
210 			    argv[0], strerror(errno));
211 			exit(1);
212 		}
213 
214 		fflush(stdout);
215 		sleep(1);
216 	}
217 
218 	close(sock);
219 	return (0);
220 }
221