1 /*
2    comm tests
3 
4    Copyright (C) Amitay Isaacs  2015
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 
23 #include <assert.h>
24 
25 #include "common/pkt_read.c"
26 #include "common/pkt_write.c"
27 #include "common/comm.c"
28 
29 /*
30  * Test read_handler and dead_handler
31  */
32 
33 static void test1_read_handler(uint8_t *buf, size_t buflen,
34 			       void *private_data)
35 {
36 	int *result = (int *)private_data;
37 
38 	*result = -1;
39 }
40 
41 static void test1_dead_handler(void *private_data)
echo_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,int fd)42 {
43 	int *result = (int *)private_data;
44 
45 	*result = 1;
46 }
47 
48 static void test1(void)
49 {
50 	TALLOC_CTX *mem_ctx;
51 	struct tevent_context *ev;
52 	struct comm_context *comm;
53 	int fd[2];
54 	int result = 0;
55 	uint32_t data[2];
56 	int ret;
57 	ssize_t n;
58 
59 	mem_ctx = talloc_new(NULL);
60 	assert(mem_ctx != NULL);
61 
62 	ev = tevent_context_init(mem_ctx);
63 	assert(ev != NULL);
64 
65 	ret = pipe(fd);
66 	assert(ret == 0);
read_handler(uint8_t * buf,size_t buflen,void * private_data)67 
68 	ret = comm_setup(ev, ev, fd[0], test1_read_handler, &result,
69 			 test1_dead_handler, &result, &comm);
70 	assert(ret == 0);
71 
72 	data[0] = 2 * sizeof(uint32_t);
73 	data[1] = 0;
74 
75 	n = write(fd[1], (void *)&data, data[0]);
76 	assert(n == data[0]);
77 
78 	while (result == 0) {
79 		tevent_loop_once(ev);
80 	}
81 
82 	assert(result == -1);
83 
84 	result = 0;
85 	close(fd[1]);
86 
87 	while (result == 0) {
read_failed(void * private_data)88 		tevent_loop_once(ev);
89 	}
90 
91 	assert(result == 1);
92 
93 	talloc_free(mem_ctx);
94 }
95 
write_done(struct tevent_req * subreq)96 /*
97  * Test that the tevent_req returned by comm_write_send() can be free'd.
98  */
99 
100 struct test2_state {
101 	TALLOC_CTX *mem_ctx;
102 	bool done;
103 };
104 
105 static void test2_read_handler(uint8_t *buf, size_t buflen,
106 			       void *private_data)
107 {
108 	struct test2_state *state = (struct test2_state *)private_data;
109 
110 	TALLOC_FREE(state->mem_ctx);
111 }
112 
113 static void test2_dead_handler(void *private_data)
114 {
echo_recv(struct tevent_req * req,int * perr)115 	abort();
116 }
117 
118 struct test2_write_state {
119 	int count;
120 };
121 
122 static void test2_write_done(struct tevent_req *subreq);
123 
124 static struct tevent_req *test2_write_send(TALLOC_CTX *mem_ctx,
125 					   struct tevent_context *ev,
126 					   struct comm_context *comm,
127 					   uint8_t *buf, size_t buflen)
128 {
129 	struct tevent_req *req, *subreq;
130 	struct test2_write_state *state;
131 	int i;
132 
133 	req = tevent_req_create(mem_ctx, &state, struct test2_write_state);
134 	if (req == NULL) {
135 		return NULL;
136 	}
137 
138 	state->count = 0;
139 
140 	for (i=0; i<10; i++) {
141 		subreq = comm_write_send(state, ev, comm, buf, buflen);
142 		if (tevent_req_nomem(subreq, req)) {
socket_process_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,int fd,int max_clients)143 			return tevent_req_post(req, ev);
144 		}
145 		tevent_req_set_callback(subreq, test2_write_done, req);
146 	}
147 
148 	return req;
149 }
150 
151 static void test2_write_done(struct tevent_req *subreq)
152 {
153 	struct tevent_req *req = tevent_req_callback_data(
154 		subreq, struct tevent_req);
155 	struct test2_write_state *state = tevent_req_data(
156 		req, struct test2_write_state);
157 	bool status;
158 	int ret;
159 
160 	status = comm_write_recv(subreq, &ret);
161 	TALLOC_FREE(subreq);
162 	if (! status) {
163 		tevent_req_error(req, ret);
164 		return;
165 	}
166 
167 	state->count += 1;
168 
socket_process_client(struct tevent_req * subreq)169 	if (state->count == 10) {
170 		tevent_req_done(req);
171 	}
172 }
173 
174 static void test2_timer_handler(struct tevent_context *ev,
175 				struct tevent_timer *te,
176 				struct timeval cur_time,
177 				void *private_data)
178 {
179 	struct test2_state *state = (struct test2_state *)private_data;
180 
181 	state->done = true;
182 }
183 
184 static void test2(void)
185 {
186 	TALLOC_CTX *mem_ctx;
187 	struct tevent_context *ev;
188 	struct comm_context *comm_reader, *comm_writer;
189 	struct test2_state test2_state;
190 	struct tevent_req *req;
191 	struct tevent_timer *te;
192 	int fd[2];
193 	uint32_t data[2];
194 	int ret;
195 
196 	mem_ctx = talloc_new(NULL);
197 	assert(mem_ctx != NULL);
198 
199 	test2_state.mem_ctx = talloc_new(mem_ctx);
200 	assert(test2_state.mem_ctx != NULL);
201 
202 	test2_state.done = false;
203 
204 	ev = tevent_context_init(mem_ctx);
205 	assert(ev != NULL);
socket_process_client_done(struct tevent_req * subreq)206 
207 	ret = pipe(fd);
208 	assert(ret == 0);
209 
210 	ret = comm_setup(ev, ev, fd[0], test2_read_handler, &test2_state,
211 			 test2_dead_handler, NULL, &comm_reader);
212 	assert(ret == 0);
213 
214 	ret = comm_setup(ev, ev, fd[1], NULL, NULL, test2_dead_handler, NULL,
215 			 &comm_writer);
216 	assert(ret == 0);
217 
218 	data[0] = 2 * sizeof(uint32_t);
219 	data[1] = 0;
220 
221 	req = test2_write_send(test2_state.mem_ctx, ev, comm_writer,
222 			       (uint8_t *)data, data[0]);
223 	assert(req != NULL);
224 
225 	te = tevent_add_timer(ev, ev, tevent_timeval_current_ofs(5,0),
226 			      test2_timer_handler, &test2_state);
socket_process_recv(struct tevent_req * req,int * perr)227 	assert(te != NULL);
228 
229 	while (! test2_state.done) {
230 		tevent_loop_once(ev);
231 	}
232 
233 	talloc_free(mem_ctx);
234 }
235 
236 /*
237  * Test that data is written and read correctly.
socket_init(char * sockpath)238  */
239 
240 static void test3_dead_handler(void *private_data)
241 {
242 	int dead_data = *(int *)private_data;
243 
244 	assert(dead_data == 1 || dead_data == 2);
245 
246 	if (dead_data == 1) {
247 		/* reader */
248 		fprintf(stderr, "writer closed pipe\n");
249 	} else {
250 		/* writer */
251 		fprintf(stderr, "reader closed pipe\n");
252 	}
253 }
254 
255 struct test3_writer_state {
256 	struct tevent_context *ev;
257 	struct comm_context *comm;
258 	uint8_t *buf;
259 	size_t *pkt_size;
260 	int count, id;
261 };
main(int argc,char * argv[])262 
263 static void test3_writer_next(struct tevent_req *subreq);
264 
265 static struct tevent_req *test3_writer_send(TALLOC_CTX *mem_ctx,
266 					    struct tevent_context *ev,
267 					    struct comm_context *comm,
268 					    size_t *pkt_size, size_t count)
269 {
270 	struct tevent_req *req, *subreq;
271 	struct test3_writer_state *state;
272 	size_t max_size = 0, buflen;
273 	size_t i;
274 
275 	for (i=0; i<count; i++) {
276 		if (pkt_size[i] > max_size) {
277 			max_size = pkt_size[i];
278 		}
279 	}
280 
281 	req = tevent_req_create(mem_ctx, &state, struct test3_writer_state);
282 	if (req == NULL) {
283 		return NULL;
284 	}
285 
286 	state->ev = ev;
287 	state->comm = comm;
288 	state->pkt_size = pkt_size;
289 	state->count = count;
290 	state->id = 0;
291 
292 	state->buf = talloc_array(state, uint8_t, max_size);
293 	if (state->buf == NULL) {
294 		talloc_free(req);
295 		return NULL;
296 	}
297 	for (i=0; i<max_size; i++) {
298 		state->buf[i] = i%256;
299 	}
300 
301 	buflen = state->pkt_size[state->id];
302 	*(uint32_t *)state->buf = buflen;
303 	subreq = comm_write_send(state, state->ev, state->comm,
304 					 state->buf, buflen);
305 	if (tevent_req_nomem(subreq, req)) {
306 		return tevent_req_post(req, ev);
307 	}
308 
309 	tevent_req_set_callback(subreq, test3_writer_next, req);
310 	return req;
311 }
312 
313 static void test3_writer_next(struct tevent_req *subreq)
314 {
315 	struct tevent_req *req = tevent_req_callback_data(
316 		subreq, struct tevent_req);
317 	struct test3_writer_state *state = tevent_req_data(
318 		req, struct test3_writer_state);
319 	bool ret;
320 	int err;
321 	size_t buflen;
322 
323 	ret = comm_write_recv(subreq, &err);
324 	TALLOC_FREE(subreq);
325 	if (!ret) {
326 		tevent_req_error(req, err);
327 		return;
328 	}
329 
330 	state->id++;
331 	if (state->id >= state->count) {
332 		tevent_req_done(req);
333 		return;
334 	}
335 
336 	buflen = state->pkt_size[state->id];
337 	*(uint32_t *)state->buf = buflen;
338 	subreq = comm_write_send(state, state->ev, state->comm,
339 					 state->buf, buflen);
340 	if (tevent_req_nomem(subreq, req)) {
341 		return;
342 	}
343 
344 	tevent_req_set_callback(subreq, test3_writer_next, req);
345 }
346 
347 static void test3_writer_recv(struct tevent_req *req, int *perr)
348 {
349 	if (tevent_req_is_unix_error(req, perr)) {
350 		return;
351 	}
352 	*perr = 0;
353 }
354 
355 static void test3_writer(int fd, size_t *pkt_size, size_t count)
356 {
357 	TALLOC_CTX *mem_ctx;
358 	struct tevent_context *ev;
359 	struct comm_context *comm;
360 	struct tevent_req *req;
361 	int dead_data = 2;
362 	int err;
363 
364 	mem_ctx = talloc_new(NULL);
365 	assert(mem_ctx != NULL);
366 
367 	ev = tevent_context_init(mem_ctx);
368 	assert(ev != NULL);
369 
370 	err = comm_setup(mem_ctx, ev, fd, NULL, NULL,
371 			 test3_dead_handler, &dead_data, &comm);
372 	assert(err == 0);
373 	assert(comm != NULL);
374 
375 	req = test3_writer_send(mem_ctx, ev, comm, pkt_size, count);
376 	assert(req != NULL);
377 
378 	tevent_req_poll(req, ev);
379 
380 	test3_writer_recv(req, &err);
381 	assert(err == 0);
382 
383 	talloc_free(mem_ctx);
384 }
385 
386 struct test3_reader_state {
387 	size_t *pkt_size;
388 	int count, received;
389 	bool done;
390 };
391 
392 static void test3_reader_handler(uint8_t *buf, size_t buflen,
393 				 void *private_data)
394 {
395 	struct test3_reader_state *state = talloc_get_type_abort(
396 		private_data, struct test3_reader_state);
397 
398 	assert(buflen == state->pkt_size[state->received]);
399 	printf("%zi ", buflen);
400 	state->received++;
401 
402 	if (state->received == state->count) {
403 		printf("\n");
404 		state->done = true;
405 	}
406 }
407 
408 static void test3_reader(int fd, size_t *pkt_size, int count)
409 {
410 	TALLOC_CTX *mem_ctx;
411 	struct tevent_context *ev;
412 	struct comm_context *comm;
413 	struct test3_reader_state *state;
414 	int dead_data = 1;
415 	int err;
416 
417 	mem_ctx = talloc_new(NULL);
418 	assert(mem_ctx != NULL);
419 
420 	ev = tevent_context_init(mem_ctx);
421 	assert(ev != NULL);
422 
423 	state = talloc_zero(mem_ctx, struct test3_reader_state);
424 	assert(state != NULL);
425 
426 	state->pkt_size = pkt_size;
427 	state->count = count;
428 	state->received = 0;
429 	state->done = false;
430 
431 	err = comm_setup(mem_ctx, ev, fd, test3_reader_handler, state,
432 			 test3_dead_handler, &dead_data, &comm);
433 	assert(err == 0);
434 	assert(comm != NULL);
435 
436 	while (!state->done) {
437 		tevent_loop_once(ev);
438 	}
439 
440 	talloc_free(mem_ctx);
441 }
442 
443 static void test3(void)
444 {
445 	int fd[2];
446 	int ret;
447 	pid_t pid;
448 	size_t pkt_size[13] = { 100, 2048, 500, 4096, 1024, 8192,
449 			      200, 16384, 300, 32768, 400, 65536,
450 			      1024*1024 };
451 
452 	ret = pipe(fd);
453 	assert(ret == 0);
454 
455 	pid = fork();
456 	assert(pid != -1);
457 
458 	if (pid == 0) {
459 		/* Child process */
460 		close(fd[0]);
461 		test3_writer(fd[1], pkt_size, 13);
462 		close(fd[1]);
463 		exit(0);
464 	}
465 
466 	close(fd[1]);
467 	test3_reader(fd[0], pkt_size, 13);
468 	close(fd[0]);
469 }
470 
471 
472 int main(int argc, const char **argv)
473 {
474 	int num;
475 
476 	if (argc != 2) {
477 		fprintf(stderr, "%s <testnum>\n", argv[0]);
478 		exit(1);
479 	}
480 
481 	num = atoi(argv[1]);
482 
483 	switch (num) {
484 	case 1:
485 		test1();
486 		break;
487 
488 	case 2:
489 		test2();
490 		break;
491 
492 	case 3:
493 		test3();
494 		break;
495 
496 	default:
497 		fprintf(stderr, "Unknown test number %s\n", argv[1]);
498 	}
499 
500 	return 0;
501 }
502