1 /*
2    sock I/O tests
3 
4    Copyright (C) Amitay Isaacs  2017
5 
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #include "replace.h"
21 #include "system/filesys.h"
22 #include "system/network.h"
23 #include "system/wait.h"
24 
25 #include <assert.h>
26 
27 #include "common/sock_io.c"
28 
29 static int socket_init(const char *sockpath)
30 {
31 	struct sockaddr_un addr;
32 	int fd, ret;
33 	size_t len;
34 
35 	memset(&addr, 0, sizeof(addr));
36 	addr.sun_family = AF_UNIX;
37 
38 	len = strlcpy(addr.sun_path, sockpath, sizeof(addr.sun_path));
39 	assert(len < sizeof(addr.sun_path));
40 
41 	fd = socket(AF_UNIX, SOCK_STREAM, 0);
42 	assert(fd != -1);
43 
44 	ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr));
45 	assert(ret != -1);
46 
47 	ret = listen(fd, 10);
48 	assert(ret != -1);
49 
50 	return fd;
51 }
52 
53 static void test1_writer(int fd)
54 {
55 	uint8_t buf[1024];
56 	ssize_t nwritten;
57 	uint32_t len;
58 
59 	for (len = 10; len < 1000; len += 10) {
60 		int value = len / 10;
61 		uint32_t buflen = len + sizeof(uint32_t);
62 
63 		memset(buf,  value, buflen);
64 		memcpy(buf, &buflen, sizeof(uint32_t));
65 
66 		nwritten = sys_write(fd, buf, buflen);
67 		assert(nwritten == buflen);
68 	}
69 }
70 
71 struct test1_reader_state {
72 	size_t pkt_len;
73 	bool done;
74 };
75 
76 static void test1_reader(uint8_t *buf, size_t buflen, void *private_data)
77 {
78 	struct test1_reader_state *state =
79 		(struct test1_reader_state *)private_data;
80 
81 	if (buflen == 0) {
82 		state->done = true;
83 		return;
84 	}
85 
86 	assert(buflen == state->pkt_len);
87 
88 	state->pkt_len += 10;
89 }
90 
91 static void test1(TALLOC_CTX *mem_ctx, const char *sockpath)
92 {
93 	struct test1_reader_state state;
94 	struct tevent_context *ev;
95 	struct sock_queue *queue;
96 	pid_t pid;
97 	int pfd[2], fd, ret;
98 	ssize_t n;
99 
100 	ret = pipe(pfd);
101 	assert(ret == 0);
102 
103 	pid = fork();
104 	assert(pid != -1);
105 
106 	if (pid == 0) {
107 		int newfd;
108 
109 		close(pfd[0]);
110 
111 		fd = socket_init(sockpath);
112 		assert(fd != -1);
113 
114 		ret = 1;
115 		n = sys_write(pfd[1], &ret, sizeof(int));
116 		assert(n == sizeof(int));
117 
118 		newfd = accept(fd, NULL, NULL);
119 		assert(newfd != -1);
120 
121 		test1_writer(newfd);
122 		close(newfd);
123 		unlink(sockpath);
124 
125 		exit(0);
126 	}
127 
128 	close(pfd[1]);
129 
130 	n = sys_read(pfd[0], &ret, sizeof(int));
131 	assert(n == sizeof(int));
132 	assert(ret == 1);
133 
134 	close(pfd[0]);
135 
136 	fd = sock_connect(sockpath);
137 	assert(fd != -1);
138 
139 	ev = tevent_context_init(mem_ctx);
140 	assert(ev != NULL);
141 
142 	state.pkt_len = 10 + sizeof(uint32_t);
143 	state.done = false;
144 
145 	queue = sock_queue_setup(mem_ctx, ev, fd, test1_reader, &state);
146 	assert(queue != NULL);
147 
148 	while (! state.done) {
149 		tevent_loop_once(ev);
150 	}
151 
152 	talloc_free(queue);
153 	talloc_free(ev);
154 
155 	pid = wait(&ret);
156 	assert(pid != -1);
157 }
158 
159 static void test2_reader(int fd)
160 {
161 	uint8_t buf[1024];
162 	size_t pkt_len = 10 + sizeof(uint32_t);
163 	ssize_t n;
164 
165 	while (1) {
166 		n = sys_read(fd, buf, 1024);
167 		assert(n != -1);
168 
169 		if (n == 0) {
170 			return;
171 		}
172 
173 		assert((size_t)n == pkt_len);
174 		pkt_len += 10;
175 	}
176 }
177 
178 static void test2_dummy_reader(uint8_t *buf, size_t buflen,
179 			       void *private_data)
180 {
181 	abort();
182 }
183 
184 static void test2_writer(struct sock_queue *queue)
185 {
186 	uint8_t buf[1024];
187 	uint32_t len;
188 	int ret;
189 
190 	for (len = 10; len < 1000; len += 10) {
191 		int value = len / 10;
192 		uint32_t buflen = len + sizeof(uint32_t);
193 
194 		memset(buf,  value, buflen);
195 		memcpy(buf, &buflen, sizeof(uint32_t));
196 
197 		ret = sock_queue_write(queue, buf, buflen);
198 		assert(ret == 0);
199 	}
200 }
201 
202 static void test2(TALLOC_CTX *mem_ctx, const char *sockpath)
203 {
204 	struct tevent_context *ev;
205 	struct sock_queue *queue;
206 	pid_t pid;
207 	int pfd[2], fd, ret;
208 	ssize_t n;
209 
210 	ret = pipe(pfd);
211 	assert(ret == 0);
212 
213 	pid = fork();
214 	assert(pid != -1);
215 
216 	if (pid == 0) {
217 		int newfd;
218 
219 		close(pfd[0]);
220 
221 		fd = socket_init(sockpath);
222 		assert(fd != -1);
223 
224 		ret = 1;
225 		n = sys_write(pfd[1], &ret, sizeof(int));
226 		assert(n == sizeof(int));
227 
228 		newfd = accept(fd, NULL, NULL);
229 		assert(newfd != -1);
230 
231 		test2_reader(newfd);
232 		close(newfd);
233 		unlink(sockpath);
234 
235 		exit(0);
236 	}
237 
238 	close(pfd[1]);
239 
240 	n = sys_read(pfd[0], &ret, sizeof(int));
241 	assert(n == sizeof(int));
242 	assert(ret == 1);
243 
244 	close(pfd[0]);
245 
246 	fd = sock_connect(sockpath);
247 	assert(fd != -1);
248 
249 	ev = tevent_context_init(mem_ctx);
250 	assert(ev != NULL);
251 
252 	queue = sock_queue_setup(mem_ctx, ev, fd, test2_dummy_reader, NULL);
253 	assert(queue != NULL);
254 
255 	test2_writer(queue);
256 
257 	talloc_free(queue);
258 	talloc_free(ev);
259 
260 	pid = wait(&ret);
261 	assert(pid != -1);
262 }
263 
264 int main(int argc, const char **argv)
265 {
266 	TALLOC_CTX *mem_ctx;
267 	const char *sockpath;
268 
269 	if (argc != 2) {
270 		fprintf(stderr, "%s <sockpath>\n", argv[0]);
271 		exit(1);
272 	}
273 
274 	sockpath = argv[1];
275 
276 	mem_ctx = talloc_new(NULL);
277 	assert(mem_ctx != NULL);
278 
279 	test1(mem_ctx, sockpath);
280 	test2(mem_ctx, sockpath);
281 
282 	return 0;
283 }
284