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