FD.io VPP  v19.08.3-2-gbabecb413
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  snprintf (buf, sizeof (buf), "SERVER (fd %d) RESULTS",
242  tc->fd);
243  vcl_test_stats_dump (buf, &tc->stats, 1 /* show_rx */ ,
244  test == VCL_TEST_TYPE_BI
245  /* show tx */ ,
246  conn->cfg.verbose);
247  }
248  }
249  }
250 
251  vcl_test_stats_dump ("SERVER RESULTS", &conn->stats, 1 /* show_rx */ ,
252  (test == VCL_TEST_TYPE_BI) /* show_tx */ ,
253  conn->cfg.verbose);
254  vcl_test_cfg_dump (&conn->cfg, 0 /* is_client */ );
255  if (conn->cfg.verbose)
256  {
257  printf (" sock server main\n"
259  " buf: %p\n"
260  " buf size: %u (0x%08x)\n"
262  conn->buf, conn->buf_size, conn->buf_size);
263  }
264 
265  sync_config_and_reply (conn, rx_cfg);
266  printf ("\nSERVER (fd %d): %s-directional Stream Test Complete!\n"
267  SOCK_TEST_BANNER_STRING "\n", conn->fd,
268  test == VCL_TEST_TYPE_BI ? "Bi" : "Uni");
269  }
270  else
271  {
272  printf ("\n" SOCK_TEST_BANNER_STRING
273  "SERVER (fd %d): %s-directional Stream Test!\n"
274  " Sending client the test cfg to start streaming data...\n",
275  client_fd, test == VCL_TEST_TYPE_BI ? "Bi" : "Uni");
276 
277  rx_cfg->ctrl_handle = (rx_cfg->ctrl_handle == ~0) ? conn->fd :
278  rx_cfg->ctrl_handle;
279 
280  sync_config_and_reply (conn, rx_cfg);
281 
282  /* read the 1st chunk, record start time */
283  memset (&conn->stats, 0, sizeof (conn->stats));
284  clock_gettime (CLOCK_REALTIME, &conn->stats.start);
285  }
286 }
287 
288 
289 static inline void
291 {
292  int client_fd = conn->fd;
293  vcl_test_t test = conn->cfg.test;
294 
295  if (test == VCL_TEST_TYPE_BI)
296  (void) sock_test_write (client_fd, conn->buf, rx_bytes, &conn->stats,
297  conn->cfg.verbose);
298 
299  if (conn->stats.rx_bytes >= conn->cfg.total_bytes)
300  {
301  clock_gettime (CLOCK_REALTIME, &conn->stats.stop);
302  }
303 }
304 
305 #if SOCK_SERVER_USE_EPOLL && !defined (VCL_TEST)
306 static inline void
308 {
309  sock_server_main_t *ssm = &sock_server_main;
310  int af_unix_client_fd;
311  int rv;
312  int errno_val;
313  uint8_t buffer[256];
314  size_t nbytes = strlen (SOCK_TEST_MIXED_EPOLL_DATA) + 1;
315 
316 #if HAVE_ACCEPT4
317  af_unix_client_fd = accept4 (ssm->af_unix_listen_fd,
318  (struct sockaddr *) NULL, NULL, NULL);
319 #else
320  af_unix_client_fd = accept (ssm->af_unix_listen_fd,
321  (struct sockaddr *) NULL, NULL);
322 #endif
323  if (af_unix_client_fd < 0)
324  {
325  errno_val = errno;
326  perror ("ERROR in af_unix_accept()");
327  fprintf (stderr, "SERVER: ERROR: accept failed "
328  "(errno = %d)!\n", errno_val);
329  return;
330  }
331 
332  printf ("SERVER: Got an AF_UNIX connection -- fd = %d (0x%08x)!\n",
333  af_unix_client_fd, af_unix_client_fd);
334 
335  memset (buffer, 0, sizeof (buffer));
336 
337  rv = read (af_unix_client_fd, buffer, nbytes);
338  if (rv < 0)
339  {
340  errno_val = errno;
341  perror ("ERROR in af_unix_echo(): read() failed");
342  fprintf (stderr, "SERVER: ERROR: read(af_unix_client_fd %d (0x%x), "
343  "nbytes %lu) failed (errno = %d)!\n", af_unix_client_fd,
344  af_unix_client_fd, nbytes, errno_val);
345  goto done;
346  }
347  /* Make the buffer is NULL-terminated. */
348  buffer[sizeof (buffer) - 1] = 0;
349  printf ("SERVER (AF_UNIX): RX (%d bytes) - '%s'\n", rv, buffer);
350 
351  if (!strncmp (SOCK_TEST_MIXED_EPOLL_DATA, (const char *) buffer, nbytes))
352  {
353  rv = write (af_unix_client_fd, buffer, nbytes);
354  if (rv < 0)
355  {
356  errno_val = errno;
357  perror ("ERROR in af_unix_echo(): write() failed");
358  fprintf (stderr,
359  "SERVER: ERROR: write(af_unix_client_fd %d (0x%x), "
360  "\"%s\", nbytes %ld) failed (errno = %d)!\n",
361  af_unix_client_fd, af_unix_client_fd, buffer, nbytes,
362  errno_val);
363  goto done;
364  }
365  printf ("SERVER (AF_UNIX): TX (%d bytes) - '%s'\n", rv, buffer);
366  ssm->af_unix_xacts++;
367  }
368 done:
369  close (af_unix_client_fd);
370 }
371 
372 #endif
373 
374 static inline void
376 {
377  sock_server_main_t *ssm = &sock_server_main;
378  int client_fd;
379  sock_server_conn_t *conn;
380 
381  if (ssm->conn_pool_size < (ssm->num_conn + SOCK_SERVER_MAX_TEST_CONN + 1))
383 
384  conn = conn_pool_alloc ();
385  if (!conn)
386  {
387  fprintf (stderr, "\nSERVER: ERROR: No free connections!\n");
388  return;
389  }
390 
391 #ifdef VCL_TEST
392  client_fd = vppcom_session_accept (ssm->listen_fd, &conn->endpt, 0);
393  if (client_fd < 0)
394  errno = -client_fd;
395 #elif HAVE_ACCEPT4
396  client_fd = accept4 (ssm->listen_fd, (struct sockaddr *) NULL, NULL, NULL);
397 #else
398  client_fd = accept (ssm->listen_fd, (struct sockaddr *) NULL, NULL);
399 #endif
400  if (client_fd < 0)
401  {
402  int errno_val;
403  errno_val = errno;
404  perror ("ERROR in new_client()");
405  fprintf (stderr, "SERVER: ERROR: accept failed "
406  "(errno = %d)!\n", errno_val);
407  return;
408  }
409 
410  printf ("SERVER: Got a connection -- fd = %d (0x%08x)!\n",
411  client_fd, client_fd);
412 
413  conn->fd = client_fd;
414 
415 #if ! SOCK_SERVER_USE_EPOLL
416  conn_fdset_set (conn, &ssm->rd_fdset);
417  ssm->nfds++;
418 #else
419  {
420  struct epoll_event ev;
421  int rv;
422 
423  ev.events = EPOLLIN;
424  ev.data.u64 = conn - ssm->conn_pool;
425 #ifdef VCL_TEST
426  rv = vppcom_epoll_ctl (ssm->epfd, EPOLL_CTL_ADD, client_fd, &ev);
427  if (rv)
428  errno = -rv;
429 #else
430  rv = epoll_ctl (ssm->epfd, EPOLL_CTL_ADD, client_fd, &ev);
431 #endif
432  if (rv < 0)
433  {
434  int errno_val;
435  errno_val = errno;
436  perror ("ERROR in new_client()");
437  fprintf (stderr, "SERVER: ERROR: epoll_ctl failed (errno = %d)!\n",
438  errno_val);
439  }
440  else
441  ssm->nfds++;
442  }
443 #endif
444 }
445 
446 void
448 {
449  fprintf (stderr,
450  "sock_test_server [OPTIONS] <port>\n"
451  " OPTIONS\n"
452  " -h Print this message and exit.\n"
453  " -6 Use IPv6\n"
454  " -u Use UDP transport layer\n");
455  exit (1);
456 }
457 
458 int
459 main (int argc, char **argv)
460 {
461  sock_server_main_t *ssm = &sock_server_main;
462  int client_fd, rv, main_rv = 0;
463  int tx_bytes, rx_bytes, nbytes;
464  sock_server_conn_t *conn;
465  vcl_test_cfg_t *rx_cfg;
466  uint32_t xtra = 0;
467  uint64_t xtra_bytes = 0;
468  struct sockaddr_storage servaddr;
469  int errno_val;
470  int c, v, i;
471  uint16_t port = VCL_TEST_SERVER_PORT;
472 #if ! SOCK_SERVER_USE_EPOLL
473  fd_set _rfdset, *rfdset = &_rfdset;
474 #endif
475 #ifdef VCL_TEST
476  vppcom_endpt_t endpt;
477 #else
478  uint32_t servaddr_size;
479 #if ! SOCK_SERVER_USE_EPOLL
480  fd_set _wfdset, *wfdset = &_wfdset;
481 #endif
482 #endif
483 
484  opterr = 0;
485  while ((c = getopt (argc, argv, "6D")) != -1)
486  switch (c)
487  {
488  case '6':
489  ssm->cfg.address_ip6 = 1;
490  break;
491 
492  case 'D':
493  ssm->cfg.transport_udp = 1;
494  break;
495 
496  case '?':
497  switch (optopt)
498  {
499  default:
500  if (isprint (optopt))
501  fprintf (stderr, "SERVER: ERROR: Unknown "
502  "option `-%c'.\n", optopt);
503  else
504  fprintf (stderr, "SERVER: ERROR: Unknown "
505  "option character `\\x%x'.\n", optopt);
506  }
507  /* fall thru */
508  case 'h':
509  default:
511  }
512 
513  if (argc < (optind + 1))
514  {
515  fprintf (stderr, "SERVER: ERROR: Insufficient number of arguments!\n");
517  }
518 
519  if (sscanf (argv[optind], "%d", &v) == 1)
520  port = (uint16_t) v;
521  else
522  {
523  fprintf (stderr, "SERVER: ERROR: Invalid port (%s)!\n", argv[optind]);
525  }
526 
528 
529 #ifdef VCL_TEST
530  rv = vppcom_app_create ("vcl_test_server");
531  if (rv)
532  {
533  errno = -rv;
534  ssm->listen_fd = -1;
535  }
536  else
537  {
538  ssm->listen_fd = vppcom_session_create (ssm->cfg.transport_udp ?
539  VPPCOM_PROTO_UDP :
540  VPPCOM_PROTO_TCP,
541  0 /* is_nonblocking */ );
542  }
543 #else
544  ssm->listen_fd = socket (ssm->cfg.address_ip6 ? AF_INET6 : AF_INET,
545  ssm->cfg.transport_udp ? SOCK_DGRAM : SOCK_STREAM,
546  0);
547 #if SOCK_SERVER_USE_EPOLL && !defined (VCL_TEST)
548  unlink ((const char *) SOCK_TEST_AF_UNIX_FILENAME);
549  ssm->af_unix_listen_fd = socket (AF_UNIX, SOCK_STREAM, 0);
550  if (ssm->af_unix_listen_fd < 0)
551  {
552  errno_val = errno;
553  perror ("ERROR in main(): socket(AF_UNIX) failed");
554  fprintf (stderr,
555  "SERVER: ERROR: socket(AF_UNIX, SOCK_STREAM, 0) failed "
556  "(errno = %d)!\n", errno_val);
557  return ssm->af_unix_listen_fd;
558  }
559 
560  memset (&ssm->serveraddr, 0, sizeof (ssm->serveraddr));
561  ssm->serveraddr.sun_family = AF_UNIX;
562  strncpy (ssm->serveraddr.sun_path, SOCK_TEST_AF_UNIX_FILENAME,
563  sizeof (ssm->serveraddr.sun_path));
564 
565  rv = bind (ssm->af_unix_listen_fd, (struct sockaddr *) &ssm->serveraddr,
566  SUN_LEN (&ssm->serveraddr));
567  if (rv < 0)
568  {
569  errno_val = errno;
570  perror ("ERROR in main(): bind(SOCK_TEST_AF_UNIX_FILENAME) failed");
571  fprintf (stderr, "SERVER: ERROR: bind() fd %d, \"%s\": "
572  "failed (errno = %d)!\n", ssm->af_unix_listen_fd,
573  SOCK_TEST_AF_UNIX_FILENAME, errno_val);
574  close (ssm->af_unix_listen_fd);
575  unlink ((const char *) SOCK_TEST_AF_UNIX_FILENAME);
576  return rv;
577  }
578 
579  rv = listen (ssm->af_unix_listen_fd, 10);
580  if (rv < 0)
581  {
582  errno_val = errno;
583  perror ("ERROR in main(): listen(AF_UNIX) failed");
584  fprintf (stderr, "SERVER: ERROR: listen() fd %d, \"%s\": "
585  "failed (errno = %d)!\n", ssm->af_unix_listen_fd,
586  SOCK_TEST_AF_UNIX_FILENAME, errno_val);
587  close (ssm->af_unix_listen_fd);
588  unlink ((const char *) SOCK_TEST_AF_UNIX_FILENAME);
589  return rv;
590  }
591 #endif /* SOCK_SERVER_USE_EPOLL */
592 #endif
593  if (ssm->listen_fd < 0)
594  {
595  errno_val = errno;
596  perror ("ERROR in main()");
597  fprintf (stderr, "SERVER: ERROR: socket() failed "
598  "(errno = %d)!\n", errno_val);
599  return ssm->listen_fd;
600  }
601 
602  memset (&servaddr, 0, sizeof (servaddr));
603 
604  if (ssm->cfg.address_ip6)
605  {
606  struct sockaddr_in6 *server_addr = (struct sockaddr_in6 *) &servaddr;
607 #ifndef VCL_TEST
608  servaddr_size = sizeof (*server_addr);
609 #endif
610  server_addr->sin6_family = AF_INET6;
611  server_addr->sin6_addr = in6addr_any;
612  server_addr->sin6_port = htons (port);
613  }
614  else
615  {
616  struct sockaddr_in *server_addr = (struct sockaddr_in *) &servaddr;
617 #ifndef VCL_TEST
618  servaddr_size = sizeof (*server_addr);
619 #endif
620  server_addr->sin_family = AF_INET;
621  server_addr->sin_addr.s_addr = htonl (INADDR_ANY);
622  server_addr->sin_port = htons (port);
623  }
624 
625 #ifdef VCL_TEST
626  if (ssm->cfg.address_ip6)
627  {
628  struct sockaddr_in6 *server_addr = (struct sockaddr_in6 *) &servaddr;
629  endpt.is_ip4 = 0;
630  endpt.ip = (uint8_t *) & server_addr->sin6_addr;
631  endpt.port = (uint16_t) server_addr->sin6_port;
632  }
633  else
634  {
635  struct sockaddr_in *server_addr = (struct sockaddr_in *) &servaddr;
636  endpt.is_ip4 = 1;
637  endpt.ip = (uint8_t *) & server_addr->sin_addr;
638  endpt.port = (uint16_t) server_addr->sin_port;
639  }
640 
641  rv = vppcom_session_bind (ssm->listen_fd, &endpt);
642  if (rv)
643  {
644  errno = -rv;
645  rv = -1;
646  }
647 #else
648  rv = bind (ssm->listen_fd, (struct sockaddr *) &servaddr, servaddr_size);
649 #endif
650  if (rv < 0)
651  {
652  errno_val = errno;
653  perror ("ERROR in main()");
654  fprintf (stderr, "SERVER: ERROR: bind failed (errno = %d)!\n",
655  errno_val);
656  return rv;
657  }
658  if (fcntl (ssm->listen_fd, F_SETFL, O_NONBLOCK) < 0)
659  {
660  errno_val = errno;
661  perror ("ERROR in main()");
662  fprintf (stderr, "SERVER: ERROR: fcntl failed (errno = %d)!\n",
663  errno_val);
664  return rv;
665  }
666 
667 #ifdef VCL_TEST
668  rv = vppcom_session_listen (ssm->listen_fd, 10);
669  if (rv)
670  {
671  errno = -rv;
672  rv = -1;
673  }
674 #else
675  rv = listen (ssm->listen_fd, 10);
676 #endif
677  if (rv < 0)
678  {
679  errno_val = errno;
680  perror ("ERROR in main()");
681  fprintf (stderr, "SERVER: ERROR: listen failed "
682  "(errno = %d)!\n", errno_val);
683  return rv;
684  }
685 
686 #if ! SOCK_SERVER_USE_EPOLL
687 
688  FD_ZERO (&ssm->wr_fdset);
689  FD_ZERO (&ssm->rd_fdset);
690 
691  FD_SET (ssm->listen_fd, &ssm->rd_fdset);
692  ssm->nfds = ssm->listen_fd + 1;
693 
694 #else
695 #ifdef VCL_TEST
696  ssm->epfd = vppcom_epoll_create ();
697  if (ssm->epfd < 0)
698  errno = -ssm->epfd;
699 #else
700  ssm->epfd = epoll_create (1);
701 #endif
702  if (ssm->epfd < 0)
703  {
704  errno_val = errno;
705  perror ("ERROR in main()");
706  fprintf (stderr, "SERVER: ERROR: epoll_create failed (errno = %d)!\n",
707  errno_val);
708  return ssm->epfd;
709  }
710 
711  ssm->listen_ev.events = EPOLLIN;
712  ssm->listen_ev.data.u32 = ~0;
713 #ifdef VCL_TEST
714  rv = vppcom_epoll_ctl (ssm->epfd, EPOLL_CTL_ADD, ssm->listen_fd,
715  &ssm->listen_ev);
716  if (rv < 0)
717  errno = -rv;
718 #else
719  ssm->af_unix_listen_ev.events = EPOLLIN;
721  rv = epoll_ctl (ssm->epfd, EPOLL_CTL_ADD, ssm->af_unix_listen_fd,
722  &ssm->af_unix_listen_ev);
723  if (rv < 0)
724  {
725  errno_val = errno;
726  perror ("ERROR in main(): mixed epoll_ctl(EPOLL_CTL_ADD)");
727  fprintf (stderr, "SERVER: ERROR: mixed epoll_ctl(epfd %d (0x%x), "
728  "EPOLL_CTL_ADD, af_unix_listen_fd %d (0x%x), EPOLLIN) failed "
729  "(errno = %d)!\n", ssm->epfd, ssm->epfd,
730  ssm->af_unix_listen_fd, ssm->af_unix_listen_fd, errno_val);
731  close (ssm->af_unix_listen_fd);
732  unlink ((const char *) SOCK_TEST_AF_UNIX_FILENAME);
733  return rv;
734  }
735 
736  rv = epoll_ctl (ssm->epfd, EPOLL_CTL_ADD, ssm->listen_fd, &ssm->listen_ev);
737 #endif
738  if (rv < 0)
739  {
740  errno_val = errno;
741  perror ("ERROR in main()");
742  fprintf (stderr, "SERVER: ERROR: epoll_ctl failed "
743  "(errno = %d)!\n", errno_val);
744  return rv;
745  }
746 #endif
747 
748  printf ("\nSERVER: Waiting for a client to connect on port %d...\n", port);
749 
750  while (1)
751  {
752 #if ! SOCK_SERVER_USE_EPOLL
753  _rfdset = ssm->rd_fdset;
754 
755 #ifdef VCL_TEST
756  rv = vppcom_select (ssm->nfds, (unsigned long *) rfdset, NULL, NULL, 0);
757 #else
758  {
759  struct timeval timeout;
760  timeout = ssm->timeout;
761  _wfdset = ssm->wr_fdset;
762  rv = select (ssm->nfds, rfdset, wfdset, NULL, &timeout);
763  }
764 #endif
765  if (rv < 0)
766  {
767  perror ("select()");
768  fprintf (stderr, "\nSERVER: ERROR: select() failed -- aborting!\n");
769  main_rv = -1;
770  goto done;
771  }
772  else if (rv == 0)
773  continue;
774 
775  if (FD_ISSET (ssm->listen_fd, rfdset))
776  new_client ();
777 
778  for (i = 0; i < ssm->conn_pool_size; i++)
779  {
780  if (!ssm->conn_pool[i].is_alloc)
781  continue;
782 
783  conn = &ssm->conn_pool[i];
784 #else
785  int num_ev;
786 #ifdef VCL_TEST
787  num_ev = vppcom_epoll_wait (ssm->epfd, ssm->wait_events,
789  if (num_ev < 0)
790  errno = -num_ev;
791 #else
792  num_ev = epoll_wait (ssm->epfd, ssm->wait_events,
794 #endif
795  if (num_ev < 0)
796  {
797  perror ("epoll_wait()");
798  fprintf (stderr, "\nSERVER: ERROR: epoll_wait() "
799  "failed -- aborting!\n");
800  main_rv = -1;
801  goto done;
802  }
803  if (num_ev == 0)
804  {
805  fprintf (stderr, "\nSERVER: epoll_wait() timeout!\n");
806  continue;
807  }
808  for (i = 0; i < num_ev; i++)
809  {
810  conn = &ssm->conn_pool[ssm->wait_events[i].data.u32];
811  if (ssm->wait_events[i].events & (EPOLLHUP | EPOLLRDHUP))
812  {
813 #ifdef VCL_TEST
814  vppcom_session_close (conn->fd);
815 #else
816  close (conn->fd);
817 #endif
818  continue;
819  }
820  if (ssm->wait_events[i].data.u32 == ~0)
821  {
822  new_client ();
823  continue;
824  }
825 #if !defined (VCL_TEST)
826  else if (ssm->wait_events[i].data.u32 ==
828  {
829  af_unix_echo ();
830  continue;
831  }
832 #endif
833 #endif
834  client_fd = conn->fd;
835 
836 #if ! SOCK_SERVER_USE_EPOLL
837  if (FD_ISSET (client_fd, rfdset))
838 #else
839  if (EPOLLIN & ssm->wait_events[i].events)
840 #endif
841  {
842  read_again:
843  rx_bytes = sock_test_read (client_fd, conn->buf,
844  conn->buf_size, &conn->stats);
845  if (rx_bytes > 0)
846  {
847  rx_cfg = (vcl_test_cfg_t *) conn->buf;
848  if (rx_cfg->magic == VCL_TEST_CFG_CTRL_MAGIC)
849  {
850  if (rx_cfg->verbose)
851  {
852  printf ("SERVER (fd %d): Received a cfg message!\n",
853  client_fd);
854  vcl_test_cfg_dump (rx_cfg, 0 /* is_client */ );
855  }
856 
857  if (rx_bytes != sizeof (*rx_cfg))
858  {
859  printf ("SERVER (fd %d): Invalid cfg message "
860  "size (%d)!\n Should be %lu bytes.\n",
861  client_fd, rx_bytes, sizeof (*rx_cfg));
862  conn->cfg.rxbuf_size = 0;
863  conn->cfg.num_writes = 0;
864  if (conn->cfg.verbose)
865  {
866  printf ("SERVER (fd %d): Replying to "
867  "cfg message!\n", client_fd);
868  vcl_test_cfg_dump (rx_cfg, 0 /* is_client */ );
869  }
870  sock_test_write (client_fd, (uint8_t *) & conn->cfg,
871  sizeof (conn->cfg), NULL,
872  conn->cfg.verbose);
873  continue;
874  }
875 
876  switch (rx_cfg->test)
877  {
878  case VCL_TEST_TYPE_NONE:
879  case VCL_TEST_TYPE_ECHO:
880  sync_config_and_reply (conn, rx_cfg);
881  break;
882 
883  case VCL_TEST_TYPE_BI:
884  case VCL_TEST_TYPE_UNI:
885  stream_test_server_start_stop (conn, rx_cfg);
886  break;
887 
888  case VCL_TEST_TYPE_EXIT:
889  printf ("SERVER: Have a great day, "
890  "connection %d!\n", client_fd);
891 #ifdef VCL_TEST
892  vppcom_session_close (client_fd);
893 #else
894  close (client_fd);
895 #endif
896  conn_pool_free (conn);
897  printf ("SERVER: Closed client fd %d\n", client_fd);
898 #if ! SOCK_SERVER_USE_EPOLL
899  if (ssm->nfds == (ssm->listen_fd + 1))
900 #else
901  ssm->nfds--;
902  if (!ssm->nfds)
903 #endif
904  {
905  printf ("SERVER: All client connections "
906  "closed.\n\nSERVER: "
907  "May the force be with you!\n\n");
908  goto done;
909  }
910  break;
911 
912  default:
913  fprintf (stderr,
914  "SERVER: ERROR: Unknown test type!\n");
915  vcl_test_cfg_dump (rx_cfg, 0 /* is_client */ );
916  break;
917  }
918  continue;
919  }
920 
921  else if ((conn->cfg.test == VCL_TEST_TYPE_UNI) ||
922  (conn->cfg.test == VCL_TEST_TYPE_BI))
923  {
924  stream_test_server (conn, rx_bytes);
925  if (ioctl (conn->fd, FIONREAD))
926  goto read_again;
927  continue;
928  }
929 
930  else if (isascii (conn->buf[0]))
931  {
932  // If it looks vaguely like a string, make sure it's terminated
933  ((char *) conn->buf)[rx_bytes <
934  conn->buf_size ? rx_bytes :
935  conn->buf_size - 1] = 0;
936  printf ("SERVER (fd %d): RX (%d bytes) - '%s'\n",
937  conn->fd, rx_bytes, conn->buf);
938  }
939  }
940  else // rx_bytes < 0
941  {
942  if (errno == ECONNRESET)
943  {
944  printf ("\nSERVER: Connection reset by remote peer.\n"
945  " Y'all have a great day now!\n\n");
946  break;
947  }
948  else
949  continue;
950  }
951 
952  if (isascii (conn->buf[0]))
953  {
954  /* If it looks vaguely like a string,
955  * make sure it's terminated
956  */
957  ((char *) conn->buf)[rx_bytes <
958  conn->buf_size ? rx_bytes :
959  conn->buf_size - 1] = 0;
960  if (xtra)
961  fprintf (stderr, "SERVER: ERROR: "
962  "FIFO not drained in previous test!\n"
963  " extra chunks %u (0x%x)\n"
964  " extra bytes %lu (0x%lx)\n",
965  xtra, xtra, xtra_bytes, xtra_bytes);
966 
967  xtra = 0;
968  xtra_bytes = 0;
969 
970  if (conn->cfg.verbose)
971  printf ("SERVER (fd %d): Echoing back\n", client_fd);
972 
973  nbytes = strlen ((const char *) conn->buf) + 1;
974 
975  tx_bytes = sock_test_write (client_fd, conn->buf,
976  nbytes, &conn->stats,
977  conn->cfg.verbose);
978  if (tx_bytes >= 0)
979  printf ("SERVER (fd %d): TX (%d bytes) - '%s'\n",
980  conn->fd, tx_bytes, conn->buf);
981  }
982 
983  else // Extraneous read data from non-echo tests???
984  {
985  xtra++;
986  xtra_bytes += rx_bytes;
987  }
988  }
989  }
990  }
991 
992 done:
993 #ifdef VCL_TEST
994  vppcom_session_close (ssm->listen_fd);
995  vppcom_app_destroy ();
996 #else
997  close (ssm->listen_fd);
998 
999 #if SOCK_SERVER_USE_EPOLL && !defined (VCL_TEST)
1000  close (ssm->af_unix_listen_fd);
1001  unlink ((const char *) SOCK_TEST_AF_UNIX_FILENAME);
1002 #endif /* SOCK_SERVER_USE_EPOLL */
1003 
1004 #endif
1005  if (ssm->conn_pool)
1006  free (ssm->conn_pool);
1007 
1008  return main_rv;
1009 }
1010 
1011 /*
1012  * fd.io coding-style-patch-verification: ON
1013  *
1014  * Local Variables:
1015  * eval: (c-set-style "gnu")
1016  * End:
1017  */
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)
u32 flags
Definition: vhost_user.h:141
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.
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
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:489
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