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