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