misc: strcpy be gone
[vpp.git] / src / plugins / hs_apps / vcl / sock_test_client.c
1 /*
2  * Copyright (c) 2017-2019 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #include <unistd.h>
17 #include <errno.h>
18 #include <stdlib.h>
19 #include <ctype.h>
20 #include <sys/types.h>
21 #include <sys/socket.h>
22 #include <stdio.h>
23 #include <time.h>
24 #include <arpa/inet.h>
25 #include <hs_apps/vcl/sock_test.h>
26 #include <fcntl.h>
27 #ifndef VCL_TEST
28 #include <sys/un.h>
29 #endif
30
31 typedef struct
32 {
33 #ifdef VCL_TEST
34   vppcom_endpt_t server_endpt;
35 #else
36   int af_unix_echo_tx;
37   int af_unix_echo_rx;
38 #endif
39   struct sockaddr_storage server_addr;
40   uint32_t server_addr_size;
41   uint32_t cfg_seq_num;
42   vcl_test_session_t ctrl_socket;
43   vcl_test_session_t *test_socket;
44   uint32_t num_test_sockets;
45   uint8_t dump_cfg;
46 } sock_client_main_t;
47
48 sock_client_main_t vcl_client_main;
49
50
51 static int
52 sock_test_cfg_sync (vcl_test_session_t * socket)
53 {
54   sock_client_main_t *scm = &vcl_client_main;
55   vcl_test_session_t *ctrl = &scm->ctrl_socket;
56   vcl_test_cfg_t *rl_cfg = (vcl_test_cfg_t *) socket->rxbuf;
57   int rx_bytes, tx_bytes;
58
59   if (socket->cfg.verbose)
60     vcl_test_cfg_dump (&socket->cfg, 1 /* is_client */ );
61
62   ctrl->cfg.seq_num = ++scm->cfg_seq_num;
63   if (socket->cfg.verbose)
64     {
65       printf ("CLIENT (fd %d): Sending config sent to server.\n", socket->fd);
66       vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
67     }
68   tx_bytes = sock_test_write (socket->fd, (uint8_t *) & ctrl->cfg,
69                               sizeof (ctrl->cfg), NULL, ctrl->cfg.verbose);
70   if (tx_bytes < 0)
71     {
72       fprintf (stderr, "CLIENT (fd %d): ERROR: write test cfg failed (%d)!\n",
73                socket->fd, tx_bytes);
74       return tx_bytes;
75     }
76
77   rx_bytes = sock_test_read (socket->fd, (uint8_t *) socket->rxbuf,
78                              sizeof (vcl_test_cfg_t), NULL);
79   if (rx_bytes < 0)
80     return rx_bytes;
81
82   if (rl_cfg->magic != VCL_TEST_CFG_CTRL_MAGIC)
83     {
84       fprintf (stderr, "CLIENT (fd %d): ERROR: Bad server reply cfg "
85                "-- aborting!\n", socket->fd);
86       return -1;
87     }
88   if ((rx_bytes != sizeof (vcl_test_cfg_t))
89       || !vcl_test_cfg_verify (rl_cfg, &ctrl->cfg))
90     {
91       fprintf (stderr, "CLIENT (fd %d): ERROR: Invalid config received "
92                "from server!\n", socket->fd);
93       if (rx_bytes != sizeof (vcl_test_cfg_t))
94         {
95           fprintf (stderr, "\tRx bytes %d != cfg size %lu\n",
96                    rx_bytes, sizeof (vcl_test_cfg_t));
97         }
98       else
99         {
100           vcl_test_cfg_dump (rl_cfg, 1 /* is_client */ );
101           fprintf (stderr, "CLIENT (fd %d): Valid config sent to server.\n",
102                    socket->fd);
103           vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
104         }
105       return -1;
106     }
107   else if (socket->cfg.verbose)
108     {
109       printf ("CLIENT (fd %d): Got config back from server.\n", socket->fd);
110       vcl_test_cfg_dump (rl_cfg, 1 /* is_client */ );
111     }
112   ctrl->cfg.ctrl_handle = ((ctrl->cfg.ctrl_handle == ~0) ?
113                            rl_cfg->ctrl_handle : ctrl->cfg.ctrl_handle);
114
115   return 0;
116 }
117
118 static void
119 echo_test_client ()
120 {
121   sock_client_main_t *scm = &vcl_client_main;
122   vcl_test_session_t *ctrl = &scm->ctrl_socket;
123   vcl_test_session_t *tsock;
124   int rx_bytes, tx_bytes, nbytes;
125   uint32_t i, n;
126   int rv;
127   int nfds = 0;
128   fd_set wr_fdset, rd_fdset;
129   fd_set _wfdset, *wfdset = &_wfdset;
130   fd_set _rfdset, *rfdset = &_rfdset;
131
132   FD_ZERO (&wr_fdset);
133   FD_ZERO (&rd_fdset);
134   memset (&ctrl->stats, 0, sizeof (ctrl->stats));
135   ctrl->cfg.total_bytes = nbytes = strlen (ctrl->txbuf) + 1;
136   for (n = 0; n != ctrl->cfg.num_test_sessions; n++)
137     {
138       tsock = &scm->test_socket[n];
139       tsock->cfg = ctrl->cfg;
140       vcl_test_session_buf_alloc (tsock);
141       if (sock_test_cfg_sync (tsock))
142         return;
143
144       memcpy (tsock->txbuf, ctrl->txbuf, nbytes);
145       memset (&tsock->stats, 0, sizeof (tsock->stats));
146
147       FD_SET (tsock->fd, &wr_fdset);
148       FD_SET (tsock->fd, &rd_fdset);
149       nfds = ((tsock->fd + 1) > nfds) ? (tsock->fd + 1) : nfds;
150     }
151
152   nfds++;
153   clock_gettime (CLOCK_REALTIME, &ctrl->stats.start);
154   while (n)
155     {
156       _wfdset = wr_fdset;
157       _rfdset = rd_fdset;
158
159 #ifdef VCL_TEST
160       rv =
161         vppcom_select (nfds, (unsigned long *) rfdset,
162                        (unsigned long *) wfdset, NULL, 0);
163 #else
164       {
165         struct timeval timeout;
166         timeout.tv_sec = 0;
167         timeout.tv_usec = 0;
168         rv = select (nfds, rfdset, wfdset, NULL, &timeout);
169       }
170 #endif
171       if (rv < 0)
172         {
173           perror ("select()");
174           fprintf (stderr, "\nCLIENT: ERROR: select() failed -- "
175                    "aborting test!\n");
176           return;
177         }
178       else if (rv == 0)
179         continue;
180
181       for (i = 0; i < ctrl->cfg.num_test_sessions; i++)
182         {
183           tsock = &scm->test_socket[i];
184           if (!((tsock->stats.stop.tv_sec == 0) &&
185                 (tsock->stats.stop.tv_nsec == 0)))
186             continue;
187
188           if (FD_ISSET (tsock->fd, wfdset) &&
189               (tsock->stats.tx_bytes < ctrl->cfg.total_bytes))
190
191             {
192               tx_bytes =
193                 sock_test_write (tsock->fd, (uint8_t *) tsock->txbuf, nbytes,
194                                  &tsock->stats, ctrl->cfg.verbose);
195               if (tx_bytes < 0)
196                 {
197                   fprintf (stderr, "\nCLIENT: ERROR: sock_test_write(%d) "
198                            "failed -- aborting test!\n", tsock->fd);
199                   return;
200                 }
201
202               printf ("CLIENT (fd %d): TX (%d bytes) - '%s'\n",
203                       tsock->fd, tx_bytes, tsock->txbuf);
204             }
205
206           if ((FD_ISSET (tsock->fd, rfdset)) &&
207               (tsock->stats.rx_bytes < ctrl->cfg.total_bytes))
208             {
209               rx_bytes =
210                 sock_test_read (tsock->fd, (uint8_t *) tsock->rxbuf,
211                                 nbytes, &tsock->stats);
212               if (rx_bytes > 0)
213                 {
214                   printf ("CLIENT (fd %d): RX (%d bytes)\n", tsock->fd,
215                           rx_bytes);
216
217                   if (tsock->stats.rx_bytes != tsock->stats.tx_bytes)
218                     printf ("CLIENT: WARNING: bytes read (%lu) "
219                             "!= bytes written (%lu)!\n",
220                             tsock->stats.rx_bytes, tsock->stats.tx_bytes);
221                 }
222             }
223
224           if (tsock->stats.rx_bytes >= ctrl->cfg.total_bytes)
225             {
226               clock_gettime (CLOCK_REALTIME, &tsock->stats.stop);
227               n--;
228             }
229         }
230     }
231   clock_gettime (CLOCK_REALTIME, &ctrl->stats.stop);
232
233 #ifndef VCL_TEST
234   {
235     int fd, errno_val;
236     struct sockaddr_un serveraddr;
237     uint8_t buffer[256];
238     size_t nbytes = strlen (SOCK_TEST_MIXED_EPOLL_DATA) + 1;
239     struct timeval timeout;
240
241     /* Open AF_UNIX socket and send an echo to test mixed epoll on server.
242      */
243     fd = socket (AF_UNIX, SOCK_STREAM, 0);
244     if (fd < 0)
245       {
246         errno_val = errno;
247         perror ("ERROR in echo_test_client(): socket(AF_UNIX) failed");
248         fprintf (stderr,
249                  "CLIENT: ERROR: socket(AF_UNIX, SOCK_STREAM, 0) failed "
250                  "(errno = %d)!\n", errno_val);
251         goto out;
252       }
253     memset (&serveraddr, 0, sizeof (serveraddr));
254     serveraddr.sun_family = AF_UNIX;
255     strncpy (serveraddr.sun_path, SOCK_TEST_AF_UNIX_FILENAME,
256              sizeof (serveraddr.sun_path));
257     rv = connect (fd, (struct sockaddr *) &serveraddr, SUN_LEN (&serveraddr));
258     if (rv < 0)
259       {
260         errno_val = errno;
261         perror ("ERROR in echo_test_client(): connect() failed");
262         fprintf (stderr, "CLIENT: ERROR: connect(fd %d, \"%s\", %lu) "
263                  "failed (errno = %d)!\n", fd, SOCK_TEST_AF_UNIX_FILENAME,
264                  SUN_LEN (&serveraddr), errno_val);
265         goto done;
266       }
267
268     scm->af_unix_echo_tx++;
269     strncpy ((char *) buffer, SOCK_TEST_MIXED_EPOLL_DATA, sizeof (buffer));
270     timeout.tv_sec = 0;
271     timeout.tv_usec = 250000;
272     select (0, NULL, NULL, NULL, &timeout);     /* delay .25 secs */
273     rv = write (fd, buffer, nbytes);
274     if (rv < 0)
275       {
276         errno_val = errno;
277         perror ("ERROR in echo_test_client(): write() failed");
278         fprintf (stderr, "CLIENT: ERROR: write(fd %d, \"%s\", %lu) "
279                  "failed (errno = %d)!\n", fd, buffer, nbytes, errno_val);
280         goto done;
281       }
282     else if (rv < nbytes)
283       {
284         fprintf (stderr, "CLIENT: ERROR: write(fd %d, \"%s\", %lu) "
285                  "returned %d!\n", fd, buffer, nbytes, rv);
286         goto done;
287       }
288
289     printf ("CLIENT (AF_UNIX): TX (%d bytes) - '%s'\n", rv, buffer);
290     memset (buffer, 0, sizeof (buffer));
291     rv = read (fd, buffer, nbytes);
292     if (rv < 0)
293       {
294         errno_val = errno;
295         perror ("ERROR in echo_test_client(): read() failed");
296         fprintf (stderr, "CLIENT: ERROR: read(fd %d, %p, %lu) "
297                  "failed (errno = %d)!\n", fd, buffer, nbytes, errno_val);
298         goto done;
299       }
300     else if (rv < nbytes)
301       {
302         fprintf (stderr, "CLIENT: ERROR: read(fd %d, %p, %lu) "
303                  "returned %d!\n", fd, buffer, nbytes, rv);
304         goto done;
305       }
306
307     if (!strncmp (SOCK_TEST_MIXED_EPOLL_DATA, (const char *) buffer, nbytes))
308       {
309         printf ("CLIENT (AF_UNIX): RX (%d bytes) - '%s'\n", rv, buffer);
310         scm->af_unix_echo_rx++;
311       }
312     else
313       printf ("CLIENT (AF_UNIX): ERROR: RX (%d bytes) - '%s'\n", rv, buffer);
314
315   done:
316     close (fd);
317   out:
318     ;
319   }
320 #endif
321
322   for (i = 0; i < ctrl->cfg.num_test_sessions; i++)
323     {
324       tsock = &scm->test_socket[i];
325       tsock->stats.start = ctrl->stats.start;
326
327       if (ctrl->cfg.verbose)
328         {
329           static char buf[64];
330
331           snprintf (buf, sizeof (buf), "CLIENT (fd %d) RESULTS", tsock->fd);
332           vcl_test_stats_dump (buf, &tsock->stats,
333                                1 /* show_rx */ , 1 /* show tx */ ,
334                                ctrl->cfg.verbose);
335         }
336
337       vcl_test_stats_accumulate (&ctrl->stats, &tsock->stats);
338     }
339
340   if (ctrl->cfg.verbose)
341     {
342       vcl_test_stats_dump ("CLIENT RESULTS", &ctrl->stats,
343                            1 /* show_rx */ , 1 /* show tx */ ,
344                            ctrl->cfg.verbose);
345       vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
346
347       if (ctrl->cfg.verbose > 1)
348         {
349           printf ("  ctrl socket info\n"
350                   VCL_TEST_SEPARATOR_STRING
351                   "          fd:  %d (0x%08x)\n"
352                   "       rxbuf:  %p\n"
353                   "  rxbuf size:  %u (0x%08x)\n"
354                   "       txbuf:  %p\n"
355                   "  txbuf size:  %u (0x%08x)\n"
356                   VCL_TEST_SEPARATOR_STRING,
357                   ctrl->fd, (uint32_t) ctrl->fd,
358                   ctrl->rxbuf, ctrl->rxbuf_size, ctrl->rxbuf_size,
359                   ctrl->txbuf, ctrl->txbuf_size, ctrl->txbuf_size);
360         }
361     }
362 }
363
364 static void
365 stream_test_client (vcl_test_t test)
366 {
367   sock_client_main_t *scm = &vcl_client_main;
368   vcl_test_session_t *ctrl = &scm->ctrl_socket;
369   vcl_test_session_t *tsock;
370   int tx_bytes;
371   uint32_t i, n;
372   int rv;
373   int nfds = 0;
374   fd_set wr_fdset, rd_fdset;
375   fd_set _wfdset, *wfdset = &_wfdset;
376   fd_set _rfdset, *rfdset = (test == VCL_TEST_TYPE_BI) ? &_rfdset : 0;
377
378   ctrl->cfg.total_bytes = ctrl->cfg.num_writes * ctrl->cfg.txbuf_size;
379   ctrl->cfg.ctrl_handle = ~0;
380
381   printf ("\n" SOCK_TEST_BANNER_STRING
382           "CLIENT (fd %d): %s-directional Stream Test!\n\n"
383           "CLIENT (fd %d): Sending config to server on ctrl socket...\n",
384           ctrl->fd, test == VCL_TEST_TYPE_BI ? "Bi" : "Uni", ctrl->fd);
385
386   if (sock_test_cfg_sync (ctrl))
387     {
388       fprintf (stderr, "CLIENT: ERROR: test cfg sync failed -- aborting!");
389       return;
390     }
391
392   FD_ZERO (&wr_fdset);
393   FD_ZERO (&rd_fdset);
394   memset (&ctrl->stats, 0, sizeof (ctrl->stats));
395   for (n = 0; n != ctrl->cfg.num_test_sessions; n++)
396     {
397       tsock = &scm->test_socket[n];
398       tsock->cfg = ctrl->cfg;
399       vcl_test_session_buf_alloc (tsock);
400       printf ("CLIENT (fd %d): Sending config to server on "
401               "test socket %d...\n", tsock->fd, n);
402       sock_test_cfg_sync (tsock);
403
404       /* Fill payload with incrementing uint32's */
405       for (i = 0; i < tsock->txbuf_size; i++)
406         tsock->txbuf[i] = i & 0xff;
407
408       memset (&tsock->stats, 0, sizeof (tsock->stats));
409       FD_SET (tsock->fd, &wr_fdset);
410       FD_SET (tsock->fd, &rd_fdset);
411       nfds = ((tsock->fd + 1) > nfds) ? (tsock->fd + 1) : nfds;
412     }
413
414   nfds++;
415   clock_gettime (CLOCK_REALTIME, &ctrl->stats.start);
416   while (n)
417     {
418       _wfdset = wr_fdset;
419       _rfdset = rd_fdset;
420
421 #ifdef VCL_TEST
422       rv =
423         vppcom_select (nfds, (unsigned long *) rfdset,
424                        (unsigned long *) wfdset, NULL, 0);
425 #else
426       {
427         struct timeval timeout;
428         timeout.tv_sec = 0;
429         timeout.tv_usec = 0;
430         rv = select (nfds, rfdset, wfdset, NULL, &timeout);
431       }
432 #endif
433       if (rv < 0)
434         {
435           perror ("select()");
436           fprintf (stderr, "\nCLIENT: ERROR: select() failed -- "
437                    "aborting test!\n");
438           return;
439         }
440       else if (rv == 0)
441         continue;
442
443       for (i = 0; i < ctrl->cfg.num_test_sessions; i++)
444         {
445           tsock = &scm->test_socket[i];
446           if (!((tsock->stats.stop.tv_sec == 0) &&
447                 (tsock->stats.stop.tv_nsec == 0)))
448             continue;
449
450           if ((test == VCL_TEST_TYPE_BI) &&
451               FD_ISSET (tsock->fd, rfdset) &&
452               (tsock->stats.rx_bytes < ctrl->cfg.total_bytes))
453             {
454               (void) sock_test_read (tsock->fd,
455                                      (uint8_t *) tsock->rxbuf,
456                                      tsock->rxbuf_size, &tsock->stats);
457             }
458
459           if (FD_ISSET (tsock->fd, wfdset) &&
460               (tsock->stats.tx_bytes < ctrl->cfg.total_bytes))
461             {
462               tx_bytes = sock_test_write (tsock->fd, (uint8_t *) tsock->txbuf,
463                                           ctrl->cfg.txbuf_size, &tsock->stats,
464                                           ctrl->cfg.verbose);
465               if (tx_bytes < 0)
466                 {
467                   fprintf (stderr, "\nCLIENT: ERROR: sock_test_write(%d) "
468                            "failed -- aborting test!\n", tsock->fd);
469                   return;
470                 }
471             }
472
473           if (((test == VCL_TEST_TYPE_UNI) &&
474                (tsock->stats.tx_bytes >= ctrl->cfg.total_bytes)) ||
475               ((test == VCL_TEST_TYPE_BI) &&
476                (tsock->stats.rx_bytes >= ctrl->cfg.total_bytes)))
477             {
478               clock_gettime (CLOCK_REALTIME, &tsock->stats.stop);
479               n--;
480             }
481         }
482     }
483   clock_gettime (CLOCK_REALTIME, &ctrl->stats.stop);
484
485   printf ("CLIENT (fd %d): Sending config to server on ctrl socket...\n",
486           ctrl->fd);
487
488   if (sock_test_cfg_sync (ctrl))
489     {
490       fprintf (stderr, "CLIENT: ERROR: test cfg sync failed -- aborting!");
491       return;
492     }
493
494   for (i = 0; i < ctrl->cfg.num_test_sessions; i++)
495     {
496       tsock = &scm->test_socket[i];
497
498       if (ctrl->cfg.verbose)
499         {
500           static char buf[64];
501
502           snprintf (buf, sizeof (buf), "CLIENT (fd %d) RESULTS", tsock->fd);
503           vcl_test_stats_dump (buf, &tsock->stats,
504                                test == VCL_TEST_TYPE_BI /* show_rx */ ,
505                                1 /* show tx */ , ctrl->cfg.verbose);
506         }
507
508       vcl_test_stats_accumulate (&ctrl->stats, &tsock->stats);
509     }
510
511   vcl_test_stats_dump ("CLIENT RESULTS", &ctrl->stats,
512                        test == VCL_TEST_TYPE_BI /* show_rx */ ,
513                        1 /* show tx */ , ctrl->cfg.verbose);
514   vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
515
516   if (ctrl->cfg.verbose)
517     {
518       printf ("  ctrl socket info\n"
519               VCL_TEST_SEPARATOR_STRING
520               "          fd:  %d (0x%08x)\n"
521               "       rxbuf:  %p\n"
522               "  rxbuf size:  %u (0x%08x)\n"
523               "       txbuf:  %p\n"
524               "  txbuf size:  %u (0x%08x)\n"
525               VCL_TEST_SEPARATOR_STRING,
526               ctrl->fd, (uint32_t) ctrl->fd,
527               ctrl->rxbuf, ctrl->rxbuf_size, ctrl->rxbuf_size,
528               ctrl->txbuf, ctrl->txbuf_size, ctrl->txbuf_size);
529     }
530
531   ctrl->cfg.test = VCL_TEST_TYPE_ECHO;
532   if (sock_test_cfg_sync (ctrl))
533     fprintf (stderr, "CLIENT: ERROR: post-test cfg sync failed!");
534
535   printf ("CLIENT (fd %d): %s-directional Stream Test Complete!\n"
536           SOCK_TEST_BANNER_STRING "\n", ctrl->fd,
537           test == VCL_TEST_TYPE_BI ? "Bi" : "Uni");
538 }
539
540 static void
541 exit_client (void)
542 {
543   sock_client_main_t *scm = &vcl_client_main;
544   vcl_test_session_t *ctrl = &scm->ctrl_socket;
545   vcl_test_session_t *tsock;
546   int i;
547
548 #ifndef VCL_TEST
549   printf ("CLIENT: af_unix_echo_tx %d, af_unix_echo_rx %d\n",
550           scm->af_unix_echo_tx, scm->af_unix_echo_rx);
551 #endif
552   for (i = 0; i < ctrl->cfg.num_test_sessions; i++)
553     {
554       tsock = &scm->test_socket[i];
555       tsock->cfg.test = VCL_TEST_TYPE_EXIT;
556
557       /* coverity[COPY_PASTE_ERROR] */
558       if (ctrl->cfg.verbose)
559         {
560           printf ("\nCLIENT (fd %d): Sending exit cfg to server...\n",
561                   tsock->fd);
562           vcl_test_cfg_dump (&tsock->cfg, 1 /* is_client */ );
563         }
564       (void) sock_test_write (tsock->fd, (uint8_t *) & tsock->cfg,
565                               sizeof (tsock->cfg), &tsock->stats,
566                               ctrl->cfg.verbose);
567     }
568
569   ctrl->cfg.test = VCL_TEST_TYPE_EXIT;
570   if (ctrl->cfg.verbose)
571     {
572       printf ("\nCLIENT (fd %d): Sending exit cfg to server...\n", ctrl->fd);
573       vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
574     }
575   (void) sock_test_write (ctrl->fd, (uint8_t *) & ctrl->cfg,
576                           sizeof (ctrl->cfg), &ctrl->stats,
577                           ctrl->cfg.verbose);
578   printf ("\nCLIENT: So long and thanks for all the fish!\n\n");
579   sleep (1);
580 }
581
582 static int
583 sock_test_connect_test_sockets (uint32_t num_test_sockets)
584 {
585   sock_client_main_t *scm = &vcl_client_main;
586   vcl_test_session_t *ctrl = &scm->ctrl_socket;
587   vcl_test_session_t *tsock;
588   int i, rv, errno_val;
589
590   if (num_test_sockets < 1)
591     {
592       errno = EINVAL;
593       return -1;
594     }
595
596   if (num_test_sockets < scm->num_test_sockets)
597     {
598       for (i = scm->num_test_sockets - 1; i >= num_test_sockets; i--)
599         {
600           tsock = &scm->test_socket[i];
601 #ifdef VCL_TEST
602           vppcom_session_close (tsock->fd);
603 #else
604           close (tsock->fd);
605 #endif
606           free (tsock->txbuf);
607           free (tsock->rxbuf);
608         }
609     }
610
611   else if (num_test_sockets > scm->num_test_sockets)
612     {
613       tsock = realloc (scm->test_socket,
614                        sizeof (vcl_test_session_t) * num_test_sockets);
615       if (!tsock)
616         {
617           errno_val = errno;
618           perror ("ERROR in sock_test_connect_test_sockets()");
619           fprintf (stderr, "CLIENT: ERROR: socket failed (errno = %d)!\n",
620                    errno_val);
621           return -1;
622         }
623
624       memset (&tsock[scm->num_test_sockets], 0,
625               sizeof (vcl_test_session_t) * (num_test_sockets -
626                                              scm->num_test_sockets));
627
628       scm->test_socket = tsock;
629       for (i = scm->num_test_sockets; i < num_test_sockets; i++)
630         {
631           tsock = &scm->test_socket[i];
632 #ifdef VCL_TEST
633           tsock->fd = vppcom_session_create (ctrl->cfg.transport_udp ?
634                                              VPPCOM_PROTO_UDP :
635                                              VPPCOM_PROTO_TCP,
636                                              1 /* is_nonblocking */ );
637           if (tsock->fd < 0)
638             {
639               errno = -tsock->fd;
640               tsock->fd = -1;
641             }
642 #else
643           tsock->fd = socket (ctrl->cfg.address_ip6 ? AF_INET6 : AF_INET,
644                               ctrl->cfg.transport_udp ?
645                               SOCK_DGRAM : SOCK_STREAM, 0);
646 #endif
647           if (tsock->fd < 0)
648             {
649               errno_val = errno;
650               perror ("ERROR in sock_test_connect_test_sockets()");
651               fprintf (stderr, "CLIENT: ERROR: socket failed (errno = %d)!\n",
652                        errno_val);
653               return tsock->fd;
654             }
655
656 #ifdef VCL_TEST
657           rv = vppcom_session_connect (tsock->fd, &scm->server_endpt);
658           if (rv)
659             {
660               errno = -rv;
661               rv = -1;
662             }
663 #else
664           rv = connect (tsock->fd, (struct sockaddr *) &scm->server_addr,
665                         scm->server_addr_size);
666 #endif
667           if (rv < 0)
668             {
669               errno_val = errno;
670               perror ("ERROR in sock_test_connect_test_sockets()");
671               fprintf (stderr, "CLIENT: ERROR: connect failed "
672                        "(errno = %d)!\n", errno_val);
673               return -1;
674             }
675           if (fcntl (tsock->fd, F_SETFL, O_NONBLOCK) < 0)
676             {
677               errno_val = errno;
678               perror ("ERROR in sock_test_connect_test_sockets()");
679               fprintf (stderr, "CLIENT: ERROR: fcntl failed (errno = %d)!\n",
680                        errno_val);
681               return -1;
682             }
683           tsock->cfg = ctrl->cfg;
684           vcl_test_session_buf_alloc (tsock);
685           sock_test_cfg_sync (tsock);
686
687           printf ("CLIENT (fd %d): Test socket %d connected.\n",
688                   tsock->fd, i);
689         }
690     }
691
692   scm->num_test_sockets = num_test_sockets;
693   printf ("CLIENT: All sockets (%d) connected!\n", scm->num_test_sockets + 1);
694   return 0;
695 }
696
697 static void
698 dump_help (void)
699 {
700 #define INDENT "\n  "
701
702   printf ("CLIENT: Test configuration commands:"
703           INDENT VCL_TEST_TOKEN_HELP
704           "\t\t\tDisplay help."
705           INDENT VCL_TEST_TOKEN_EXIT
706           "\t\t\tExit test client & server."
707           INDENT VCL_TEST_TOKEN_SHOW_CFG
708           "\t\t\tShow the current test cfg."
709           INDENT VCL_TEST_TOKEN_RUN_UNI
710           "\t\t\tRun the Uni-directional test."
711           INDENT VCL_TEST_TOKEN_RUN_BI
712           "\t\t\tRun the Bi-directional test."
713           INDENT VCL_TEST_TOKEN_VERBOSE
714           "\t\t\tToggle verbose setting."
715           INDENT VCL_TEST_TOKEN_RXBUF_SIZE
716           "<rxbuf size>\tRx buffer size (bytes)."
717           INDENT VCL_TEST_TOKEN_TXBUF_SIZE
718           "<txbuf size>\tTx buffer size (bytes)."
719           INDENT VCL_TEST_TOKEN_NUM_WRITES
720           "<# of writes>\tNumber of txbuf writes to server." "\n");
721 }
722
723 static void
724 cfg_txbuf_size_set (void)
725 {
726   sock_client_main_t *scm = &vcl_client_main;
727   vcl_test_session_t *ctrl = &scm->ctrl_socket;
728   char *p = ctrl->txbuf + strlen (VCL_TEST_TOKEN_TXBUF_SIZE);
729   uint64_t txbuf_size = strtoull ((const char *) p, NULL, 10);
730
731   if (txbuf_size >= VCL_TEST_CFG_BUF_SIZE_MIN)
732     {
733       ctrl->cfg.txbuf_size = txbuf_size;
734       ctrl->cfg.total_bytes = ctrl->cfg.num_writes * ctrl->cfg.txbuf_size;
735       vcl_test_buf_alloc (&ctrl->cfg, 0 /* is_rxbuf */ ,
736                           (uint8_t **) & ctrl->txbuf, &ctrl->txbuf_size);
737       vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
738     }
739   else
740     fprintf (stderr, "CLIENT: ERROR: Invalid txbuf size (%lu) < "
741              "minimum buf size (%u)!\n",
742              txbuf_size, VCL_TEST_CFG_BUF_SIZE_MIN);
743 }
744
745 static void
746 cfg_num_writes_set (void)
747 {
748   sock_client_main_t *scm = &vcl_client_main;
749   vcl_test_session_t *ctrl = &scm->ctrl_socket;
750   char *p = ctrl->txbuf + strlen (VCL_TEST_TOKEN_NUM_WRITES);
751   uint32_t num_writes = strtoul ((const char *) p, NULL, 10);
752
753   if (num_writes > 0)
754     {
755       ctrl->cfg.num_writes = num_writes;
756       ctrl->cfg.total_bytes = ctrl->cfg.num_writes * ctrl->cfg.txbuf_size;
757       vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
758     }
759   else
760     {
761       fprintf (stderr, "CLIENT: ERROR: invalid num writes: %u\n", num_writes);
762     }
763 }
764
765 static void
766 cfg_num_test_sockets_set (void)
767 {
768   sock_client_main_t *scm = &vcl_client_main;
769   vcl_test_session_t *ctrl = &scm->ctrl_socket;
770   char *p = ctrl->txbuf + strlen (VCL_TEST_TOKEN_NUM_TEST_SESS);
771   uint32_t num_test_sockets = strtoul ((const char *) p, NULL, 10);
772
773   if ((num_test_sockets > 0) &&
774       (num_test_sockets <= VCL_TEST_CFG_MAX_TEST_SESS))
775     {
776       ctrl->cfg.num_test_sessions = num_test_sockets;
777       sock_test_connect_test_sockets (num_test_sockets);
778
779       vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
780     }
781   else
782     {
783       fprintf (stderr, "CLIENT: ERROR: invalid num test sockets: "
784                "%u, (%d max)\n",
785                num_test_sockets, VCL_TEST_CFG_MAX_TEST_SESS);
786     }
787 }
788
789 static void
790 cfg_rxbuf_size_set (void)
791 {
792   sock_client_main_t *scm = &vcl_client_main;
793   vcl_test_session_t *ctrl = &scm->ctrl_socket;
794   char *p = ctrl->txbuf + strlen (VCL_TEST_TOKEN_RXBUF_SIZE);
795   uint64_t rxbuf_size = strtoull ((const char *) p, NULL, 10);
796
797   if (rxbuf_size >= VCL_TEST_CFG_BUF_SIZE_MIN)
798     {
799       ctrl->cfg.rxbuf_size = rxbuf_size;
800       vcl_test_buf_alloc (&ctrl->cfg, 1 /* is_rxbuf */ ,
801                           (uint8_t **) & ctrl->rxbuf, &ctrl->rxbuf_size);
802       vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
803     }
804   else
805     fprintf (stderr, "CLIENT: ERROR: Invalid rxbuf size (%lu) < "
806              "minimum buf size (%u)!\n",
807              rxbuf_size, VCL_TEST_CFG_BUF_SIZE_MIN);
808 }
809
810 static void
811 cfg_verbose_toggle (void)
812 {
813   sock_client_main_t *scm = &vcl_client_main;
814   vcl_test_session_t *ctrl = &scm->ctrl_socket;
815
816   ctrl->cfg.verbose = ctrl->cfg.verbose ? 0 : 1;
817   vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
818
819 }
820
821 static vcl_test_t
822 parse_input ()
823 {
824   sock_client_main_t *scm = &vcl_client_main;
825   vcl_test_session_t *ctrl = &scm->ctrl_socket;
826   vcl_test_t rv = VCL_TEST_TYPE_NONE;
827
828   if (!strncmp (VCL_TEST_TOKEN_EXIT, ctrl->txbuf,
829                 strlen (VCL_TEST_TOKEN_EXIT)))
830     rv = VCL_TEST_TYPE_EXIT;
831
832   else if (!strncmp (VCL_TEST_TOKEN_HELP, ctrl->txbuf,
833                      strlen (VCL_TEST_TOKEN_HELP)))
834     dump_help ();
835
836   else if (!strncmp (VCL_TEST_TOKEN_SHOW_CFG, ctrl->txbuf,
837                      strlen (VCL_TEST_TOKEN_SHOW_CFG)))
838     scm->dump_cfg = 1;
839
840   else if (!strncmp (VCL_TEST_TOKEN_VERBOSE, ctrl->txbuf,
841                      strlen (VCL_TEST_TOKEN_VERBOSE)))
842     cfg_verbose_toggle ();
843
844   else if (!strncmp (VCL_TEST_TOKEN_TXBUF_SIZE, ctrl->txbuf,
845                      strlen (VCL_TEST_TOKEN_TXBUF_SIZE)))
846     cfg_txbuf_size_set ();
847
848   else if (!strncmp (VCL_TEST_TOKEN_NUM_TEST_SESS, ctrl->txbuf,
849                      strlen (VCL_TEST_TOKEN_NUM_TEST_SESS)))
850     cfg_num_test_sockets_set ();
851
852   else if (!strncmp (VCL_TEST_TOKEN_NUM_WRITES, ctrl->txbuf,
853                      strlen (VCL_TEST_TOKEN_NUM_WRITES)))
854     cfg_num_writes_set ();
855
856   else if (!strncmp (VCL_TEST_TOKEN_RXBUF_SIZE, ctrl->txbuf,
857                      strlen (VCL_TEST_TOKEN_RXBUF_SIZE)))
858     cfg_rxbuf_size_set ();
859
860   else if (!strncmp (VCL_TEST_TOKEN_RUN_UNI, ctrl->txbuf,
861                      strlen (VCL_TEST_TOKEN_RUN_UNI)))
862     rv = ctrl->cfg.test = VCL_TEST_TYPE_UNI;
863
864   else if (!strncmp (VCL_TEST_TOKEN_RUN_BI, ctrl->txbuf,
865                      strlen (VCL_TEST_TOKEN_RUN_BI)))
866     rv = ctrl->cfg.test = VCL_TEST_TYPE_BI;
867
868   else
869     rv = VCL_TEST_TYPE_ECHO;
870
871   return rv;
872 }
873
874 void
875 print_usage_and_exit (void)
876 {
877   fprintf (stderr,
878            "sock_test_client [OPTIONS] <ipaddr> <port>\n"
879            "  OPTIONS\n"
880            "  -h               Print this message and exit.\n"
881            "  -6               Use IPv6\n"
882            "  -u               Use UDP transport layer\n"
883            "  -c               Print test config before test.\n"
884            "  -w <dir>         Write test results to <dir>.\n"
885            "  -X               Exit after running test.\n"
886            "  -E               Run Echo test.\n"
887            "  -N <num-writes>  Test Cfg: number of writes.\n"
888            "  -R <rxbuf-size>  Test Cfg: rx buffer size.\n"
889            "  -T <txbuf-size>  Test Cfg: tx buffer size.\n"
890            "  -U               Run Uni-directional test.\n"
891            "  -B               Run Bi-directional test.\n"
892            "  -V               Verbose mode.\n");
893   exit (1);
894 }
895
896 int
897 main (int argc, char **argv)
898 {
899   sock_client_main_t *scm = &vcl_client_main;
900   vcl_test_session_t *ctrl = &scm->ctrl_socket;
901   int c, rv, errno_val;
902   vcl_test_t post_test = VCL_TEST_TYPE_NONE;
903
904   vcl_test_cfg_init (&ctrl->cfg);
905   vcl_test_session_buf_alloc (ctrl);
906
907   opterr = 0;
908   while ((c = getopt (argc, argv, "chn:w:XE:I:N:R:T:UBV6D")) != -1)
909     switch (c)
910       {
911       case 'c':
912         scm->dump_cfg = 1;
913         break;
914
915       case 's':
916         if (sscanf (optarg, "0x%x", &ctrl->cfg.num_test_sessions) != 1)
917           if (sscanf (optarg, "%u", &ctrl->cfg.num_test_sessions) != 1)
918             {
919               fprintf (stderr, "CLIENT: ERROR: Invalid value for "
920                        "option -%c!\n", c);
921               print_usage_and_exit ();
922             }
923         if (!ctrl->cfg.num_test_sessions ||
924             (ctrl->cfg.num_test_sessions > FD_SETSIZE))
925           {
926             fprintf (stderr, "CLIENT: ERROR: Invalid number of "
927                      "sockets (%d) specified for option -%c!\n"
928                      "       Valid range is 1 - %d\n",
929                      ctrl->cfg.num_test_sessions, c, FD_SETSIZE);
930             print_usage_and_exit ();
931           }
932         break;
933
934       case 'w':
935         fprintf (stderr, "CLIENT: Writing test results to files is TBD.\n");
936         break;
937
938       case 'X':
939         post_test = VCL_TEST_TYPE_EXIT;
940         break;
941
942       case 'E':
943         if (strlen (optarg) > ctrl->txbuf_size)
944           {
945             fprintf (stderr, "CLIENT: ERROR: Option -%c value "
946                      "larger than txbuf size (%d)!\n",
947                      optopt, ctrl->txbuf_size);
948             print_usage_and_exit ();
949           }
950         strncpy (ctrl->txbuf, optarg, ctrl->txbuf_size);
951         ctrl->cfg.test = VCL_TEST_TYPE_ECHO;
952         break;
953
954       case 'I':
955         if (sscanf (optarg, "0x%x", &ctrl->cfg.num_test_sessions) != 1)
956           if (sscanf (optarg, "%d", &ctrl->cfg.num_test_sessions) != 1)
957             {
958               fprintf (stderr, "CLIENT: ERROR: Invalid value for "
959                        "option -%c!\n", c);
960               print_usage_and_exit ();
961             }
962         if (ctrl->cfg.num_test_sessions > VCL_TEST_CFG_MAX_TEST_SESS)
963           {
964             fprintf (stderr, "CLIENT: ERROR: value greater than max "
965                      "number test sockets (%d)!", VCL_TEST_CFG_MAX_TEST_SESS);
966             print_usage_and_exit ();
967           }
968         break;
969
970       case 'N':
971         if (sscanf (optarg, "0x%lx", &ctrl->cfg.num_writes) != 1)
972           if (sscanf (optarg, "%ld", &ctrl->cfg.num_writes) != 1)
973             {
974               fprintf (stderr, "CLIENT: ERROR: Invalid value for "
975                        "option -%c!\n", c);
976               print_usage_and_exit ();
977             }
978         ctrl->cfg.total_bytes = ctrl->cfg.num_writes * ctrl->cfg.txbuf_size;
979         break;
980
981       case 'R':
982         if (sscanf (optarg, "0x%lx", &ctrl->cfg.rxbuf_size) != 1)
983           if (sscanf (optarg, "%ld", &ctrl->cfg.rxbuf_size) != 1)
984             {
985               fprintf (stderr, "CLIENT: ERROR: Invalid value for "
986                        "option -%c!\n", c);
987               print_usage_and_exit ();
988             }
989         if (ctrl->cfg.rxbuf_size >= VCL_TEST_CFG_BUF_SIZE_MIN)
990           {
991             ctrl->rxbuf_size = ctrl->cfg.rxbuf_size;
992             vcl_test_buf_alloc (&ctrl->cfg, 1 /* is_rxbuf */ ,
993                                 (uint8_t **) & ctrl->rxbuf,
994                                 &ctrl->rxbuf_size);
995           }
996         else
997           {
998             fprintf (stderr, "CLIENT: ERROR: rxbuf size (%lu) "
999                      "less than minumum (%u)\n",
1000                      ctrl->cfg.rxbuf_size, VCL_TEST_CFG_BUF_SIZE_MIN);
1001             print_usage_and_exit ();
1002           }
1003
1004         break;
1005
1006       case 'T':
1007         if (sscanf (optarg, "0x%lx", &ctrl->cfg.txbuf_size) != 1)
1008           if (sscanf (optarg, "%ld", &ctrl->cfg.txbuf_size) != 1)
1009             {
1010               fprintf (stderr, "CLIENT: ERROR: Invalid value "
1011                        "for option -%c!\n", c);
1012               print_usage_and_exit ();
1013             }
1014         if (ctrl->cfg.txbuf_size >= VCL_TEST_CFG_BUF_SIZE_MIN)
1015           {
1016             ctrl->txbuf_size = ctrl->cfg.txbuf_size;
1017             vcl_test_buf_alloc (&ctrl->cfg, 0 /* is_rxbuf */ ,
1018                                 (uint8_t **) & ctrl->txbuf,
1019                                 &ctrl->txbuf_size);
1020             ctrl->cfg.total_bytes =
1021               ctrl->cfg.num_writes * ctrl->cfg.txbuf_size;
1022           }
1023         else
1024           {
1025             fprintf (stderr, "CLIENT: ERROR: txbuf size (%lu) "
1026                      "less than minumum (%u)!\n",
1027                      ctrl->cfg.txbuf_size, VCL_TEST_CFG_BUF_SIZE_MIN);
1028             print_usage_and_exit ();
1029           }
1030         break;
1031
1032       case 'U':
1033         ctrl->cfg.test = VCL_TEST_TYPE_UNI;
1034         break;
1035
1036       case 'B':
1037         ctrl->cfg.test = VCL_TEST_TYPE_BI;
1038         break;
1039
1040       case 'V':
1041         ctrl->cfg.verbose = 1;
1042         break;
1043
1044       case '6':
1045         ctrl->cfg.address_ip6 = 1;
1046         break;
1047
1048       case 'D':
1049         ctrl->cfg.transport_udp = 1;
1050         break;
1051
1052       case '?':
1053         switch (optopt)
1054           {
1055           case 'E':
1056           case 'I':
1057           case 'N':
1058           case 'R':
1059           case 'T':
1060           case 'w':
1061             fprintf (stderr, "CLIENT: ERROR: Option -%c "
1062                      "requires an argument.\n", optopt);
1063             break;
1064
1065           default:
1066             if (isprint (optopt))
1067               fprintf (stderr, "CLIENT: ERROR: Unknown "
1068                        "option `-%c'.\n", optopt);
1069             else
1070               fprintf (stderr, "CLIENT: ERROR: Unknown "
1071                        "option character `\\x%x'.\n", optopt);
1072           }
1073         /* fall thru */
1074       case 'h':
1075       default:
1076         print_usage_and_exit ();
1077       }
1078
1079   if (argc < (optind + 2))
1080     {
1081       fprintf (stderr, "CLIENT: ERROR: Insufficient number of arguments!\n");
1082       print_usage_and_exit ();
1083     }
1084
1085 #ifdef VCL_TEST
1086   ctrl->fd = vppcom_app_create ("vcl_test_client");
1087   if (ctrl->fd < 0)
1088     {
1089       errno = -ctrl->fd;
1090       ctrl->fd = -1;
1091     }
1092   else
1093     {
1094       ctrl->fd = vppcom_session_create (ctrl->cfg.transport_udp ?
1095                                         VPPCOM_PROTO_UDP :
1096                                         VPPCOM_PROTO_TCP,
1097                                         0 /* is_nonblocking */ );
1098       if (ctrl->fd < 0)
1099         {
1100           errno = -ctrl->fd;
1101           ctrl->fd = -1;
1102         }
1103     }
1104 #else
1105   ctrl->fd = socket (ctrl->cfg.address_ip6 ? AF_INET6 : AF_INET,
1106                      ctrl->cfg.transport_udp ? SOCK_DGRAM : SOCK_STREAM, 0);
1107 #endif
1108
1109   if (ctrl->fd < 0)
1110     {
1111       errno_val = errno;
1112       perror ("ERROR in main()");
1113       fprintf (stderr, "CLIENT: ERROR: socket "
1114                "failed (errno = %d)!\n", errno_val);
1115       return ctrl->fd;
1116     }
1117
1118   memset (&scm->server_addr, 0, sizeof (scm->server_addr));
1119   if (ctrl->cfg.address_ip6)
1120     {
1121       struct sockaddr_in6 *server_addr =
1122         (struct sockaddr_in6 *) &scm->server_addr;
1123       scm->server_addr_size = sizeof (*server_addr);
1124       server_addr->sin6_family = AF_INET6;
1125       inet_pton (AF_INET6, argv[optind++], &(server_addr->sin6_addr));
1126       server_addr->sin6_port = htons (atoi (argv[optind]));
1127     }
1128   else
1129     {
1130       struct sockaddr_in *server_addr =
1131         (struct sockaddr_in *) &scm->server_addr;
1132       scm->server_addr_size = sizeof (*server_addr);
1133       server_addr->sin_family = AF_INET;
1134       inet_pton (AF_INET, argv[optind++], &(server_addr->sin_addr));
1135       server_addr->sin_port = htons (atoi (argv[optind]));
1136     }
1137
1138 #ifdef VCL_TEST
1139   if (ctrl->cfg.address_ip6)
1140     {
1141       struct sockaddr_in6 *server_addr =
1142         (struct sockaddr_in6 *) &scm->server_addr;
1143       scm->server_endpt.is_ip4 = 0;
1144       scm->server_endpt.ip = (uint8_t *) & server_addr->sin6_addr;
1145       scm->server_endpt.port = (uint16_t) server_addr->sin6_port;
1146     }
1147   else
1148     {
1149       struct sockaddr_in *server_addr =
1150         (struct sockaddr_in *) &scm->server_addr;
1151       scm->server_endpt.is_ip4 = 1;
1152       scm->server_endpt.ip = (uint8_t *) & server_addr->sin_addr;
1153       scm->server_endpt.port = (uint16_t) server_addr->sin_port;
1154     }
1155 #endif
1156
1157   do
1158     {
1159       printf ("\nCLIENT: Connecting to server...\n");
1160
1161 #ifdef VCL_TEST
1162       rv = vppcom_session_connect (ctrl->fd, &scm->server_endpt);
1163       if (rv)
1164         {
1165           errno = -rv;
1166           rv = -1;
1167         }
1168 #else
1169       rv =
1170         connect (ctrl->fd, (struct sockaddr *) &scm->server_addr,
1171                  scm->server_addr_size);
1172 #endif
1173       if (rv < 0)
1174         {
1175           errno_val = errno;
1176           perror ("ERROR in main()");
1177           fprintf (stderr, "CLIENT: ERROR: connect failed (errno = %d)!\n",
1178                    errno_val);
1179           return -1;
1180         }
1181
1182       sock_test_cfg_sync (ctrl);
1183       printf ("CLIENT (fd %d): Control socket connected.\n", ctrl->fd);
1184     }
1185   while (rv < 0);
1186
1187   sock_test_connect_test_sockets (ctrl->cfg.num_test_sessions);
1188
1189   while (ctrl->cfg.test != VCL_TEST_TYPE_EXIT)
1190     {
1191       if (scm->dump_cfg)
1192         {
1193           vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
1194           scm->dump_cfg = 0;
1195         }
1196
1197       switch (ctrl->cfg.test)
1198         {
1199         case VCL_TEST_TYPE_ECHO:
1200           echo_test_client ();
1201           break;
1202
1203         case VCL_TEST_TYPE_UNI:
1204         case VCL_TEST_TYPE_BI:
1205           stream_test_client (ctrl->cfg.test);
1206           break;
1207
1208         case VCL_TEST_TYPE_EXIT:
1209           continue;
1210
1211         case VCL_TEST_TYPE_NONE:
1212         default:
1213           break;
1214         }
1215       switch (post_test)
1216         {
1217         case VCL_TEST_TYPE_EXIT:
1218           switch (ctrl->cfg.test)
1219             {
1220             case VCL_TEST_TYPE_EXIT:
1221             case VCL_TEST_TYPE_UNI:
1222             case VCL_TEST_TYPE_BI:
1223             case VCL_TEST_TYPE_ECHO:
1224               ctrl->cfg.test = VCL_TEST_TYPE_EXIT;
1225               continue;
1226
1227             case VCL_TEST_TYPE_NONE:
1228             default:
1229               break;
1230             }
1231           break;
1232
1233         case VCL_TEST_TYPE_NONE:
1234         case VCL_TEST_TYPE_ECHO:
1235         case VCL_TEST_TYPE_UNI:
1236         case VCL_TEST_TYPE_BI:
1237         default:
1238           break;
1239         }
1240
1241       memset (ctrl->txbuf, 0, ctrl->txbuf_size);
1242       memset (ctrl->rxbuf, 0, ctrl->rxbuf_size);
1243
1244       printf ("\nCLIENT: Type some characters and hit <return>\n"
1245               "('" VCL_TEST_TOKEN_HELP "' for help): ");
1246
1247       if (fgets (ctrl->txbuf, ctrl->txbuf_size, stdin) != NULL)
1248         {
1249           if (strlen (ctrl->txbuf) == 1)
1250             {
1251               printf ("\nCLIENT: Nothing to send!  Please try again...\n");
1252               continue;
1253             }
1254           ctrl->txbuf[strlen (ctrl->txbuf) - 1] = 0;    // chomp the newline.
1255
1256           /* Parse input for keywords */
1257           ctrl->cfg.test = parse_input ();
1258         }
1259     }
1260
1261   exit_client ();
1262 #ifdef VCL_TEST
1263   vppcom_session_close (ctrl->fd);
1264   vppcom_app_destroy ();
1265   return 0;
1266 #else
1267   close (ctrl->fd);
1268   return (scm->af_unix_echo_tx == scm->af_unix_echo_rx) ? 0 : -1;
1269 #endif
1270 }
1271
1272 /*
1273  * fd.io coding-style-patch-verification: ON
1274  *
1275  * Local Variables:
1276  * eval: (c-set-style "gnu")
1277  * End:
1278  */