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 static void *
37 server(void *varg)
38 {
39 	int *sfds = (int *)varg;
40 	int ret;
41 	int sock = sfds[0];
42 	unsigned int i;
43 
44 	for (i = 0; i < 5; i++) {
45 		struct iovec iov;
46 		struct msghdr msg;
47 		uint8_t buf[4096];
48 
49 		iov = (struct iovec) {
50 			.iov_base = buf,
51 			.iov_len = sizeof (buf)
52 		};
53 
54 		msg = (struct msghdr) {
55 			.msg_iov = &iov,
56 			.msg_iovlen = 1,
57 		};
58 
59 		ret = recvmsg(sock, &msg, 0);
60 		if (ret == -1) {
61 			fprintf(stderr, "server - recvmsg fail %s\n",
62 			    strerror(errno));
63 			exit(1);
64 		}
65 
66 		printf("SERVER:%s\n", (char *)msg.msg_iov->iov_base);
67 		fflush(stdout);
68 	}
69 
70 	exit(0);
71 }
72 
73 /*
74  * This should be a place only root is allowed to write.
75  * The test will create and destroy this directory.
76  */
77 char testdir[100] = "/var/run/os-tests-sockfs";
78 struct sockaddr_un addr;
79 int test_uid = UID_NOBODY;
80 
81 int
82 main(int argc, char **argv)
83 {
84 	int ret;
85 	int sfds[2];
86 	int sock;
87 	unsigned int i;
88 
89 	if (argc > 1) {
90 		ret = strlcpy(testdir, argv[1], sizeof (testdir));
91 		if (ret >= sizeof (testdir)) {
92 			fprintf(stderr, "%s: too long\n", argv[1]);
93 			exit(1);
94 		}
95 	}
96 
97 	addr.sun_family = AF_UNIX;
98 	(void) sprintf(addr.sun_path, "%s/s", testdir);
99 
100 	if (mkdir(testdir, 0700) != 0) {
101 		switch (errno) {
102 		case EEXIST:
103 		case EISDIR:
104 			break;
105 		default:
106 			perror(testdir);
107 			exit(1);
108 		}
109 	}
110 	(void) unlink(addr.sun_path);
111 
112 	/* Create socketpair */
113 	ret = socketpair(AF_UNIX, SOCK_STREAM, 0, sfds);
114 	if (ret == -1) {
115 		fprintf(stderr, "%s - socketpair fail %s\n",
116 		    argv[0], strerror(errno));
117 		exit(1);
118 	}
119 
120 	/* Set up the server. */
121 	ret = pthread_create(NULL, NULL, server, sfds);
122 	if (ret == -1) {
123 		fprintf(stderr, "%s - thread create fail %s\n",
124 		    argv[0], strerror(errno));
125 		exit(1);
126 	}
127 
128 	sleep(1);
129 
130 	/* "Server" is sfds[0], "client" is sfds[1] */
131 	sock = sfds[1];
132 
133 	/* Send some messages */
134 	for (i = 0; i < 5; i++) {
135 		struct iovec iov;
136 		struct msghdr msg;
137 		uint8_t buf[4096];
138 
139 		memcpy(buf, "TEST0", sizeof ("TEST0"));
140 		buf[4] = '0' + i;
141 
142 		printf("CLIENT:%s\n", buf);
143 
144 		iov = (struct iovec) {
145 			.iov_base = buf,
146 			.iov_len = sizeof (buf),
147 		};
148 
149 		msg = (struct msghdr) {
150 			.msg_iov = &iov,
151 			.msg_iovlen = 1,
152 		};
153 
154 		ret = sendmsg(sock, &msg, 0);
155 
156 		if (ret == -1) {
157 			fprintf(stderr, "%s - sendmsg fail %s\n",
158 			    argv[0], strerror(errno));
159 			exit(1);
160 		}
161 
162 		fflush(stdout);
163 		sleep(1);
164 	}
165 
166 	close(sock);
167 	return (0);
168 }
169