bf467981815f1b2ec4b57ca76ca2a37684b77a37
[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           fcntl (tsock->fd, F_SETFL, O_NONBLOCK);
652
653 #ifdef VCL_TEST
654           rv = vppcom_session_connect (tsock->fd, &scm->server_endpt);
655           if (rv)
656             {
657               errno = -rv;
658               rv = -1;
659             }
660 #else
661           rv =
662             connect (tsock->fd, (struct sockaddr *) &scm->server_addr,
663                      scm->server_addr_size);
664 #endif
665           if (rv < 0)
666             {
667               errno_val = errno;
668               perror ("ERROR in sock_test_connect_test_sockets()");
669               fprintf (stderr, "CLIENT: ERROR: connect failed "
670                        "(errno = %d)!\n", errno_val);
671               return -1;
672             }
673           tsock->cfg = ctrl->cfg;
674           vcl_test_session_buf_alloc (tsock);
675           sock_test_cfg_sync (tsock);
676
677           printf ("CLIENT (fd %d): Test socket %d connected.\n",
678                   tsock->fd, i);
679         }
680     }
681
682   scm->num_test_sockets = num_test_sockets;
683   printf ("CLIENT: All sockets (%d) connected!\n", scm->num_test_sockets + 1);
684   return 0;
685 }
686
687 static void
688 dump_help (void)
689 {
690 #define INDENT "\n  "
691
692   printf ("CLIENT: Test configuration commands:"
693           INDENT VCL_TEST_TOKEN_HELP
694           "\t\t\tDisplay help."
695           INDENT VCL_TEST_TOKEN_EXIT
696           "\t\t\tExit test client & server."
697           INDENT VCL_TEST_TOKEN_SHOW_CFG
698           "\t\t\tShow the current test cfg."
699           INDENT VCL_TEST_TOKEN_RUN_UNI
700           "\t\t\tRun the Uni-directional test."
701           INDENT VCL_TEST_TOKEN_RUN_BI
702           "\t\t\tRun the Bi-directional test."
703           INDENT VCL_TEST_TOKEN_VERBOSE
704           "\t\t\tToggle verbose setting."
705           INDENT VCL_TEST_TOKEN_RXBUF_SIZE
706           "<rxbuf size>\tRx buffer size (bytes)."
707           INDENT VCL_TEST_TOKEN_TXBUF_SIZE
708           "<txbuf size>\tTx buffer size (bytes)."
709           INDENT VCL_TEST_TOKEN_NUM_WRITES
710           "<# of writes>\tNumber of txbuf writes to server." "\n");
711 }
712
713 static void
714 cfg_txbuf_size_set (void)
715 {
716   sock_client_main_t *scm = &vcl_client_main;
717   vcl_test_session_t *ctrl = &scm->ctrl_socket;
718   char *p = ctrl->txbuf + strlen (VCL_TEST_TOKEN_TXBUF_SIZE);
719   uint64_t txbuf_size = strtoull ((const char *) p, NULL, 10);
720
721   if (txbuf_size >= VCL_TEST_CFG_BUF_SIZE_MIN)
722     {
723       ctrl->cfg.txbuf_size = txbuf_size;
724       ctrl->cfg.total_bytes = ctrl->cfg.num_writes * ctrl->cfg.txbuf_size;
725       vcl_test_buf_alloc (&ctrl->cfg, 0 /* is_rxbuf */ ,
726                           (uint8_t **) & ctrl->txbuf, &ctrl->txbuf_size);
727       vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
728     }
729   else
730     fprintf (stderr, "CLIENT: ERROR: Invalid txbuf size (%lu) < "
731              "minimum buf size (%u)!\n",
732              txbuf_size, VCL_TEST_CFG_BUF_SIZE_MIN);
733 }
734
735 static void
736 cfg_num_writes_set (void)
737 {
738   sock_client_main_t *scm = &vcl_client_main;
739   vcl_test_session_t *ctrl = &scm->ctrl_socket;
740   char *p = ctrl->txbuf + strlen (VCL_TEST_TOKEN_NUM_WRITES);
741   uint32_t num_writes = strtoul ((const char *) p, NULL, 10);
742
743   if (num_writes > 0)
744     {
745       ctrl->cfg.num_writes = num_writes;
746       ctrl->cfg.total_bytes = ctrl->cfg.num_writes * ctrl->cfg.txbuf_size;
747       vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
748     }
749   else
750     {
751       fprintf (stderr, "CLIENT: ERROR: invalid num writes: %u\n", num_writes);
752     }
753 }
754
755 static void
756 cfg_num_test_sockets_set (void)
757 {
758   sock_client_main_t *scm = &vcl_client_main;
759   vcl_test_session_t *ctrl = &scm->ctrl_socket;
760   char *p = ctrl->txbuf + strlen (VCL_TEST_TOKEN_NUM_TEST_SESS);
761   uint32_t num_test_sockets = strtoul ((const char *) p, NULL, 10);
762
763   if ((num_test_sockets > 0) &&
764       (num_test_sockets <= VCL_TEST_CFG_MAX_TEST_SESS))
765     {
766       ctrl->cfg.num_test_sessions = num_test_sockets;
767       sock_test_connect_test_sockets (num_test_sockets);
768
769       vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
770     }
771   else
772     {
773       fprintf (stderr, "CLIENT: ERROR: invalid num test sockets: "
774                "%u, (%d max)\n",
775                num_test_sockets, VCL_TEST_CFG_MAX_TEST_SESS);
776     }
777 }
778
779 static void
780 cfg_rxbuf_size_set (void)
781 {
782   sock_client_main_t *scm = &vcl_client_main;
783   vcl_test_session_t *ctrl = &scm->ctrl_socket;
784   char *p = ctrl->txbuf + strlen (VCL_TEST_TOKEN_RXBUF_SIZE);
785   uint64_t rxbuf_size = strtoull ((const char *) p, NULL, 10);
786
787   if (rxbuf_size >= VCL_TEST_CFG_BUF_SIZE_MIN)
788     {
789       ctrl->cfg.rxbuf_size = rxbuf_size;
790       vcl_test_buf_alloc (&ctrl->cfg, 1 /* is_rxbuf */ ,
791                           (uint8_t **) & ctrl->rxbuf, &ctrl->rxbuf_size);
792       vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
793     }
794   else
795     fprintf (stderr, "CLIENT: ERROR: Invalid rxbuf size (%lu) < "
796              "minimum buf size (%u)!\n",
797              rxbuf_size, VCL_TEST_CFG_BUF_SIZE_MIN);
798 }
799
800 static void
801 cfg_verbose_toggle (void)
802 {
803   sock_client_main_t *scm = &vcl_client_main;
804   vcl_test_session_t *ctrl = &scm->ctrl_socket;
805
806   ctrl->cfg.verbose = ctrl->cfg.verbose ? 0 : 1;
807   vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
808
809 }
810
811 static vcl_test_t
812 parse_input ()
813 {
814   sock_client_main_t *scm = &vcl_client_main;
815   vcl_test_session_t *ctrl = &scm->ctrl_socket;
816   vcl_test_t rv = VCL_TEST_TYPE_NONE;
817
818   if (!strncmp (VCL_TEST_TOKEN_EXIT, ctrl->txbuf,
819                 strlen (VCL_TEST_TOKEN_EXIT)))
820     rv = VCL_TEST_TYPE_EXIT;
821
822   else if (!strncmp (VCL_TEST_TOKEN_HELP, ctrl->txbuf,
823                      strlen (VCL_TEST_TOKEN_HELP)))
824     dump_help ();
825
826   else if (!strncmp (VCL_TEST_TOKEN_SHOW_CFG, ctrl->txbuf,
827                      strlen (VCL_TEST_TOKEN_SHOW_CFG)))
828     scm->dump_cfg = 1;
829
830   else if (!strncmp (VCL_TEST_TOKEN_VERBOSE, ctrl->txbuf,
831                      strlen (VCL_TEST_TOKEN_VERBOSE)))
832     cfg_verbose_toggle ();
833
834   else if (!strncmp (VCL_TEST_TOKEN_TXBUF_SIZE, ctrl->txbuf,
835                      strlen (VCL_TEST_TOKEN_TXBUF_SIZE)))
836     cfg_txbuf_size_set ();
837
838   else if (!strncmp (VCL_TEST_TOKEN_NUM_TEST_SESS, ctrl->txbuf,
839                      strlen (VCL_TEST_TOKEN_NUM_TEST_SESS)))
840     cfg_num_test_sockets_set ();
841
842   else if (!strncmp (VCL_TEST_TOKEN_NUM_WRITES, ctrl->txbuf,
843                      strlen (VCL_TEST_TOKEN_NUM_WRITES)))
844     cfg_num_writes_set ();
845
846   else if (!strncmp (VCL_TEST_TOKEN_RXBUF_SIZE, ctrl->txbuf,
847                      strlen (VCL_TEST_TOKEN_RXBUF_SIZE)))
848     cfg_rxbuf_size_set ();
849
850   else if (!strncmp (VCL_TEST_TOKEN_RUN_UNI, ctrl->txbuf,
851                      strlen (VCL_TEST_TOKEN_RUN_UNI)))
852     rv = ctrl->cfg.test = VCL_TEST_TYPE_UNI;
853
854   else if (!strncmp (VCL_TEST_TOKEN_RUN_BI, ctrl->txbuf,
855                      strlen (VCL_TEST_TOKEN_RUN_BI)))
856     rv = ctrl->cfg.test = VCL_TEST_TYPE_BI;
857
858   else
859     rv = VCL_TEST_TYPE_ECHO;
860
861   return rv;
862 }
863
864 void
865 print_usage_and_exit (void)
866 {
867   fprintf (stderr,
868            "sock_test_client [OPTIONS] <ipaddr> <port>\n"
869            "  OPTIONS\n"
870            "  -h               Print this message and exit.\n"
871            "  -6               Use IPv6\n"
872            "  -u               Use UDP transport layer\n"
873            "  -c               Print test config before test.\n"
874            "  -w <dir>         Write test results to <dir>.\n"
875            "  -X               Exit after running test.\n"
876            "  -E               Run Echo test.\n"
877            "  -N <num-writes>  Test Cfg: number of writes.\n"
878            "  -R <rxbuf-size>  Test Cfg: rx buffer size.\n"
879            "  -T <txbuf-size>  Test Cfg: tx buffer size.\n"
880            "  -U               Run Uni-directional test.\n"
881            "  -B               Run Bi-directional test.\n"
882            "  -V               Verbose mode.\n");
883   exit (1);
884 }
885
886 int
887 main (int argc, char **argv)
888 {
889   sock_client_main_t *scm = &vcl_client_main;
890   vcl_test_session_t *ctrl = &scm->ctrl_socket;
891   int c, rv, errno_val;
892   vcl_test_t post_test = VCL_TEST_TYPE_NONE;
893
894   vcl_test_cfg_init (&ctrl->cfg);
895   vcl_test_session_buf_alloc (ctrl);
896
897   opterr = 0;
898   while ((c = getopt (argc, argv, "chn:w:XE:I:N:R:T:UBV6D")) != -1)
899     switch (c)
900       {
901       case 'c':
902         scm->dump_cfg = 1;
903         break;
904
905       case 's':
906         if (sscanf (optarg, "0x%x", &ctrl->cfg.num_test_sessions) != 1)
907           if (sscanf (optarg, "%u", &ctrl->cfg.num_test_sessions) != 1)
908             {
909               fprintf (stderr, "CLIENT: ERROR: Invalid value for "
910                        "option -%c!\n", c);
911               print_usage_and_exit ();
912             }
913         if (!ctrl->cfg.num_test_sessions ||
914             (ctrl->cfg.num_test_sessions > FD_SETSIZE))
915           {
916             fprintf (stderr, "CLIENT: ERROR: Invalid number of "
917                      "sockets (%d) specified for option -%c!\n"
918                      "       Valid range is 1 - %d\n",
919                      ctrl->cfg.num_test_sessions, c, FD_SETSIZE);
920             print_usage_and_exit ();
921           }
922         break;
923
924       case 'w':
925         fprintf (stderr, "CLIENT: Writing test results to files is TBD.\n");
926         break;
927
928       case 'X':
929         post_test = VCL_TEST_TYPE_EXIT;
930         break;
931
932       case 'E':
933         if (strlen (optarg) > ctrl->txbuf_size)
934           {
935             fprintf (stderr, "CLIENT: ERROR: Option -%c value "
936                      "larger than txbuf size (%d)!\n",
937                      optopt, ctrl->txbuf_size);
938             print_usage_and_exit ();
939           }
940         strcpy (ctrl->txbuf, optarg);
941         ctrl->cfg.test = VCL_TEST_TYPE_ECHO;
942         break;
943
944       case 'I':
945         if (sscanf (optarg, "0x%x", &ctrl->cfg.num_test_sessions) != 1)
946           if (sscanf (optarg, "%d", &ctrl->cfg.num_test_sessions) != 1)
947             {
948               fprintf (stderr, "CLIENT: ERROR: Invalid value for "
949                        "option -%c!\n", c);
950               print_usage_and_exit ();
951             }
952         if (ctrl->cfg.num_test_sessions > VCL_TEST_CFG_MAX_TEST_SESS)
953           {
954             fprintf (stderr, "CLIENT: ERROR: value greater than max "
955                      "number test sockets (%d)!", VCL_TEST_CFG_MAX_TEST_SESS);
956             print_usage_and_exit ();
957           }
958         break;
959
960       case 'N':
961         if (sscanf (optarg, "0x%lx", &ctrl->cfg.num_writes) != 1)
962           if (sscanf (optarg, "%ld", &ctrl->cfg.num_writes) != 1)
963             {
964               fprintf (stderr, "CLIENT: ERROR: Invalid value for "
965                        "option -%c!\n", c);
966               print_usage_and_exit ();
967             }
968         ctrl->cfg.total_bytes = ctrl->cfg.num_writes * ctrl->cfg.txbuf_size;
969         break;
970
971       case 'R':
972         if (sscanf (optarg, "0x%lx", &ctrl->cfg.rxbuf_size) != 1)
973           if (sscanf (optarg, "%ld", &ctrl->cfg.rxbuf_size) != 1)
974             {
975               fprintf (stderr, "CLIENT: ERROR: Invalid value for "
976                        "option -%c!\n", c);
977               print_usage_and_exit ();
978             }
979         if (ctrl->cfg.rxbuf_size >= VCL_TEST_CFG_BUF_SIZE_MIN)
980           {
981             ctrl->rxbuf_size = ctrl->cfg.rxbuf_size;
982             vcl_test_buf_alloc (&ctrl->cfg, 1 /* is_rxbuf */ ,
983                                 (uint8_t **) & ctrl->rxbuf,
984                                 &ctrl->rxbuf_size);
985           }
986         else
987           {
988             fprintf (stderr, "CLIENT: ERROR: rxbuf size (%lu) "
989                      "less than minumum (%u)\n",
990                      ctrl->cfg.rxbuf_size, VCL_TEST_CFG_BUF_SIZE_MIN);
991             print_usage_and_exit ();
992           }
993
994         break;
995
996       case 'T':
997         if (sscanf (optarg, "0x%lx", &ctrl->cfg.txbuf_size) != 1)
998           if (sscanf (optarg, "%ld", &ctrl->cfg.txbuf_size) != 1)
999             {
1000               fprintf (stderr, "CLIENT: ERROR: Invalid value "
1001                        "for option -%c!\n", c);
1002               print_usage_and_exit ();
1003             }
1004         if (ctrl->cfg.txbuf_size >= VCL_TEST_CFG_BUF_SIZE_MIN)
1005           {
1006             ctrl->txbuf_size = ctrl->cfg.txbuf_size;
1007             vcl_test_buf_alloc (&ctrl->cfg, 0 /* is_rxbuf */ ,
1008                                 (uint8_t **) & ctrl->txbuf,
1009                                 &ctrl->txbuf_size);
1010             ctrl->cfg.total_bytes =
1011               ctrl->cfg.num_writes * ctrl->cfg.txbuf_size;
1012           }
1013         else
1014           {
1015             fprintf (stderr, "CLIENT: ERROR: txbuf size (%lu) "
1016                      "less than minumum (%u)!\n",
1017                      ctrl->cfg.txbuf_size, VCL_TEST_CFG_BUF_SIZE_MIN);
1018             print_usage_and_exit ();
1019           }
1020         break;
1021
1022       case 'U':
1023         ctrl->cfg.test = VCL_TEST_TYPE_UNI;
1024         break;
1025
1026       case 'B':
1027         ctrl->cfg.test = VCL_TEST_TYPE_BI;
1028         break;
1029
1030       case 'V':
1031         ctrl->cfg.verbose = 1;
1032         break;
1033
1034       case '6':
1035         ctrl->cfg.address_ip6 = 1;
1036         break;
1037
1038       case 'D':
1039         ctrl->cfg.transport_udp = 1;
1040         break;
1041
1042       case '?':
1043         switch (optopt)
1044           {
1045           case 'E':
1046           case 'I':
1047           case 'N':
1048           case 'R':
1049           case 'T':
1050           case 'w':
1051             fprintf (stderr, "CLIENT: ERROR: Option -%c "
1052                      "requires an argument.\n", optopt);
1053             break;
1054
1055           default:
1056             if (isprint (optopt))
1057               fprintf (stderr, "CLIENT: ERROR: Unknown "
1058                        "option `-%c'.\n", optopt);
1059             else
1060               fprintf (stderr, "CLIENT: ERROR: Unknown "
1061                        "option character `\\x%x'.\n", optopt);
1062           }
1063         /* fall thru */
1064       case 'h':
1065       default:
1066         print_usage_and_exit ();
1067       }
1068
1069   if (argc < (optind + 2))
1070     {
1071       fprintf (stderr, "CLIENT: ERROR: Insufficient number of arguments!\n");
1072       print_usage_and_exit ();
1073     }
1074
1075 #ifdef VCL_TEST
1076   ctrl->fd = vppcom_app_create ("vcl_test_client");
1077   if (ctrl->fd < 0)
1078     {
1079       errno = -ctrl->fd;
1080       ctrl->fd = -1;
1081     }
1082   else
1083     {
1084       ctrl->fd = vppcom_session_create (ctrl->cfg.transport_udp ?
1085                                         VPPCOM_PROTO_UDP :
1086                                         VPPCOM_PROTO_TCP,
1087                                         0 /* is_nonblocking */ );
1088       if (ctrl->fd < 0)
1089         {
1090           errno = -ctrl->fd;
1091           ctrl->fd = -1;
1092         }
1093     }
1094 #else
1095   ctrl->fd = socket (ctrl->cfg.address_ip6 ? AF_INET6 : AF_INET,
1096                      ctrl->cfg.transport_udp ? SOCK_DGRAM : SOCK_STREAM, 0);
1097 #endif
1098
1099   if (ctrl->fd < 0)
1100     {
1101       errno_val = errno;
1102       perror ("ERROR in main()");
1103       fprintf (stderr, "CLIENT: ERROR: socket "
1104                "failed (errno = %d)!\n", errno_val);
1105       return ctrl->fd;
1106     }
1107
1108   memset (&scm->server_addr, 0, sizeof (scm->server_addr));
1109   if (ctrl->cfg.address_ip6)
1110     {
1111       struct sockaddr_in6 *server_addr =
1112         (struct sockaddr_in6 *) &scm->server_addr;
1113       scm->server_addr_size = sizeof (*server_addr);
1114       server_addr->sin6_family = AF_INET6;
1115       inet_pton (AF_INET6, argv[optind++], &(server_addr->sin6_addr));
1116       server_addr->sin6_port = htons (atoi (argv[optind]));
1117     }
1118   else
1119     {
1120       struct sockaddr_in *server_addr =
1121         (struct sockaddr_in *) &scm->server_addr;
1122       scm->server_addr_size = sizeof (*server_addr);
1123       server_addr->sin_family = AF_INET;
1124       inet_pton (AF_INET, argv[optind++], &(server_addr->sin_addr));
1125       server_addr->sin_port = htons (atoi (argv[optind]));
1126     }
1127
1128 #ifdef VCL_TEST
1129   if (ctrl->cfg.address_ip6)
1130     {
1131       struct sockaddr_in6 *server_addr =
1132         (struct sockaddr_in6 *) &scm->server_addr;
1133       scm->server_endpt.is_ip4 = 0;
1134       scm->server_endpt.ip = (uint8_t *) & server_addr->sin6_addr;
1135       scm->server_endpt.port = (uint16_t) server_addr->sin6_port;
1136     }
1137   else
1138     {
1139       struct sockaddr_in *server_addr =
1140         (struct sockaddr_in *) &scm->server_addr;
1141       scm->server_endpt.is_ip4 = 1;
1142       scm->server_endpt.ip = (uint8_t *) & server_addr->sin_addr;
1143       scm->server_endpt.port = (uint16_t) server_addr->sin_port;
1144     }
1145 #endif
1146
1147   do
1148     {
1149       printf ("\nCLIENT: Connecting to server...\n");
1150
1151 #ifdef VCL_TEST
1152       rv = vppcom_session_connect (ctrl->fd, &scm->server_endpt);
1153       if (rv)
1154         {
1155           errno = -rv;
1156           rv = -1;
1157         }
1158 #else
1159       rv =
1160         connect (ctrl->fd, (struct sockaddr *) &scm->server_addr,
1161                  scm->server_addr_size);
1162 #endif
1163       if (rv < 0)
1164         {
1165           errno_val = errno;
1166           perror ("ERROR in main()");
1167           fprintf (stderr, "CLIENT: ERROR: connect failed (errno = %d)!\n",
1168                    errno_val);
1169           return -1;
1170         }
1171
1172       sock_test_cfg_sync (ctrl);
1173       printf ("CLIENT (fd %d): Control socket connected.\n", ctrl->fd);
1174     }
1175   while (rv < 0);
1176
1177   sock_test_connect_test_sockets (ctrl->cfg.num_test_sessions);
1178
1179   while (ctrl->cfg.test != VCL_TEST_TYPE_EXIT)
1180     {
1181       if (scm->dump_cfg)
1182         {
1183           vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
1184           scm->dump_cfg = 0;
1185         }
1186
1187       switch (ctrl->cfg.test)
1188         {
1189         case VCL_TEST_TYPE_ECHO:
1190           echo_test_client ();
1191           break;
1192
1193         case VCL_TEST_TYPE_UNI:
1194         case VCL_TEST_TYPE_BI:
1195           stream_test_client (ctrl->cfg.test);
1196           break;
1197
1198         case VCL_TEST_TYPE_EXIT:
1199           continue;
1200
1201         case VCL_TEST_TYPE_NONE:
1202         default:
1203           break;
1204         }
1205       switch (post_test)
1206         {
1207         case VCL_TEST_TYPE_EXIT:
1208           switch (ctrl->cfg.test)
1209             {
1210             case VCL_TEST_TYPE_EXIT:
1211             case VCL_TEST_TYPE_UNI:
1212             case VCL_TEST_TYPE_BI:
1213             case VCL_TEST_TYPE_ECHO:
1214               ctrl->cfg.test = VCL_TEST_TYPE_EXIT;
1215               continue;
1216
1217             case VCL_TEST_TYPE_NONE:
1218             default:
1219               break;
1220             }
1221           break;
1222
1223         case VCL_TEST_TYPE_NONE:
1224         case VCL_TEST_TYPE_ECHO:
1225         case VCL_TEST_TYPE_UNI:
1226         case VCL_TEST_TYPE_BI:
1227         default:
1228           break;
1229         }
1230
1231       memset (ctrl->txbuf, 0, ctrl->txbuf_size);
1232       memset (ctrl->rxbuf, 0, ctrl->rxbuf_size);
1233
1234       printf ("\nCLIENT: Type some characters and hit <return>\n"
1235               "('" VCL_TEST_TOKEN_HELP "' for help): ");
1236
1237       if (fgets (ctrl->txbuf, ctrl->txbuf_size, stdin) != NULL)
1238         {
1239           if (strlen (ctrl->txbuf) == 1)
1240             {
1241               printf ("\nCLIENT: Nothing to send!  Please try again...\n");
1242               continue;
1243             }
1244           ctrl->txbuf[strlen (ctrl->txbuf) - 1] = 0;    // chomp the newline.
1245
1246           /* Parse input for keywords */
1247           ctrl->cfg.test = parse_input ();
1248         }
1249     }
1250
1251   exit_client ();
1252 #ifdef VCL_TEST
1253   vppcom_session_close (ctrl->fd);
1254   vppcom_app_destroy ();
1255   return 0;
1256 #else
1257   close (ctrl->fd);
1258   return (scm->af_unix_echo_tx == scm->af_unix_echo_rx) ? 0 : -1;
1259 #endif
1260 }
1261
1262 /*
1263  * fd.io coding-style-patch-verification: ON
1264  *
1265  * Local Variables:
1266  * eval: (c-set-style "gnu")
1267  * End:
1268  */