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