ed36c7a6acc9aba18492ed60e81c7a740f46af2f
[vpp.git] / src / vcl / sock_test_server.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 <sys/types.h>
19 #include <sys/socket.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include <time.h>
23 #include <ctype.h>
24 #include <vcl/sock_test.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27
28 #define SOCK_SERVER_USE_EPOLL 1
29 #define VPPCOM_SESSION_ATTR_UNIT_TEST 0
30
31 #if SOCK_SERVER_USE_EPOLL
32 #include <sys/epoll.h>
33 #endif
34
35 #ifdef VCL_TEST
36 #if VPPCOM_SESSION_ATTR_UNIT_TEST
37 #define BUFLEN  sizeof (uint64_t) * 16
38 uint64_t buffer[16];
39 uint32_t buflen = BUFLEN;
40 uint32_t *flags = (uint32_t *) buffer;
41 #endif
42 #endif
43
44 typedef struct
45 {
46   uint8_t is_alloc;
47   int fd;
48   uint8_t *buf;
49   uint32_t buf_size;
50   sock_test_cfg_t cfg;
51   sock_test_stats_t stats;
52 #ifdef VCL_TEST
53   vppcom_endpt_t endpt;
54   uint8_t ip[16];
55 #endif
56 } sock_server_conn_t;
57
58 #define SOCK_SERVER_MAX_TEST_CONN  10
59 #define SOCK_SERVER_MAX_EPOLL_EVENTS 10
60 typedef struct
61 {
62   int listen_fd;
63 #if SOCK_SERVER_USE_EPOLL
64   int epfd;
65   struct epoll_event listen_ev;
66   struct epoll_event wait_events[SOCK_SERVER_MAX_EPOLL_EVENTS];
67 #endif
68   size_t num_conn;
69   size_t conn_pool_size;
70   sock_server_conn_t *conn_pool;
71   int nfds;
72   fd_set rd_fdset;
73   fd_set wr_fdset;
74   struct timeval timeout;
75 } sock_server_main_t;
76
77 sock_server_main_t sock_server_main;
78
79 #if ! SOCK_SERVER_USE_EPOLL
80 static inline int
81 get_nfds (void)
82 {
83   sock_server_main_t *ssm = &sock_server_main;
84   int i, nfds;
85
86   for (nfds = i = 0; i < FD_SETSIZE; i++)
87     {
88       if (FD_ISSET (i, &ssm->rd_fdset) || FD_ISSET (i, &ssm->wr_fdset))
89         nfds = i + 1;
90     }
91   return nfds;
92 }
93
94 static inline void
95 conn_fdset_set (sock_server_conn_t * conn, fd_set * fdset)
96 {
97   sock_server_main_t *ssm = &sock_server_main;
98
99   FD_SET (conn->fd, fdset);
100   ssm->nfds = get_nfds ();
101 }
102
103 static inline void
104 conn_fdset_clr (sock_server_conn_t * conn, fd_set * fdset)
105 {
106   sock_server_main_t *ssm = &sock_server_main;
107
108   FD_CLR (conn->fd, fdset);
109   ssm->nfds = get_nfds ();
110 }
111 #endif
112
113 static inline void
114 conn_pool_expand (size_t expand_size)
115 {
116   sock_server_main_t *ssm = &sock_server_main;
117   sock_server_conn_t *conn_pool;
118   size_t new_size = ssm->conn_pool_size + expand_size;
119   int i;
120
121   conn_pool = realloc (ssm->conn_pool, new_size * sizeof (*ssm->conn_pool));
122   if (conn_pool)
123     {
124       for (i = ssm->conn_pool_size; i < new_size; i++)
125         {
126           sock_server_conn_t *conn = &conn_pool[i];
127           memset (conn, 0, sizeof (*conn));
128           sock_test_cfg_init (&conn->cfg);
129           sock_test_buf_alloc (&conn->cfg, 1 /* is_rxbuf */ ,
130                                &conn->buf, &conn->buf_size);
131           conn->cfg.txbuf_size = conn->cfg.rxbuf_size;
132         }
133
134       ssm->conn_pool = conn_pool;
135       ssm->conn_pool_size = new_size;
136     }
137   else
138     {
139       int errno_val = errno;
140       perror ("ERROR in conn_pool_expand()");
141       fprintf (stderr, "ERROR: Memory allocation failed (errno = %d)!\n",
142                errno_val);
143     }
144 }
145
146 static inline sock_server_conn_t *
147 conn_pool_alloc (void)
148 {
149   sock_server_main_t *ssm = &sock_server_main;
150   int i;
151
152   for (i = 0; i < ssm->conn_pool_size; i++)
153     {
154       if (!ssm->conn_pool[i].is_alloc)
155         {
156 #ifdef VCL_TEST
157           ssm->conn_pool[i].endpt.ip = ssm->conn_pool[i].ip;
158 #endif
159           ssm->conn_pool[i].is_alloc = 1;
160           return (&ssm->conn_pool[i]);
161         }
162     }
163
164   return 0;
165 }
166
167 static inline void
168 conn_pool_free (sock_server_conn_t * conn)
169 {
170 #if ! SOCK_SERVER_USE_EPOLL
171   sock_server_main_t *ssm = &sock_server_main;
172
173   conn_fdset_clr (conn, &ssm->rd_fdset);
174   conn_fdset_clr (conn, &ssm->wr_fdset);
175 #endif
176   conn->fd = 0;
177   conn->is_alloc = 0;
178 }
179
180 static inline void
181 sync_config_and_reply (sock_server_conn_t * conn, sock_test_cfg_t * rx_cfg)
182 {
183   conn->cfg = *rx_cfg;
184   sock_test_buf_alloc (&conn->cfg, 1 /* is_rxbuf */ ,
185                        &conn->buf, &conn->buf_size);
186   conn->cfg.txbuf_size = conn->cfg.rxbuf_size;
187
188   if (conn->cfg.verbose)
189     {
190       printf ("\nSERVER (fd %d): Replying to cfg message!\n", conn->fd);
191       sock_test_cfg_dump (&conn->cfg, 0 /* is_client */ );
192     }
193   (void) sock_test_write (conn->fd, (uint8_t *) & conn->cfg,
194                           sizeof (conn->cfg), NULL, conn->cfg.verbose);
195 }
196
197 static void
198 stream_test_server_start_stop (sock_server_conn_t * conn,
199                                sock_test_cfg_t * rx_cfg)
200 {
201   sock_server_main_t *ssm = &sock_server_main;
202   int client_fd = conn->fd;
203   sock_test_t test = rx_cfg->test;
204
205   if (rx_cfg->ctrl_handle == conn->fd)
206     {
207       int i;
208       clock_gettime (CLOCK_REALTIME, &conn->stats.stop);
209
210       for (i = 0; i < ssm->conn_pool_size; i++)
211         {
212           sock_server_conn_t *tc = &ssm->conn_pool[i];
213
214           if (tc->cfg.ctrl_handle == conn->fd)
215             {
216               sock_test_stats_accumulate (&conn->stats, &tc->stats);
217
218               if (conn->cfg.verbose)
219                 {
220                   static char buf[64];
221
222                   sprintf (buf, "SERVER (fd %d) RESULTS", tc->fd);
223                   sock_test_stats_dump (buf, &tc->stats, 1 /* show_rx */ ,
224                                         test == SOCK_TEST_TYPE_BI
225                                         /* show tx */ ,
226                                         conn->cfg.verbose);
227                 }
228             }
229         }
230
231       sock_test_stats_dump ("SERVER RESULTS", &conn->stats, 1 /* show_rx */ ,
232                             (test == SOCK_TEST_TYPE_BI) /* show_tx */ ,
233                             conn->cfg.verbose);
234       sock_test_cfg_dump (&conn->cfg, 0 /* is_client */ );
235       if (conn->cfg.verbose)
236         {
237           printf ("  sock server main\n"
238                   SOCK_TEST_SEPARATOR_STRING
239                   "       buf:  %p\n"
240                   "  buf size:  %u (0x%08x)\n"
241                   SOCK_TEST_SEPARATOR_STRING,
242                   conn->buf, conn->buf_size, conn->buf_size);
243         }
244
245       sync_config_and_reply (conn, rx_cfg);
246       printf ("\nSERVER (fd %d): %s-directional Stream Test Complete!\n"
247               SOCK_TEST_BANNER_STRING "\n", conn->fd,
248               test == SOCK_TEST_TYPE_BI ? "Bi" : "Uni");
249     }
250   else
251     {
252       printf ("\n" SOCK_TEST_BANNER_STRING
253               "SERVER (fd %d): %s-directional Stream Test!\n"
254               "  Sending client the test cfg to start streaming data...\n",
255               client_fd, test == SOCK_TEST_TYPE_BI ? "Bi" : "Uni");
256
257       rx_cfg->ctrl_handle = (rx_cfg->ctrl_handle == ~0) ? conn->fd :
258         rx_cfg->ctrl_handle;
259
260       sync_config_and_reply (conn, rx_cfg);
261
262       /* read the 1st chunk, record start time */
263       memset (&conn->stats, 0, sizeof (conn->stats));
264       clock_gettime (CLOCK_REALTIME, &conn->stats.start);
265     }
266 }
267
268
269 static inline void
270 stream_test_server (sock_server_conn_t * conn, int rx_bytes)
271 {
272   int client_fd = conn->fd;
273   sock_test_t test = conn->cfg.test;
274
275   if (test == SOCK_TEST_TYPE_BI)
276     (void) sock_test_write (client_fd, conn->buf, rx_bytes, &conn->stats,
277                             conn->cfg.verbose);
278
279   if (conn->stats.rx_bytes >= conn->cfg.total_bytes)
280     {
281       clock_gettime (CLOCK_REALTIME, &conn->stats.stop);
282     }
283 }
284
285 static inline void
286 new_client (void)
287 {
288   sock_server_main_t *ssm = &sock_server_main;
289   int client_fd;
290   sock_server_conn_t *conn;
291
292   if (ssm->conn_pool_size < (ssm->num_conn + SOCK_SERVER_MAX_TEST_CONN + 1))
293     conn_pool_expand (SOCK_SERVER_MAX_TEST_CONN + 1);
294
295   conn = conn_pool_alloc ();
296   if (!conn)
297     {
298       fprintf (stderr, "\nERROR: No free connections!\n");
299       return;
300     }
301
302 #ifdef VCL_TEST
303   client_fd = vppcom_session_accept (ssm->listen_fd, &conn->endpt, 0,
304                                      -1.0 /* wait forever */ );
305   if (client_fd < 0)
306     errno = -client_fd;
307 #elif HAVE_ACCEPT4
308   client_fd = accept4 (ssm->listen_fd, (struct sockaddr *) NULL, NULL, NULL);
309 #else
310   client_fd = accept (ssm->listen_fd, (struct sockaddr *) NULL, NULL);
311 #endif
312   if (client_fd < 0)
313     {
314       int errno_val;
315       errno_val = errno;
316       perror ("ERROR in new_client()");
317       fprintf (stderr, "ERROR: accept failed (errno = %d)!\n", errno_val);
318     }
319
320   printf ("SERVER: Got a connection -- fd = %d (0x%08x)!\n",
321           client_fd, client_fd);
322
323   conn->fd = client_fd;
324
325 #if ! SOCK_SERVER_USE_EPOLL
326   conn_fdset_set (conn, &ssm->rd_fdset);
327   ssm->nfds++;
328 #else
329   {
330     struct epoll_event ev;
331     int rv;
332
333     ev.events = EPOLLIN;
334     ev.data.u64 = conn - ssm->conn_pool;
335 #ifdef VCL_TEST
336     rv = vppcom_epoll_ctl (ssm->epfd, EPOLL_CTL_ADD, client_fd, &ev);
337     if (rv)
338       errno = -rv;
339 #else
340     rv = epoll_ctl (ssm->epfd, EPOLL_CTL_ADD, client_fd, &ev);
341 #endif
342     if (rv < 0)
343       {
344         int errno_val;
345         errno_val = errno;
346         perror ("ERROR in new_client()");
347         fprintf (stderr, "ERROR: epoll_ctl failed (errno = %d)!\n",
348                  errno_val);
349       }
350     else
351       ssm->nfds++;
352   }
353 #endif
354 }
355
356 int
357 main (int argc, char **argv)
358 {
359   sock_server_main_t *ssm = &sock_server_main;
360   int client_fd, rv, main_rv = 0;
361   int tx_bytes, rx_bytes, nbytes;
362   sock_server_conn_t *conn;
363   sock_test_cfg_t *rx_cfg;
364   uint32_t xtra = 0;
365   uint64_t xtra_bytes = 0;
366   struct sockaddr_in servaddr;
367   int errno_val;
368   int v, i;
369   uint16_t port = SOCK_TEST_SERVER_PORT;
370 #if ! SOCK_SERVER_USE_EPOLL
371   fd_set _rfdset, *rfdset = &_rfdset;
372 #endif
373 #ifdef VCL_TEST
374   vppcom_endpt_t endpt;
375 #else
376 #if ! SOCK_SERVER_USE_EPOLL
377   fd_set _wfdset, *wfdset = &_wfdset;
378 #endif
379 #endif
380
381   if ((argc == 2) && (sscanf (argv[1], "%d", &v) == 1))
382     port = (uint16_t) v;
383
384   conn_pool_expand (SOCK_SERVER_MAX_TEST_CONN + 1);
385
386 #ifdef VCL_TEST
387   rv = vppcom_app_create ("vcl_test_server");
388   if (rv)
389     {
390       errno = -rv;
391       ssm->listen_fd = -1;
392     }
393   else
394     {
395       ssm->listen_fd =
396         vppcom_session_create (VPPCOM_VRF_DEFAULT, VPPCOM_PROTO_TCP,
397                                0 /* is_nonblocking */ );
398     }
399 #else
400   ssm->listen_fd = socket (AF_INET, SOCK_STREAM, 0);
401 #endif
402   if (ssm->listen_fd < 0)
403     {
404       errno_val = errno;
405       perror ("ERROR in main()");
406       fprintf (stderr, "ERROR: socket() failed (errno = %d)!\n", errno_val);
407       return ssm->listen_fd;
408     }
409
410   memset (&servaddr, 0, sizeof (servaddr));
411
412   servaddr.sin_family = AF_INET;
413   servaddr.sin_addr.s_addr = htonl (INADDR_ANY);
414   servaddr.sin_port = htons (port);
415
416 #ifdef VCL_TEST
417   endpt.vrf = VPPCOM_VRF_DEFAULT;
418   endpt.is_ip4 = (servaddr.sin_family == AF_INET);
419   endpt.ip = (uint8_t *) & servaddr.sin_addr;
420   endpt.port = (uint16_t) servaddr.sin_port;
421
422   rv = vppcom_session_bind (ssm->listen_fd, &endpt);
423   if (rv)
424     {
425       errno = -rv;
426       rv = -1;
427     }
428
429 #if VPPCOM_SESSION_ATTR_UNIT_TEST
430   buflen = BUFLEN;
431   if (vppcom_session_attr (ssm->listen_fd, VPPCOM_ATTR_GET_FLAGS,
432                            buffer, &buflen) != VPPCOM_OK)
433     printf ("\nGET_FLAGS0: Oh no, Mr. Biiiiiiiiiiiilllllll ! ! ! !\n");
434   buflen = BUFLEN;
435   *flags = O_RDWR | O_NONBLOCK;
436   if (vppcom_session_attr (ssm->listen_fd, VPPCOM_ATTR_SET_FLAGS,
437                            buffer, &buflen) != VPPCOM_OK)
438     printf ("\nSET_FLAGS1: Oh no, Mr. Biiiiiiiiiiiilllllll ! ! ! !\n");
439   buflen = BUFLEN;
440   if (vppcom_session_attr (ssm->listen_fd, VPPCOM_ATTR_GET_FLAGS,
441                            buffer, &buflen) != VPPCOM_OK)
442     printf ("\nGET_FLAGS1:Oh no, Mr. Biiiiiiiiiiiilllllll ! ! ! !\n");
443   *flags = O_RDWR;
444   buflen = BUFLEN;
445   if (vppcom_session_attr (ssm->listen_fd, VPPCOM_ATTR_SET_FLAGS,
446                            buffer, &buflen) != VPPCOM_OK)
447     printf ("\nSET_FLAGS2: Oh no, Mr. Biiiiiiiiiiiilllllll ! ! ! !\n");
448   buflen = BUFLEN;
449   if (vppcom_session_attr (ssm->listen_fd, VPPCOM_ATTR_GET_FLAGS,
450                            buffer, &buflen) != VPPCOM_OK)
451     printf ("\nGET_FLAGS2:Oh no, Mr. Biiiiiiiiiiiilllllll ! ! ! !\n");
452
453   buflen = BUFLEN;
454   if (vppcom_session_attr (ssm->listen_fd, VPPCOM_ATTR_GET_PEER_ADDR,
455                            buffer, &buflen) != VPPCOM_OK)
456     printf ("\nGET_PEER_ADDR: Oh no, Mr. Biiiiiiiiiiiilllllll ! ! ! !\n");
457   buflen = BUFLEN;
458   if (vppcom_session_attr (ssm->listen_fd, VPPCOM_ATTR_GET_LCL_ADDR,
459                            buffer, &buflen) != VPPCOM_OK)
460     printf ("\nGET_LCL_ADDR: Oh no, Mr. Biiiiiiiiiiiilllllll ! ! ! !\n");
461 #endif
462 #else
463   rv =
464     bind (ssm->listen_fd, (struct sockaddr *) &servaddr, sizeof (servaddr));
465 #endif
466   if (rv < 0)
467     {
468       errno_val = errno;
469       perror ("ERROR in main()");
470       fprintf (stderr, "ERROR: bind failed (errno = %d)!\n", errno_val);
471       return rv;
472     }
473
474 #ifdef VCL_TEST
475   rv = vppcom_session_listen (ssm->listen_fd, 10);
476   if (rv)
477     {
478       errno = -rv;
479       rv = -1;
480     }
481 #else
482   rv = listen (ssm->listen_fd, 10);
483 #endif
484   if (rv < 0)
485     {
486       errno_val = errno;
487       perror ("ERROR in main()");
488       fprintf (stderr, "ERROR: listen failed (errno = %d)!\n", errno_val);
489       return rv;
490     }
491
492   printf ("\nSERVER: Waiting for a client to connect on port %d...\n", port);
493
494 #if ! SOCK_SERVER_USE_EPOLL
495
496   FD_ZERO (&ssm->wr_fdset);
497   FD_ZERO (&ssm->rd_fdset);
498
499   FD_SET (ssm->listen_fd, &ssm->rd_fdset);
500   ssm->nfds = ssm->listen_fd + 1;
501
502 #else
503 #ifdef VCL_TEST
504   ssm->epfd = vppcom_epoll_create ();
505   if (ssm->epfd < 0)
506     errno = -ssm->epfd;
507 #else
508   ssm->epfd = epoll_create (1);
509 #endif
510   if (ssm->epfd < 0)
511     {
512       errno_val = errno;
513       perror ("ERROR in main()");
514       fprintf (stderr, "ERROR: epoll_create failed (errno = %d)!\n",
515                errno_val);
516       return ssm->epfd;
517     }
518
519   ssm->listen_ev.events = EPOLLIN;
520   ssm->listen_ev.data.u32 = ~0;
521 #ifdef VCL_TEST
522   rv = vppcom_epoll_ctl (ssm->epfd, EPOLL_CTL_ADD, ssm->listen_fd,
523                          &ssm->listen_ev);
524   if (rv < 0)
525     errno = -rv;
526 #else
527   rv = epoll_ctl (ssm->epfd, EPOLL_CTL_ADD, ssm->listen_fd, &ssm->listen_ev);
528 #endif
529   if (rv < 0)
530     {
531       errno_val = errno;
532       perror ("ERROR in main()");
533       fprintf (stderr, "ERROR: epoll_ctl failed (errno = %d)!\n", errno_val);
534       return rv;
535     }
536 #endif
537
538   while (1)
539     {
540 #if ! SOCK_SERVER_USE_EPOLL
541       _rfdset = ssm->rd_fdset;
542
543 #ifdef VCL_TEST
544       rv = vppcom_select (ssm->nfds, (uint64_t *) rfdset, NULL, NULL, 0);
545 #else
546       {
547         struct timeval timeout;
548         timeout = ssm->timeout;
549         _wfdset = ssm->wr_fdset;
550         rv = select (ssm->nfds, rfdset, wfdset, NULL, &timeout);
551       }
552 #endif
553       if (rv < 0)
554         {
555           perror ("select()");
556           fprintf (stderr, "\nERROR: select() failed -- aborting!\n");
557           main_rv = -1;
558           goto done;
559         }
560       else if (rv == 0)
561         continue;
562
563       if (FD_ISSET (ssm->listen_fd, rfdset))
564         new_client ();
565
566       for (i = 0; i < ssm->conn_pool_size; i++)
567         {
568           if (!ssm->conn_pool[i].is_alloc)
569             continue;
570
571           conn = &ssm->conn_pool[i];
572 #else
573       int num_ev;
574 #ifdef VCL_TEST
575       num_ev = vppcom_epoll_wait (ssm->epfd, ssm->wait_events,
576                                   SOCK_SERVER_MAX_EPOLL_EVENTS, 60.0);
577       if (num_ev < 0)
578         errno = -num_ev;
579 #else
580       num_ev = epoll_wait (ssm->epfd, ssm->wait_events,
581                            SOCK_SERVER_MAX_EPOLL_EVENTS, 60000);
582 #endif
583       if (num_ev < 0)
584         {
585           perror ("epoll_wait()");
586           fprintf (stderr, "\nERROR: epoll_wait() failed -- aborting!\n");
587           main_rv = -1;
588           goto done;
589         }
590       if (num_ev == 0)
591         {
592           fprintf (stderr, "\nepoll_wait() timeout!\n");
593           continue;
594         }
595       for (i = 0; i < num_ev; i++)
596         {
597           if (ssm->wait_events[i].data.u32 == ~0)
598             {
599               new_client ();
600               continue;
601             }
602           conn = &ssm->conn_pool[ssm->wait_events[i].data.u32];
603 #endif
604           client_fd = conn->fd;
605
606 #if ! SOCK_SERVER_USE_EPOLL
607           if (FD_ISSET (client_fd, rfdset))
608 #else
609           if (EPOLLIN & ssm->wait_events[i].events)
610 #endif
611             {
612 #ifdef VCL_TEST
613 #if VPPCOM_SESSION_ATTR_UNIT_TEST
614               buflen = BUFLEN;
615               if (vppcom_session_attr (client_fd, VPPCOM_ATTR_GET_NREAD,
616                                        buffer, &buflen) < VPPCOM_OK)
617                 printf ("\nNREAD: Oh no, Mr. Biiiiiiiiiiiilllllll ! ! ! !\n");
618               if (vppcom_session_attr (client_fd,
619                                        VPPCOM_ATTR_GET_PEER_ADDR,
620                                        buffer, &buflen) != VPPCOM_OK)
621                 printf ("\nGET_PEER_ADDR: Oh no, Mr. "
622                         "Biiiiiiiiiiiilllllll ! ! ! !\n");
623               buflen = BUFLEN;
624               if (vppcom_session_attr (client_fd, VPPCOM_ATTR_GET_LCL_ADDR,
625                                        buffer, &buflen) != VPPCOM_OK)
626                 printf ("\nGET_LCL_ADDR: Oh no, Mr. "
627                         "Biiiiiiiiiiiilllllll ! ! ! !\n");
628 #endif
629 #endif
630               rx_bytes = sock_test_read (client_fd, conn->buf,
631                                          conn->buf_size, &conn->stats);
632               if (rx_bytes > 0)
633                 {
634                   rx_cfg = (sock_test_cfg_t *) conn->buf;
635                   if (rx_cfg->magic == SOCK_TEST_CFG_CTRL_MAGIC)
636                     {
637                       if (rx_cfg->verbose)
638                         {
639                           printf ("SERVER (fd %d): Received a cfg message!\n",
640                                   client_fd);
641                           sock_test_cfg_dump (rx_cfg, 0 /* is_client */ );
642                         }
643
644                       if (rx_bytes != sizeof (*rx_cfg))
645                         {
646                           printf ("SERVER (fd %d): Invalid cfg message "
647                                   "size (%d)!\n  Should be %lu bytes.\n",
648                                   client_fd, rx_bytes, sizeof (*rx_cfg));
649                           conn->cfg.rxbuf_size = 0;
650                           conn->cfg.num_writes = 0;
651                           if (conn->cfg.verbose)
652                             {
653                               printf ("SERVER (fd %d): Replying to "
654                                       "cfg message!\n", client_fd);
655                               sock_test_cfg_dump (rx_cfg, 0 /* is_client */ );
656                             }
657                           sock_test_write (client_fd, (uint8_t *) & conn->cfg,
658                                            sizeof (conn->cfg), NULL,
659                                            conn->cfg.verbose);
660                           continue;
661                         }
662
663                       switch (rx_cfg->test)
664                         {
665                         case SOCK_TEST_TYPE_NONE:
666                         case SOCK_TEST_TYPE_ECHO:
667                           sync_config_and_reply (conn, rx_cfg);
668                           break;
669
670                         case SOCK_TEST_TYPE_BI:
671                         case SOCK_TEST_TYPE_UNI:
672                           stream_test_server_start_stop (conn, rx_cfg);
673                           break;
674
675                         case SOCK_TEST_TYPE_EXIT:
676                           printf ("SERVER: Have a great day, "
677                                   "connection %d!\n", client_fd);
678 #ifdef VCL_TEST
679                           vppcom_session_close (client_fd);
680 #else
681                           close (client_fd);
682 #endif
683                           conn_pool_free (conn);
684 #if ! SOCK_SERVER_USE_EPOLL
685                           if (ssm->nfds == (ssm->listen_fd + 1))
686 #else
687                           ssm->nfds--;
688                           if (!ssm->nfds)
689 #endif
690                             {
691                               printf ("SERVER: All client connections "
692                                       "closed.\n\nSERVER: "
693                                       "May the force be with you!\n\n");
694                               goto done;
695                             }
696                           break;
697
698                         default:
699                           fprintf (stderr, "ERROR: Unknown test type!\n");
700                           sock_test_cfg_dump (rx_cfg, 0 /* is_client */ );
701                           break;
702                         }
703                       continue;
704                     }
705
706                   else if ((conn->cfg.test == SOCK_TEST_TYPE_UNI) ||
707                            (conn->cfg.test == SOCK_TEST_TYPE_BI))
708                     {
709                       stream_test_server (conn, rx_bytes);
710                       continue;
711                     }
712
713                   else if (isascii (conn->buf[0]))
714                     {
715                       // If it looks vaguely like a string, make sure it's terminated
716                       ((char *) conn->buf)[rx_bytes <
717                                            conn->buf_size ? rx_bytes :
718                                            conn->buf_size - 1] = 0;
719                       printf ("SERVER (fd %d): RX (%d bytes) - '%s'\n",
720                               conn->fd, rx_bytes, conn->buf);
721                     }
722                 }
723               else              // rx_bytes < 0
724                 {
725                   if (errno == ECONNRESET)
726                     {
727                       printf ("\nSERVER: Connection reset by remote peer.\n"
728                               "  Y'all have a great day now!\n\n");
729                       break;
730                     }
731                   else
732                     continue;
733                 }
734
735               if (isascii (conn->buf[0]))
736                 {
737                   // If it looks vaguely like a string, make sure it's terminated
738                   ((char *) conn->buf)[rx_bytes <
739                                        conn->buf_size ? rx_bytes :
740                                        conn->buf_size - 1] = 0;
741                   if (xtra)
742                     fprintf (stderr,
743                              "ERROR: FIFO not drained in previous test!\n"
744                              "       extra chunks %u (0x%x)\n"
745                              "        extra bytes %lu (0x%lx)\n",
746                              xtra, xtra, xtra_bytes, xtra_bytes);
747
748                   xtra = 0;
749                   xtra_bytes = 0;
750
751                   if (conn->cfg.verbose)
752                     printf ("SERVER (fd %d): Echoing back\n", client_fd);
753
754                   nbytes = strlen ((const char *) conn->buf) + 1;
755
756                   tx_bytes = sock_test_write (client_fd, conn->buf,
757                                               nbytes, &conn->stats,
758                                               conn->cfg.verbose);
759                   if (tx_bytes >= 0)
760                     printf ("SERVER (fd %d): TX (%d bytes) - '%s'\n",
761                             conn->fd, tx_bytes, conn->buf);
762                 }
763
764               else              // Extraneous read data from non-echo tests???
765                 {
766                   xtra++;
767                   xtra_bytes += rx_bytes;
768                 }
769             }
770         }
771     }
772
773 done:
774 #ifdef VCL_TEST
775   vppcom_session_close (ssm->listen_fd);
776   vppcom_app_destroy ();
777 #else
778   close (ssm->listen_fd);
779 #endif
780   if (ssm->conn_pool)
781     free (ssm->conn_pool);
782
783   return main_rv;
784 }
785
786 /*
787  * fd.io coding-style-patch-verification: ON
788  *
789  * Local Variables:
790  * eval: (c-set-style "gnu")
791  * End:
792  */