13227f282652447ca62c15693930bdeb0ba19089
[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           sprintf (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           sprintf (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           if (fcntl (tsock->fd, F_SETFL, O_NONBLOCK) < 0)
655             {
656               errno_val = errno;
657               perror ("ERROR in sock_test_connect_test_sockets()");
658               fprintf (stderr, "CLIENT: ERROR: fcntl failed (errno = %d)!\n",
659                        errno_val);
660               return -1;
661             }
662
663 #ifdef VCL_TEST
664           rv = vppcom_session_connect (tsock->fd, &scm->server_endpt);
665           if (rv)
666             {
667               errno = -rv;
668               rv = -1;
669             }
670 #else
671           rv =
672             connect (tsock->fd, (struct sockaddr *) &scm->server_addr,
673                      scm->server_addr_size);
674 #endif
675           if (rv < 0)
676             {
677               errno_val = errno;
678               perror ("ERROR in sock_test_connect_test_sockets()");
679               fprintf (stderr, "CLIENT: ERROR: connect failed "
680                        "(errno = %d)!\n", 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         strcpy (ctrl->txbuf, optarg);
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  */