VCL: improve debug output
[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       return;
319     }
320
321   printf ("SERVER: Got a connection -- fd = %d (0x%08x)!\n",
322           client_fd, client_fd);
323
324   conn->fd = client_fd;
325
326 #if ! SOCK_SERVER_USE_EPOLL
327   conn_fdset_set (conn, &ssm->rd_fdset);
328   ssm->nfds++;
329 #else
330   {
331     struct epoll_event ev;
332     int rv;
333
334     ev.events = EPOLLIN;
335     ev.data.u64 = conn - ssm->conn_pool;
336 #ifdef VCL_TEST
337     rv = vppcom_epoll_ctl (ssm->epfd, EPOLL_CTL_ADD, client_fd, &ev);
338     if (rv)
339       errno = -rv;
340 #else
341     rv = epoll_ctl (ssm->epfd, EPOLL_CTL_ADD, client_fd, &ev);
342 #endif
343     if (rv < 0)
344       {
345         int errno_val;
346         errno_val = errno;
347         perror ("ERROR in new_client()");
348         fprintf (stderr, "ERROR: epoll_ctl failed (errno = %d)!\n",
349                  errno_val);
350       }
351     else
352       ssm->nfds++;
353   }
354 #endif
355 }
356
357 int
358 main (int argc, char **argv)
359 {
360   sock_server_main_t *ssm = &sock_server_main;
361   int client_fd, rv, main_rv = 0;
362   int tx_bytes, rx_bytes, nbytes;
363   sock_server_conn_t *conn;
364   sock_test_cfg_t *rx_cfg;
365   uint32_t xtra = 0;
366   uint64_t xtra_bytes = 0;
367   struct sockaddr_in servaddr;
368   int errno_val;
369   int v, i;
370   uint16_t port = SOCK_TEST_SERVER_PORT;
371 #if ! SOCK_SERVER_USE_EPOLL
372   fd_set _rfdset, *rfdset = &_rfdset;
373 #endif
374 #ifdef VCL_TEST
375   vppcom_endpt_t endpt;
376 #else
377 #if ! SOCK_SERVER_USE_EPOLL
378   fd_set _wfdset, *wfdset = &_wfdset;
379 #endif
380 #endif
381
382   if ((argc == 2) && (sscanf (argv[1], "%d", &v) == 1))
383     port = (uint16_t) v;
384
385   conn_pool_expand (SOCK_SERVER_MAX_TEST_CONN + 1);
386
387 #ifdef VCL_TEST
388   rv = vppcom_app_create ("vcl_test_server");
389   if (rv)
390     {
391       errno = -rv;
392       ssm->listen_fd = -1;
393     }
394   else
395     {
396       ssm->listen_fd =
397         vppcom_session_create (VPPCOM_VRF_DEFAULT, VPPCOM_PROTO_TCP,
398                                0 /* is_nonblocking */ );
399     }
400 #else
401   ssm->listen_fd = socket (AF_INET, SOCK_STREAM, 0);
402 #endif
403   if (ssm->listen_fd < 0)
404     {
405       errno_val = errno;
406       perror ("ERROR in main()");
407       fprintf (stderr, "ERROR: socket() failed (errno = %d)!\n", errno_val);
408       return ssm->listen_fd;
409     }
410
411   memset (&servaddr, 0, sizeof (servaddr));
412
413   servaddr.sin_family = AF_INET;
414   servaddr.sin_addr.s_addr = htonl (INADDR_ANY);
415   servaddr.sin_port = htons (port);
416
417 #ifdef VCL_TEST
418   endpt.vrf = VPPCOM_VRF_DEFAULT;
419   endpt.is_ip4 = (servaddr.sin_family == AF_INET);
420   endpt.ip = (uint8_t *) & servaddr.sin_addr;
421   endpt.port = (uint16_t) servaddr.sin_port;
422
423   rv = vppcom_session_bind (ssm->listen_fd, &endpt);
424   if (rv)
425     {
426       errno = -rv;
427       rv = -1;
428     }
429
430 #if VPPCOM_SESSION_ATTR_UNIT_TEST
431   buflen = BUFLEN;
432   if (vppcom_session_attr (ssm->listen_fd, VPPCOM_ATTR_GET_FLAGS,
433                            buffer, &buflen) != VPPCOM_OK)
434     printf ("\nGET_FLAGS0: Oh no, Mr. Biiiiiiiiiiiilllllll ! ! ! !\n");
435   buflen = BUFLEN;
436   *flags = O_RDWR | O_NONBLOCK;
437   if (vppcom_session_attr (ssm->listen_fd, VPPCOM_ATTR_SET_FLAGS,
438                            buffer, &buflen) != VPPCOM_OK)
439     printf ("\nSET_FLAGS1: Oh no, Mr. Biiiiiiiiiiiilllllll ! ! ! !\n");
440   buflen = BUFLEN;
441   if (vppcom_session_attr (ssm->listen_fd, VPPCOM_ATTR_GET_FLAGS,
442                            buffer, &buflen) != VPPCOM_OK)
443     printf ("\nGET_FLAGS1:Oh no, Mr. Biiiiiiiiiiiilllllll ! ! ! !\n");
444   *flags = O_RDWR;
445   buflen = BUFLEN;
446   if (vppcom_session_attr (ssm->listen_fd, VPPCOM_ATTR_SET_FLAGS,
447                            buffer, &buflen) != VPPCOM_OK)
448     printf ("\nSET_FLAGS2: Oh no, Mr. Biiiiiiiiiiiilllllll ! ! ! !\n");
449   buflen = BUFLEN;
450   if (vppcom_session_attr (ssm->listen_fd, VPPCOM_ATTR_GET_FLAGS,
451                            buffer, &buflen) != VPPCOM_OK)
452     printf ("\nGET_FLAGS2:Oh no, Mr. Biiiiiiiiiiiilllllll ! ! ! !\n");
453
454   buflen = BUFLEN;
455   if (vppcom_session_attr (ssm->listen_fd, VPPCOM_ATTR_GET_PEER_ADDR,
456                            buffer, &buflen) != VPPCOM_OK)
457     printf ("\nGET_PEER_ADDR: Oh no, Mr. Biiiiiiiiiiiilllllll ! ! ! !\n");
458   buflen = BUFLEN;
459   if (vppcom_session_attr (ssm->listen_fd, VPPCOM_ATTR_GET_LCL_ADDR,
460                            buffer, &buflen) != VPPCOM_OK)
461     printf ("\nGET_LCL_ADDR: Oh no, Mr. Biiiiiiiiiiiilllllll ! ! ! !\n");
462 #endif
463 #else
464   rv =
465     bind (ssm->listen_fd, (struct sockaddr *) &servaddr, sizeof (servaddr));
466 #endif
467   if (rv < 0)
468     {
469       errno_val = errno;
470       perror ("ERROR in main()");
471       fprintf (stderr, "ERROR: bind failed (errno = %d)!\n", errno_val);
472       return rv;
473     }
474
475 #ifdef VCL_TEST
476   rv = vppcom_session_listen (ssm->listen_fd, 10);
477   if (rv)
478     {
479       errno = -rv;
480       rv = -1;
481     }
482 #else
483   rv = listen (ssm->listen_fd, 10);
484 #endif
485   if (rv < 0)
486     {
487       errno_val = errno;
488       perror ("ERROR in main()");
489       fprintf (stderr, "ERROR: listen failed (errno = %d)!\n", errno_val);
490       return rv;
491     }
492
493   printf ("\nSERVER: Waiting for a client to connect on port %d...\n", port);
494
495 #if ! SOCK_SERVER_USE_EPOLL
496
497   FD_ZERO (&ssm->wr_fdset);
498   FD_ZERO (&ssm->rd_fdset);
499
500   FD_SET (ssm->listen_fd, &ssm->rd_fdset);
501   ssm->nfds = ssm->listen_fd + 1;
502
503 #else
504 #ifdef VCL_TEST
505   ssm->epfd = vppcom_epoll_create ();
506   if (ssm->epfd < 0)
507     errno = -ssm->epfd;
508 #else
509   ssm->epfd = epoll_create (1);
510 #endif
511   if (ssm->epfd < 0)
512     {
513       errno_val = errno;
514       perror ("ERROR in main()");
515       fprintf (stderr, "ERROR: epoll_create failed (errno = %d)!\n",
516                errno_val);
517       return ssm->epfd;
518     }
519
520   ssm->listen_ev.events = EPOLLIN;
521   ssm->listen_ev.data.u32 = ~0;
522 #ifdef VCL_TEST
523   rv = vppcom_epoll_ctl (ssm->epfd, EPOLL_CTL_ADD, ssm->listen_fd,
524                          &ssm->listen_ev);
525   if (rv < 0)
526     errno = -rv;
527 #else
528   rv = epoll_ctl (ssm->epfd, EPOLL_CTL_ADD, ssm->listen_fd, &ssm->listen_ev);
529 #endif
530   if (rv < 0)
531     {
532       errno_val = errno;
533       perror ("ERROR in main()");
534       fprintf (stderr, "ERROR: epoll_ctl failed (errno = %d)!\n", errno_val);
535       return rv;
536     }
537 #endif
538
539   while (1)
540     {
541 #if ! SOCK_SERVER_USE_EPOLL
542       _rfdset = ssm->rd_fdset;
543
544 #ifdef VCL_TEST
545       rv = vppcom_select (ssm->nfds, (uint64_t *) rfdset, NULL, NULL, 0);
546 #else
547       {
548         struct timeval timeout;
549         timeout = ssm->timeout;
550         _wfdset = ssm->wr_fdset;
551         rv = select (ssm->nfds, rfdset, wfdset, NULL, &timeout);
552       }
553 #endif
554       if (rv < 0)
555         {
556           perror ("select()");
557           fprintf (stderr, "\nERROR: select() failed -- aborting!\n");
558           main_rv = -1;
559           goto done;
560         }
561       else if (rv == 0)
562         continue;
563
564       if (FD_ISSET (ssm->listen_fd, rfdset))
565         new_client ();
566
567       for (i = 0; i < ssm->conn_pool_size; i++)
568         {
569           if (!ssm->conn_pool[i].is_alloc)
570             continue;
571
572           conn = &ssm->conn_pool[i];
573 #else
574       int num_ev;
575 #ifdef VCL_TEST
576       num_ev = vppcom_epoll_wait (ssm->epfd, ssm->wait_events,
577                                   SOCK_SERVER_MAX_EPOLL_EVENTS, 60.0);
578       if (num_ev < 0)
579         errno = -num_ev;
580 #else
581       num_ev = epoll_wait (ssm->epfd, ssm->wait_events,
582                            SOCK_SERVER_MAX_EPOLL_EVENTS, 60000);
583 #endif
584       if (num_ev < 0)
585         {
586           perror ("epoll_wait()");
587           fprintf (stderr, "\nERROR: epoll_wait() failed -- aborting!\n");
588           main_rv = -1;
589           goto done;
590         }
591       if (num_ev == 0)
592         {
593           fprintf (stderr, "\nepoll_wait() timeout!\n");
594           continue;
595         }
596       for (i = 0; i < num_ev; i++)
597         {
598           if (ssm->wait_events[i].data.u32 == ~0)
599             {
600               new_client ();
601               continue;
602             }
603           conn = &ssm->conn_pool[ssm->wait_events[i].data.u32];
604 #endif
605           client_fd = conn->fd;
606
607 #if ! SOCK_SERVER_USE_EPOLL
608           if (FD_ISSET (client_fd, rfdset))
609 #else
610           if (EPOLLIN & ssm->wait_events[i].events)
611 #endif
612             {
613 #ifdef VCL_TEST
614 #if VPPCOM_SESSION_ATTR_UNIT_TEST
615               buflen = BUFLEN;
616               if (vppcom_session_attr (client_fd, VPPCOM_ATTR_GET_NREAD,
617                                        buffer, &buflen) < VPPCOM_OK)
618                 printf ("\nNREAD: Oh no, Mr. Biiiiiiiiiiiilllllll ! ! ! !\n");
619               if (vppcom_session_attr (client_fd,
620                                        VPPCOM_ATTR_GET_PEER_ADDR,
621                                        buffer, &buflen) != VPPCOM_OK)
622                 printf ("\nGET_PEER_ADDR: Oh no, Mr. "
623                         "Biiiiiiiiiiiilllllll ! ! ! !\n");
624               buflen = BUFLEN;
625               if (vppcom_session_attr (client_fd, VPPCOM_ATTR_GET_LCL_ADDR,
626                                        buffer, &buflen) != VPPCOM_OK)
627                 printf ("\nGET_LCL_ADDR: Oh no, Mr. "
628                         "Biiiiiiiiiiiilllllll ! ! ! !\n");
629 #endif
630 #endif
631               rx_bytes = sock_test_read (client_fd, conn->buf,
632                                          conn->buf_size, &conn->stats);
633               if (rx_bytes > 0)
634                 {
635                   rx_cfg = (sock_test_cfg_t *) conn->buf;
636                   if (rx_cfg->magic == SOCK_TEST_CFG_CTRL_MAGIC)
637                     {
638                       if (rx_cfg->verbose)
639                         {
640                           printf ("SERVER (fd %d): Received a cfg message!\n",
641                                   client_fd);
642                           sock_test_cfg_dump (rx_cfg, 0 /* is_client */ );
643                         }
644
645                       if (rx_bytes != sizeof (*rx_cfg))
646                         {
647                           printf ("SERVER (fd %d): Invalid cfg message "
648                                   "size (%d)!\n  Should be %lu bytes.\n",
649                                   client_fd, rx_bytes, sizeof (*rx_cfg));
650                           conn->cfg.rxbuf_size = 0;
651                           conn->cfg.num_writes = 0;
652                           if (conn->cfg.verbose)
653                             {
654                               printf ("SERVER (fd %d): Replying to "
655                                       "cfg message!\n", client_fd);
656                               sock_test_cfg_dump (rx_cfg, 0 /* is_client */ );
657                             }
658                           sock_test_write (client_fd, (uint8_t *) & conn->cfg,
659                                            sizeof (conn->cfg), NULL,
660                                            conn->cfg.verbose);
661                           continue;
662                         }
663
664                       switch (rx_cfg->test)
665                         {
666                         case SOCK_TEST_TYPE_NONE:
667                         case SOCK_TEST_TYPE_ECHO:
668                           sync_config_and_reply (conn, rx_cfg);
669                           break;
670
671                         case SOCK_TEST_TYPE_BI:
672                         case SOCK_TEST_TYPE_UNI:
673                           stream_test_server_start_stop (conn, rx_cfg);
674                           break;
675
676                         case SOCK_TEST_TYPE_EXIT:
677                           printf ("SERVER: Have a great day, "
678                                   "connection %d!\n", client_fd);
679 #ifdef VCL_TEST
680                           vppcom_session_close (client_fd);
681 #else
682                           close (client_fd);
683 #endif
684                           conn_pool_free (conn);
685                           printf ("SERVER: Closed client fd %d\n", client_fd);
686 #if ! SOCK_SERVER_USE_EPOLL
687                           if (ssm->nfds == (ssm->listen_fd + 1))
688 #else
689                           ssm->nfds--;
690                           if (!ssm->nfds)
691 #endif
692                             {
693                               printf ("SERVER: All client connections "
694                                       "closed.\n\nSERVER: "
695                                       "May the force be with you!\n\n");
696                               goto done;
697                             }
698                           break;
699
700                         default:
701                           fprintf (stderr, "ERROR: Unknown test type!\n");
702                           sock_test_cfg_dump (rx_cfg, 0 /* is_client */ );
703                           break;
704                         }
705                       continue;
706                     }
707
708                   else if ((conn->cfg.test == SOCK_TEST_TYPE_UNI) ||
709                            (conn->cfg.test == SOCK_TEST_TYPE_BI))
710                     {
711                       stream_test_server (conn, rx_bytes);
712                       continue;
713                     }
714
715                   else if (isascii (conn->buf[0]))
716                     {
717                       // If it looks vaguely like a string, make sure it's terminated
718                       ((char *) conn->buf)[rx_bytes <
719                                            conn->buf_size ? rx_bytes :
720                                            conn->buf_size - 1] = 0;
721                       printf ("SERVER (fd %d): RX (%d bytes) - '%s'\n",
722                               conn->fd, rx_bytes, conn->buf);
723                     }
724                 }
725               else              // rx_bytes < 0
726                 {
727                   if (errno == ECONNRESET)
728                     {
729                       printf ("\nSERVER: Connection reset by remote peer.\n"
730                               "  Y'all have a great day now!\n\n");
731                       break;
732                     }
733                   else
734                     continue;
735                 }
736
737               if (isascii (conn->buf[0]))
738                 {
739                   // If it looks vaguely like a string, make sure it's terminated
740                   ((char *) conn->buf)[rx_bytes <
741                                        conn->buf_size ? rx_bytes :
742                                        conn->buf_size - 1] = 0;
743                   if (xtra)
744                     fprintf (stderr,
745                              "ERROR: FIFO not drained in previous test!\n"
746                              "       extra chunks %u (0x%x)\n"
747                              "        extra bytes %lu (0x%lx)\n",
748                              xtra, xtra, xtra_bytes, xtra_bytes);
749
750                   xtra = 0;
751                   xtra_bytes = 0;
752
753                   if (conn->cfg.verbose)
754                     printf ("SERVER (fd %d): Echoing back\n", client_fd);
755
756                   nbytes = strlen ((const char *) conn->buf) + 1;
757
758                   tx_bytes = sock_test_write (client_fd, conn->buf,
759                                               nbytes, &conn->stats,
760                                               conn->cfg.verbose);
761                   if (tx_bytes >= 0)
762                     printf ("SERVER (fd %d): TX (%d bytes) - '%s'\n",
763                             conn->fd, tx_bytes, conn->buf);
764                 }
765
766               else              // Extraneous read data from non-echo tests???
767                 {
768                   xtra++;
769                   xtra_bytes += rx_bytes;
770                 }
771             }
772         }
773     }
774
775 done:
776 #ifdef VCL_TEST
777   vppcom_session_close (ssm->listen_fd);
778   vppcom_app_destroy ();
779 #else
780   close (ssm->listen_fd);
781 #endif
782   if (ssm->conn_pool)
783     free (ssm->conn_pool);
784
785   return main_rv;
786 }
787
788 /*
789  * fd.io coding-style-patch-verification: ON
790  *
791  * Local Variables:
792  * eval: (c-set-style "gnu")
793  * End:
794  */