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