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