1 /* btdt.c --- "been there done that" low-level (C language) test support
2 *
3 * Copyright (C) 2011-2013 Thien-Thi Nguyen
4 * Copyright (C) 2000, 2001, 2002, 2003, 2004 Stefan Jahn <stefan@lkcc.org>
5 *
6 * This is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3, or (at your option)
9 * any later version.
10 *
11 * This software 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 GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this package. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "config.h"
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <time.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <errno.h>
27 #if HAVE_FLOSS_H
28 # include <floss.h>
29 #endif
30 #if HAVE_UNISTD_H
31 # include <unistd.h>
32 #endif
33
34 #ifndef __MINGW32__
35 # include <sys/types.h>
36 # include <sys/socket.h>
37 # include <netdb.h>
38 #else
39 # define sleep(x) Sleep ((x) * 1000)
40 # include <io.h>
41 #endif
42
43 #include "networking-headers.h"
44 #include "o-binary.h"
45 #include <libserveez.h>
46 #include "misc-macros.h"
47
48 int verbosep;
49
50
51 /*
52 * utility functions
53 */
54
55 /* Check that there are at least N args. If not,
56 display "missing args" message and exit failurefully. */
57 void
check_nargs(int argc,int n,char const * need)58 check_nargs (int argc, int n, char const *need)
59 {
60 if (n >= argc)
61 {
62 fprintf (stderr, "ERROR: missing args: %s\n", need);
63 exit (EXIT_FAILURE);
64 }
65 }
66
67 /* Initialize test suite. */
68 void
test_init(void)69 test_init (void)
70 {
71 srand (time (NULL));
72 }
73
74 /* Return a random string. */
75 char *
test_string(void)76 test_string (void)
77 {
78 static char text[0x101];
79 int length = (rand () & 0xff) + 1;
80
81 text[length] = '\0';
82 while (length--)
83 {
84 text[length] = (rand () % (128 - ' ')) + ' ';
85 }
86 return text;
87 }
88
89 /* Return a random number between 0 and NR - 1. */
90 unsigned long
test_value(unsigned long nr)91 test_value (unsigned long nr)
92 {
93 return nr ? (rand () % nr) : 0;
94 }
95
96 /* Print any text. */
97 void
test_print(char * text)98 test_print (char *text)
99 {
100 if (!verbosep)
101 return;
102 fprintf (stderr, text);
103 fflush (stderr);
104 }
105
106 /* Print an Ok. */
107 void
test_ok(void)108 test_ok (void)
109 {
110 if (!verbosep)
111 return;
112 fprintf (stderr, "ok\n");
113 fflush (stderr);
114 }
115
116 /* Print a Failed. */
117 void
test_failed(void)118 test_failed (void)
119 {
120 if (!verbosep)
121 return;
122 fprintf (stderr, "failed\n");
123 fflush (stderr);
124 }
125
126 /* Check ‘error’ and display results. */
127 #define test(error) do \
128 { \
129 if (error) \
130 { \
131 test_failed (); \
132 result++; \
133 } \
134 else \
135 test_ok (); \
136 } \
137 while (0)
138
139
140 /*
141 * data structure: array
142 */
143
144 /*
145 * Return how often the given value @var{value} is stored in the array
146 * @var{array}. Return zero if there is no such value.
147 */
148 size_t
array_popcount(svz_array_t * array,void * value)149 array_popcount (svz_array_t *array, void *value)
150 {
151 size_t n, size, found;
152
153 if (array == NULL)
154 return 0;
155 size = svz_array_size (array);
156 for (found = n = 0; n < size; n++)
157 if (svz_array_get (array, n) == value)
158 found++;
159 return found;
160 }
161
162 int
array_main(int argc,char ** argv)163 array_main (int argc, char **argv)
164 {
165 size_t repeat;
166 int result = 0;
167 svz_array_t *array;
168 size_t n;
169 int error;
170 void *value;
171 size_t cur[2];
172
173 check_nargs (argc, 1, "REPEAT (integer)");
174 repeat = atoi (argv[1]);
175
176 test_init ();
177 test_print ("array function test suite\n");
178
179 #define AGAIN(array) (array = svz_array_create (0, NULL))
180 #define CLEAR(array) (svz_array_destroy (array), AGAIN (array))
181
182 /* array creation */
183 error = 0;
184 test_print (" create: ");
185 if (AGAIN (array) == NULL)
186 error++;
187 if (svz_array_size (array) != 0)
188 error++;
189 test (error);
190
191 /* add and get functions */
192 test_print (" add: ");
193 for (n = 0; n < repeat; n++)
194 svz_array_add (array, (void *) (n + 1));
195 test (repeat != svz_array_size (array));
196
197 test_print (" get: ");
198 for (error = n = 0; n < repeat; n++)
199 if (svz_array_get (array, n) != (void *) (n + 1))
200 error++;
201 if (svz_array_get (array, n) != NULL || svz_array_get (array, -1) != NULL)
202 error++;
203 test (error);
204
205 /* array iteration */
206 error = 0;
207 test_print (" iterate: ");
208 svz_array_foreach (array, value, n)
209 if (value != (void *) (n + 1))
210 error++;
211 if (n != repeat || n != svz_array_size (array))
212 error++;
213 test (error);
214
215 /* set function */
216 test_print (" set: ");
217 for (error = n = 0; n < repeat; n++)
218 if (svz_array_set (array, n, (void *) (repeat - n)) != (void *) (n + 1))
219 error++;
220 test (error);
221
222 /* delete function */
223 test_print (" delete: ");
224 for (error = n = 0; n < repeat; n++)
225 if (svz_array_del (array, 0) != (void *) (repeat - n))
226 error++;
227 if (svz_array_size (array) != 0)
228 error++;
229
230 if (svz_array_del (array, -1) != NULL || svz_array_del (array, n) != NULL)
231 error++;
232 for (n = 0; n < repeat; n++)
233 svz_array_add (array, (void *) n);
234 for (n = repeat; n--;)
235 if (svz_array_del (array, n) != (void *) n)
236 error++;
237 if (svz_array_size (array) != 0)
238 error++;
239 test (error);
240
241 /* check the `contains' function */
242 test_print (" contains: ");
243 error = 0;
244 for (n = 0; n < repeat; n++)
245 if (array_popcount (array, (void *) n))
246 error++;
247 for (n = 0; n < repeat; n++)
248 {
249 svz_array_add (array, (void *) n);
250 if (array_popcount (array, (void *) n) != 1)
251 error++;
252 }
253 for (n = 0; n < repeat; n++)
254 {
255 svz_array_set (array, n, (void *) 0);
256 if (array_popcount (array, (void *) 0) != n + 1)
257 error++;
258 }
259 CLEAR (array);
260 if (array_popcount (array, (void *) 0) != 0)
261 error++;
262 test (error);
263
264 /* destroy function */
265 test_print (" destroy: ");
266 svz_array_destroy (array);
267 test_ok ();
268
269 /* is heap ok? */
270 test_print (" heap: ");
271 svz_get_curalloc (cur);
272 test (cur[0] || cur[1]);
273
274 #undef CLEAR
275 #undef AGAIN
276
277 return result;
278 }
279
280
281 /*
282 * data structure: hash table
283 */
284
285 struct it_test
286 {
287 long k_count;
288 long v_acc;
289 };
290
291 void
hash_count(void * k,void * v,void * closure)292 hash_count (void *k, void *v, void *closure)
293 {
294 struct it_test *x = closure;
295
296 if (k)
297 x->k_count++;
298 x->v_acc += (long) v;
299 }
300
301 void
hash_clear(svz_hash_t ** hash)302 hash_clear (svz_hash_t **hash)
303 {
304 svz_hash_destroy (*hash);
305 *hash = svz_hash_create (4, NULL);
306 }
307
308 struct hash_pair
309 {
310 char *key;
311 long value;
312 };
313
314 void
hash_accumulate(void * k,void * v,void * closure)315 hash_accumulate (void *k, void *v, void *closure)
316 {
317 char *key = k;
318 long value = SVZ_PTR2NUM (v);
319 svz_array_t *array = closure;
320 struct hash_pair *pair = svz_malloc (sizeof (struct hash_pair));
321
322 pair->key = key;
323 pair->value = value;
324 svz_array_add (array, pair);
325 }
326
327 int
hash_main(int argc,char ** argv)328 hash_main (int argc, char **argv)
329 {
330 size_t repeat;
331 int result = 0;
332 svz_hash_t *hash;
333 size_t n;
334 long error;
335 char *text;
336 size_t cur[2];
337
338 check_nargs (argc, 1, "REPEAT (integer)");
339 repeat = atoi (argv[1]);
340
341 test_print ("hash function test suite\n");
342
343 /* hash creation */
344 test_print (" create: ");
345 test ((hash = svz_hash_create (4, NULL)) == NULL);
346
347 /* hash put and get */
348 test_print (" put/get and exists: ");
349 for (error = n = 0; n < repeat; n++)
350 {
351 text = svz_strdup (test_string ());
352 svz_hash_put (hash, text, (void *) 0xdeadbeef);
353 if (((void *) 0xdeadbeef != svz_hash_get (hash, text)))
354 error++;
355 if (svz_hash_exists (hash, text) == 0)
356 error++;
357 svz_free (text);
358 }
359 test (error);
360
361 /* hash containing a certain value */
362 test_print (" contains: ");
363 error = 0;
364 if (svz_hash_contains (hash, NULL))
365 error++;
366 if (svz_hash_contains (hash, (void *) 0xeabceabc))
367 error++;
368 svz_hash_put (hash, "1234567890", (void *) 0xeabceabc);
369 if (strcmp ("1234567890", svz_hash_contains (hash, (void *) 0xeabceabc)))
370 error++;
371 test (error);
372
373 /* hash key deletion */
374 test_print (" delete: ");
375 error = 0;
376 n = svz_hash_size (hash);
377 if ((void *) 0xeabceabc != svz_hash_delete (hash, "1234567890"))
378 error++;
379 if (n - 1 != svz_hash_size (hash))
380 error++;
381 test (error);
382
383 /* keys and values */
384 test_print (" keys and values: ");
385 hash_clear (&hash);
386 error = 0;
387 text = svz_malloc (16);
388 for (n = 0; n < repeat; n++)
389 {
390 sprintf (text, "%015lu", (unsigned long) n);
391 svz_hash_put (hash, text, (void *) n);
392 if (svz_hash_get (hash, text) != (void *) n)
393 error++;
394 }
395 svz_free (text);
396 if (n != svz_hash_size (hash))
397 error++;
398 {
399 svz_array_t *array = svz_array_create (repeat, svz_free);
400 struct hash_pair *p;
401
402 svz_hash_foreach (hash_accumulate, hash, array);
403 if (svz_array_size (array))
404 svz_array_foreach (array, p, n)
405 {
406 if (atol (p->key) != p->value)
407 error++;
408 if (svz_hash_get (hash, p->key) != SVZ_NUM2PTR (p->value))
409 error++;
410 if (svz_hash_contains (hash, SVZ_NUM2PTR (p->value)) != p->key)
411 error++;
412 }
413 else
414 error++;
415 svz_array_destroy (array);
416 }
417 if (svz_hash_size (hash) != repeat)
418 error++;
419 test (error);
420
421 /* hash clear */
422 test_print (" clear: ");
423 hash_clear (&hash);
424 test (svz_hash_size (hash));
425
426 /* hash destruction */
427 test_print (" destroy: ");
428 svz_hash_destroy (hash);
429 test_ok ();
430
431 /* hash iteration */
432 hash = svz_hash_create (4, NULL);
433
434 svz_hash_put (hash, "1234567890", (void *) 1);
435 svz_hash_put (hash, "1234567891", (void *) 2);
436 svz_hash_put (hash, "1234567892", (void *) 3);
437
438 test_print (" iteration: ");
439 {
440 struct it_test x = { 0L, 0L };
441
442 svz_hash_foreach (hash_count, hash, &x);
443 test (x.k_count != 3 || x.v_acc != 6);
444 }
445
446 svz_hash_destroy (hash);
447
448 /* is heap ok ? */
449 test_print (" heap: ");
450 svz_get_curalloc (cur);
451 test (cur[0] || cur[1]);
452
453 return result;
454 }
455
456
457 /*
458 * codec
459 */
460
461 /*
462 * Stdin reader for the codec test. Read as much data as
463 * available and set the socket flags to ‘SVZ_SOFLG_FLUSH’ if
464 * ready. Invoke the ‘check_request’ callback each time some
465 * data has been received. Very likely any other ‘read_socket’
466 * callback. [??? Incomplete sentence. --ttn]
467 */
468 int
codec_recv(svz_socket_t * sock)469 codec_recv (svz_socket_t *sock)
470 {
471 int num_read, do_read;
472
473 if ((do_read = sock->recv_buffer_size - sock->recv_buffer_fill) <= 0)
474 return 0;
475 num_read = read ((int) sock->pipe_desc[SVZ_READ],
476 sock->recv_buffer + sock->recv_buffer_fill, do_read);
477 #ifndef __MINGW32__
478 if (num_read < 0 && errno == EAGAIN)
479 return 0;
480 #endif
481 if (num_read <= 0)
482 {
483 sock->flags |= SVZ_SOFLG_FLUSH;
484 close ((int) sock->pipe_desc[SVZ_READ]);
485 num_read = 0;
486 }
487 sock->recv_buffer_fill += num_read;
488 return sock->check_request (sock);
489 }
490
491 /*
492 * Stdout writer. Write as much data as possible to stdout,
493 * removing written bytes from the send buffer. Very likely any
494 * other ‘write_socket’ callback. [??? Incomplete sentence. --ttn]
495 */
496 int
codec_send(svz_socket_t * sock)497 codec_send (svz_socket_t *sock)
498 {
499 int num_written, do_write;
500
501 if ((do_write = sock->send_buffer_fill) <= 0)
502 return 0;
503 num_written = write ((int) sock->pipe_desc[SVZ_WRITE],
504 sock->send_buffer, do_write);
505 #ifndef __MINGW32__
506 if (num_written < 0 && errno == EAGAIN)
507 return 0;
508 #endif
509 if (num_written <= 0)
510 return -1;
511 if (num_written < do_write)
512 memmove (sock->send_buffer, sock->send_buffer + num_written,
513 do_write - num_written);
514 sock->send_buffer_fill -= num_written;
515 return 0;
516 }
517
518 /* Most simple ‘check_request’ callback I could think of.
519 Simply copy the receive buffer into the send buffer. */
520 int
codec_check(svz_socket_t * sock)521 codec_check (svz_socket_t *sock)
522 {
523 if (svz_sock_write (sock, sock->recv_buffer, sock->recv_buffer_fill))
524 return -1;
525 sock->recv_buffer_fill = 0;
526 return 0;
527 }
528
529 struct codec_list_closure
530 {
531 int type;
532 FILE *to;
533 };
534
535 int
codec_list_internal(const svz_codec_t * codec,void * closure)536 codec_list_internal (const svz_codec_t *codec, void *closure)
537 {
538 struct codec_list_closure *x = closure;
539
540 if (codec->type == x->type)
541 fprintf (x->to, " %s", codec->description);
542 return 0;
543 }
544
545 void
codec_list(FILE * to)546 codec_list (FILE *to)
547 {
548 struct codec_list_closure x;
549
550 x.to = to;
551 fprintf (to, "--- list of available codecs ---");
552
553 /* Print encoder list. */
554 fprintf (to, "\n\tencoder:");
555 x.type = SVZ_CODEC_ENCODER;
556 svz_foreach_codec (codec_list_internal, &x);
557
558 /* Print decoder list. */
559 fprintf (to, "\n\tdecoder:");
560 x.type = SVZ_CODEC_DECODER;
561 svz_foreach_codec (codec_list_internal, &x);
562
563 fprintf (to, "\n");
564 }
565
566 /*
567 * Main entry point for codec tests.
568 */
569 int
codec_main(int argc,char ** argv)570 codec_main (int argc, char **argv)
571 {
572 int result = 1, id, version;
573 svz_socket_t *sock;
574 svz_codec_t *codec;
575 char *desc;
576 size_t cur[2];
577
578 check_nargs (argc, 1, "CODEC < INFILE > OUTFILE");
579
580 /* Setup serveez core library. */
581 svz_boot ("codec");
582 #if ENABLE_DEBUG
583 SVZ_RUNPARM_X (VERBOSITY, 9);
584 svz_log_setfile (stderr);
585 #endif
586
587 #ifdef __MINGW32__
588 setmode (fileno (stdin), O_BINARY);
589 setmode (fileno (stdout), O_BINARY);
590 #endif
591
592 /* Create single pipe socket for stdin and stdout. */
593 if ((sock = svz_pipe_create ((svz_t_handle) fileno (stdin),
594 (svz_t_handle) fileno (stdout))) == NULL)
595 return result;
596 sock->read_socket = codec_recv;
597 sock->write_socket = codec_send;
598 sock->check_request = codec_check;
599 if (svz_sock_enqueue (sock))
600 return result;
601 id = sock->id;
602 version = sock->version;
603
604 /* Setup codecs. */
605 desc = argv[1];
606 if ((codec = svz_codec_get (desc, SVZ_CODEC_ENCODER)) == NULL)
607 {
608 codec_list (stderr);
609 return result;
610 }
611 if (svz_codec_sock_receive_setup (sock, codec))
612 return result;
613 if ((codec = svz_codec_get (desc, SVZ_CODEC_DECODER)) == NULL)
614 {
615 codec_list (stderr);
616 return result;
617 }
618 if (svz_codec_sock_send_setup (sock, codec))
619 return result;
620
621 /* Run server loop. */
622 svz_loop_pre ();
623 do
624 {
625 svz_loop_one ();
626 }
627 while (svz_sock_find (id, version) && !svz_shutting_down_p ());
628 svz_loop_post ();
629
630 /* Finalize the core API. */
631 svz_halt ();
632
633 svz_get_curalloc (cur);
634 if (cur[0] || cur[1])
635 return 1;
636
637 return EXIT_SUCCESS;
638 }
639
640
641 /*
642 * program passthrough
643 */
644
645 int
spew_main(int argc,char ** argv)646 spew_main (int argc, char **argv)
647 {
648 int s;
649 struct sockaddr_in addr;
650 socklen_t len = sizeof (struct sockaddr_in);
651 char *buf1 = "write: Hello\r\n";
652 char *buf2 = "send: Hello\r\n";
653
654 check_nargs (argc, 1, "SLEEP (seconds, integer)");
655 #ifdef __MINGW32__
656 WSADATA WSAData;
657 WSAStartup (0x0202, &WSAData);
658 #endif /* __MINGW32__ */
659
660 if (verbosep)
661 {
662 int i;
663
664 fprintf (stderr, "start...\r\n");
665 for (i = 0; i < argc; i++)
666 fprintf (stderr, " argv[%d] = \"%s\"\r\n", i, argv[i]);
667 fflush (stderr);
668 }
669
670 /* Obtain output descriptor. */
671 #ifdef __MINGW32__
672 if (getenv ("SEND_HANDLE") != NULL)
673 s = atoi (getenv ("SEND_HANDLE"));
674 else
675 s = fileno (stdout);
676 #else
677 s = fileno (stdout);
678 #endif
679
680 /* Determine remote connection. */
681 if (getpeername ((svz_t_socket) s, (struct sockaddr *) &addr, &len) < 0)
682 {
683 fprintf (stderr, "getpeername: %s\n", strerror (errno));
684 fflush (stderr);
685 }
686 else
687 {
688 /* Try using ‘fprintf’. */
689 fprintf (stdout, "fprintf: %s:%d\r\n",
690 inet_ntoa ((* ((struct in_addr *) &addr.sin_addr))),
691 ntohs (addr.sin_port));
692 fflush (stdout);
693 }
694
695 /* Try using ‘write’. */
696 if (write (s, buf1, strlen (buf1)) < 0)
697 {
698 fprintf (stderr, "write: %s\n", strerror (errno));
699 fflush (stderr);
700 }
701 /* Try using ‘send’. */
702 if (send (s, buf2, strlen (buf2), 0) < 0)
703 {
704 fprintf (stderr, "send: %s\n", strerror (errno));
705 fflush (stderr);
706 }
707
708 fflush (stdout);
709 sleep (atoi (argv[1]));
710
711 #ifdef __MINGW32__
712 shutdown (s, 2);
713 svz_closesocket (s);
714 WSACleanup();
715 #endif /* __MINGW32__ */
716
717 fprintf (stderr, "...end\r\n");
718 return EXIT_SUCCESS;
719 }
720
721
722 /*
723 * dispatch
724 */
725
726 struct avail
727 {
728 char const *name;
729 int (*sub) (int argc, char **argv);
730 };
731
732 #define SUB(x) { #x, x ## _main }
733
734 struct avail avail[] =
735 {
736 SUB (array),
737 SUB (hash),
738 SUB (codec),
739 SUB (spew),
740 { NULL, NULL }
741 };
742
743 int
main(int argc,char ** argv)744 main (int argc, char **argv)
745 {
746 struct avail *a = avail;
747
748 if (1 > argc)
749 return EXIT_FAILURE;
750
751 {
752 char *v = getenv ("VERBOSE");
753
754 if (v && !strcmp ("1", v))
755 verbosep = 1;
756 }
757
758 for (a = avail; a->name; a++)
759 if (!strcmp (argv[1], a->name))
760 return a->sub (argc - 1, argv + 1);
761
762 return EXIT_FAILURE;
763 }
764