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