FD.io VPP  v20.09-64-g4f7b92f0a
Vector Packet Processing
sock_test_client.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 <stdlib.h>
19 #include <ctype.h>
20 #include <sys/types.h>
21 #include <sys/socket.h>
22 #include <stdio.h>
23 #include <time.h>
24 #include <arpa/inet.h>
25 #include <hs_apps/vcl/sock_test.h>
26 #include <fcntl.h>
27 #include <sys/un.h>
28 
29 typedef struct
30 {
33  struct sockaddr_storage server_addr;
34  uint32_t server_addr_size;
35  uint32_t cfg_seq_num;
38  uint32_t num_test_sockets;
39  uint8_t dump_cfg;
41 
43 
44 static int
46 {
48  vcl_test_session_t *ctrl = &scm->ctrl_socket;
49  vcl_test_cfg_t *rl_cfg = (vcl_test_cfg_t *) socket->rxbuf;
50  int rx_bytes, tx_bytes;
51 
52  if (socket->cfg.verbose)
53  vcl_test_cfg_dump (&socket->cfg, 1 /* is_client */ );
54 
55  ctrl->cfg.seq_num = ++scm->cfg_seq_num;
56  if (socket->cfg.verbose)
57  {
58  printf ("CLIENT (fd %d): Sending config sent to server.\n", socket->fd);
59  vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
60  }
61  tx_bytes = sock_test_write (socket->fd, (uint8_t *) & ctrl->cfg,
62  sizeof (ctrl->cfg), NULL, ctrl->cfg.verbose);
63  if (tx_bytes < 0)
64  {
65  fprintf (stderr, "CLIENT (fd %d): ERROR: write test cfg failed (%d)!\n",
66  socket->fd, tx_bytes);
67  return tx_bytes;
68  }
69 
70  rx_bytes = sock_test_read (socket->fd, (uint8_t *) socket->rxbuf,
71  sizeof (vcl_test_cfg_t), NULL);
72  if (rx_bytes < 0)
73  return rx_bytes;
74 
75  if (rl_cfg->magic != VCL_TEST_CFG_CTRL_MAGIC)
76  {
77  fprintf (stderr, "CLIENT (fd %d): ERROR: Bad server reply cfg "
78  "-- aborting!\n", socket->fd);
79  return -1;
80  }
81  if ((rx_bytes != sizeof (vcl_test_cfg_t))
82  || !vcl_test_cfg_verify (rl_cfg, &ctrl->cfg))
83  {
84  fprintf (stderr, "CLIENT (fd %d): ERROR: Invalid config received "
85  "from server!\n", socket->fd);
86  if (rx_bytes != sizeof (vcl_test_cfg_t))
87  {
88  fprintf (stderr, "\tRx bytes %d != cfg size %lu\n",
89  rx_bytes, sizeof (vcl_test_cfg_t));
90  }
91  else
92  {
93  vcl_test_cfg_dump (rl_cfg, 1 /* is_client */ );
94  fprintf (stderr, "CLIENT (fd %d): Valid config sent to server.\n",
95  socket->fd);
96  vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
97  }
98  return -1;
99  }
100  else if (socket->cfg.verbose)
101  {
102  printf ("CLIENT (fd %d): Got config back from server.\n", socket->fd);
103  vcl_test_cfg_dump (rl_cfg, 1 /* is_client */ );
104  }
105  ctrl->cfg.ctrl_handle = ((ctrl->cfg.ctrl_handle == ~0) ?
106  rl_cfg->ctrl_handle : ctrl->cfg.ctrl_handle);
107 
108  return 0;
109 }
110 
111 static void
113 {
114  int fd, errno_val;
115  struct sockaddr_un serveraddr;
116  uint8_t buffer[256];
117  size_t nbytes = strlen (SOCK_TEST_MIXED_EPOLL_DATA) + 1;
118  struct timeval timeout;
119  int rv;
120 
121  /* Open AF_UNIX socket and send an echo to test mixed epoll on server.
122  */
123  fd = socket (AF_UNIX, SOCK_STREAM, 0);
124  if (fd < 0)
125  {
126  errno_val = errno;
127  perror ("ERROR in echo_test_client(): socket(AF_UNIX) failed");
128  fprintf (stderr,
129  "CLIENT: ERROR: socket(AF_UNIX, SOCK_STREAM, 0) failed "
130  "(errno = %d)!\n", errno_val);
131  goto out;
132  }
133  memset (&serveraddr, 0, sizeof (serveraddr));
134  serveraddr.sun_family = AF_UNIX;
135  strncpy (serveraddr.sun_path, SOCK_TEST_AF_UNIX_FILENAME,
136  sizeof (serveraddr.sun_path));
137  rv = connect (fd, (struct sockaddr *) &serveraddr, SUN_LEN (&serveraddr));
138  if (rv < 0)
139  {
140  errno_val = errno;
141  perror ("ERROR in echo_test_client(): connect() failed");
142  fprintf (stderr, "CLIENT: ERROR: connect(fd %d, \"%s\", %lu) "
143  "failed (errno = %d)!\n", fd, SOCK_TEST_AF_UNIX_FILENAME,
144  SUN_LEN (&serveraddr), errno_val);
145  goto done;
146  }
147 
148  scm->af_unix_echo_tx++;
149  strncpy ((char *) buffer, SOCK_TEST_MIXED_EPOLL_DATA, sizeof (buffer));
150  timeout.tv_sec = 0;
151  timeout.tv_usec = 250000;
152  select (0, NULL, NULL, NULL, &timeout); /* delay .25 secs */
153  rv = write (fd, buffer, nbytes);
154  if (rv < 0)
155  {
156  errno_val = errno;
157  perror ("ERROR in echo_test_client(): write() failed");
158  fprintf (stderr, "CLIENT: ERROR: write(fd %d, \"%s\", %lu) "
159  "failed (errno = %d)!\n", fd, buffer, nbytes, errno_val);
160  goto done;
161  }
162  else if (rv < nbytes)
163  {
164  fprintf (stderr, "CLIENT: ERROR: write(fd %d, \"%s\", %lu) "
165  "returned %d!\n", fd, buffer, nbytes, rv);
166  goto done;
167  }
168 
169  printf ("CLIENT (AF_UNIX): TX (%d bytes) - '%s'\n", rv, buffer);
170  memset (buffer, 0, sizeof (buffer));
171  rv = read (fd, buffer, nbytes);
172  if (rv < 0)
173  {
174  errno_val = errno;
175  perror ("ERROR in echo_test_client(): read() failed");
176  fprintf (stderr, "CLIENT: ERROR: read(fd %d, %p, %lu) "
177  "failed (errno = %d)!\n", fd, buffer, nbytes, errno_val);
178  goto done;
179  }
180  else if (rv < nbytes)
181  {
182  fprintf (stderr, "CLIENT: ERROR: read(fd %d, %p, %lu) "
183  "returned %d!\n", fd, buffer, nbytes, rv);
184  goto done;
185  }
186 
187  if (!strncmp (SOCK_TEST_MIXED_EPOLL_DATA, (const char *) buffer, nbytes))
188  {
189  printf ("CLIENT (AF_UNIX): RX (%d bytes) - '%s'\n", rv, buffer);
190  scm->af_unix_echo_rx++;
191  }
192  else
193  printf ("CLIENT (AF_UNIX): ERROR: RX (%d bytes) - '%s'\n", rv, buffer);
194 
195 done:
196  close (fd);
197 out:
198  ;
199 }
200 
201 static void
203 {
205  vcl_test_session_t *ctrl = &scm->ctrl_socket;
206  vcl_test_session_t *tsock;
207  int rx_bytes, tx_bytes, nbytes;
208  uint32_t i, n;
209  int rv;
210  int nfds = 0;
211  fd_set wr_fdset, rd_fdset;
212  fd_set _wfdset, *wfdset = &_wfdset;
213  fd_set _rfdset, *rfdset = &_rfdset;
214 
215  FD_ZERO (&wr_fdset);
216  FD_ZERO (&rd_fdset);
217  memset (&ctrl->stats, 0, sizeof (ctrl->stats));
218  ctrl->cfg.total_bytes = nbytes = strlen (ctrl->txbuf) + 1;
219  for (n = 0; n != ctrl->cfg.num_test_sessions; n++)
220  {
221  tsock = &scm->test_socket[n];
222  tsock->cfg = ctrl->cfg;
224  if (sock_test_cfg_sync (tsock))
225  return;
226 
227  memcpy (tsock->txbuf, ctrl->txbuf, nbytes);
228  memset (&tsock->stats, 0, sizeof (tsock->stats));
229 
230  FD_SET (tsock->fd, &wr_fdset);
231  FD_SET (tsock->fd, &rd_fdset);
232  nfds = ((tsock->fd + 1) > nfds) ? (tsock->fd + 1) : nfds;
233  }
234 
235  nfds++;
236  clock_gettime (CLOCK_REALTIME, &ctrl->stats.start);
237  while (n)
238  {
239  _wfdset = wr_fdset;
240  _rfdset = rd_fdset;
241 
242  struct timeval timeout;
243  timeout.tv_sec = 0;
244  timeout.tv_usec = 0;
245  rv = select (nfds, rfdset, wfdset, NULL, &timeout);
246 
247  if (rv < 0)
248  {
249  perror ("select()");
250  fprintf (stderr, "\nCLIENT: ERROR: select() failed -- "
251  "aborting test!\n");
252  return;
253  }
254  else if (rv == 0)
255  continue;
256 
257  for (i = 0; i < ctrl->cfg.num_test_sessions; i++)
258  {
259  tsock = &scm->test_socket[i];
260  if (!((tsock->stats.stop.tv_sec == 0) &&
261  (tsock->stats.stop.tv_nsec == 0)))
262  continue;
263 
264  if (FD_ISSET (tsock->fd, wfdset) &&
265  (tsock->stats.tx_bytes < ctrl->cfg.total_bytes))
266 
267  {
268  tx_bytes =
269  sock_test_write (tsock->fd, (uint8_t *) tsock->txbuf, nbytes,
270  &tsock->stats, ctrl->cfg.verbose);
271  if (tx_bytes < 0)
272  {
273  fprintf (stderr, "\nCLIENT: ERROR: sock_test_write(%d) "
274  "failed -- aborting test!\n", tsock->fd);
275  return;
276  }
277 
278  printf ("CLIENT (fd %d): TX (%d bytes) - '%s'\n",
279  tsock->fd, tx_bytes, tsock->txbuf);
280  }
281 
282  if ((FD_ISSET (tsock->fd, rfdset)) &&
283  (tsock->stats.rx_bytes < ctrl->cfg.total_bytes))
284  {
285  rx_bytes =
286  sock_test_read (tsock->fd, (uint8_t *) tsock->rxbuf,
287  nbytes, &tsock->stats);
288  if (rx_bytes > 0)
289  {
290  printf ("CLIENT (fd %d): RX (%d bytes)\n", tsock->fd,
291  rx_bytes);
292 
293  if (tsock->stats.rx_bytes != tsock->stats.tx_bytes)
294  printf ("CLIENT: WARNING: bytes read (%lu) "
295  "!= bytes written (%lu)!\n",
296  tsock->stats.rx_bytes, tsock->stats.tx_bytes);
297  }
298  }
299 
300  if (tsock->stats.rx_bytes >= ctrl->cfg.total_bytes)
301  {
302  clock_gettime (CLOCK_REALTIME, &tsock->stats.stop);
303  n--;
304  }
305  }
306  }
307  clock_gettime (CLOCK_REALTIME, &ctrl->stats.stop);
308 
310 
311  for (i = 0; i < ctrl->cfg.num_test_sessions; i++)
312  {
313  tsock = &scm->test_socket[i];
314  tsock->stats.start = ctrl->stats.start;
315 
316  if (ctrl->cfg.verbose)
317  {
318  static char buf[64];
319 
320  snprintf (buf, sizeof (buf), "CLIENT (fd %d) RESULTS", tsock->fd);
321  vcl_test_stats_dump (buf, &tsock->stats,
322  1 /* show_rx */ , 1 /* show tx */ ,
323  ctrl->cfg.verbose);
324  }
325 
326  vcl_test_stats_accumulate (&ctrl->stats, &tsock->stats);
327  }
328 
329  if (ctrl->cfg.verbose)
330  {
331  vcl_test_stats_dump ("CLIENT RESULTS", &ctrl->stats,
332  1 /* show_rx */ , 1 /* show tx */ ,
333  ctrl->cfg.verbose);
334  vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
335 
336  if (ctrl->cfg.verbose > 1)
337  {
338  printf (" ctrl socket info\n"
340  " fd: %d (0x%08x)\n"
341  " rxbuf: %p\n"
342  " rxbuf size: %u (0x%08x)\n"
343  " txbuf: %p\n"
344  " txbuf size: %u (0x%08x)\n"
346  ctrl->fd, (uint32_t) ctrl->fd,
347  ctrl->rxbuf, ctrl->rxbuf_size, ctrl->rxbuf_size,
348  ctrl->txbuf, ctrl->txbuf_size, ctrl->txbuf_size);
349  }
350  }
351 }
352 
353 static void
355 {
357  vcl_test_session_t *ctrl = &scm->ctrl_socket;
358  vcl_test_session_t *tsock;
359  int tx_bytes;
360  uint32_t i, n;
361  int rv;
362  int nfds = 0;
363  fd_set wr_fdset, rd_fdset;
364  fd_set _wfdset, *wfdset = &_wfdset;
365  fd_set _rfdset, *rfdset = (test == VCL_TEST_TYPE_BI) ? &_rfdset : 0;
366 
367  ctrl->cfg.total_bytes = ctrl->cfg.num_writes * ctrl->cfg.txbuf_size;
368  ctrl->cfg.ctrl_handle = ~0;
369 
370  printf ("\n" SOCK_TEST_BANNER_STRING
371  "CLIENT (fd %d): %s-directional Stream Test!\n\n"
372  "CLIENT (fd %d): Sending config to server on ctrl socket...\n",
373  ctrl->fd, test == VCL_TEST_TYPE_BI ? "Bi" : "Uni", ctrl->fd);
374 
375  if (sock_test_cfg_sync (ctrl))
376  {
377  fprintf (stderr, "CLIENT: ERROR: test cfg sync failed -- aborting!");
378  return;
379  }
380 
381  FD_ZERO (&wr_fdset);
382  FD_ZERO (&rd_fdset);
383  memset (&ctrl->stats, 0, sizeof (ctrl->stats));
384  for (n = 0; n != ctrl->cfg.num_test_sessions; n++)
385  {
386  tsock = &scm->test_socket[n];
387  tsock->cfg = ctrl->cfg;
389  printf ("CLIENT (fd %d): Sending config to server on "
390  "test socket %d...\n", tsock->fd, n);
391  sock_test_cfg_sync (tsock);
392 
393  /* Fill payload with incrementing uint32's */
394  for (i = 0; i < tsock->txbuf_size; i++)
395  tsock->txbuf[i] = i & 0xff;
396 
397  memset (&tsock->stats, 0, sizeof (tsock->stats));
398  FD_SET (tsock->fd, &wr_fdset);
399  FD_SET (tsock->fd, &rd_fdset);
400  nfds = ((tsock->fd + 1) > nfds) ? (tsock->fd + 1) : nfds;
401  }
402 
403  nfds++;
404  clock_gettime (CLOCK_REALTIME, &ctrl->stats.start);
405  while (n)
406  {
407  _wfdset = wr_fdset;
408  _rfdset = rd_fdset;
409 
410  struct timeval timeout;
411  timeout.tv_sec = 0;
412  timeout.tv_usec = 0;
413  rv = select (nfds, rfdset, wfdset, NULL, &timeout);
414 
415  if (rv < 0)
416  {
417  perror ("select()");
418  fprintf (stderr, "\nCLIENT: ERROR: select() failed -- "
419  "aborting test!\n");
420  return;
421  }
422  else if (rv == 0)
423  continue;
424 
425  for (i = 0; i < ctrl->cfg.num_test_sessions; i++)
426  {
427  tsock = &scm->test_socket[i];
428  if (!((tsock->stats.stop.tv_sec == 0) &&
429  (tsock->stats.stop.tv_nsec == 0)))
430  continue;
431 
432  if ((test == VCL_TEST_TYPE_BI) &&
433  FD_ISSET (tsock->fd, rfdset) &&
434  (tsock->stats.rx_bytes < ctrl->cfg.total_bytes))
435  {
436  (void) sock_test_read (tsock->fd,
437  (uint8_t *) tsock->rxbuf,
438  tsock->rxbuf_size, &tsock->stats);
439  }
440 
441  if (FD_ISSET (tsock->fd, wfdset) &&
442  (tsock->stats.tx_bytes < ctrl->cfg.total_bytes))
443  {
444  tx_bytes = sock_test_write (tsock->fd, (uint8_t *) tsock->txbuf,
445  ctrl->cfg.txbuf_size, &tsock->stats,
446  ctrl->cfg.verbose);
447  if (tx_bytes < 0)
448  {
449  fprintf (stderr, "\nCLIENT: ERROR: sock_test_write(%d) "
450  "failed -- aborting test!\n", tsock->fd);
451  return;
452  }
453  }
454 
455  if (((test == VCL_TEST_TYPE_UNI) &&
456  (tsock->stats.tx_bytes >= ctrl->cfg.total_bytes)) ||
457  ((test == VCL_TEST_TYPE_BI) &&
458  (tsock->stats.rx_bytes >= ctrl->cfg.total_bytes)))
459  {
460  clock_gettime (CLOCK_REALTIME, &tsock->stats.stop);
461  n--;
462  }
463  }
464  }
465  clock_gettime (CLOCK_REALTIME, &ctrl->stats.stop);
466 
467  printf ("CLIENT (fd %d): Sending config to server on ctrl socket...\n",
468  ctrl->fd);
469 
470  if (sock_test_cfg_sync (ctrl))
471  {
472  fprintf (stderr, "CLIENT: ERROR: test cfg sync failed -- aborting!");
473  return;
474  }
475 
476  for (i = 0; i < ctrl->cfg.num_test_sessions; i++)
477  {
478  tsock = &scm->test_socket[i];
479 
480  if (ctrl->cfg.verbose)
481  {
482  static char buf[64];
483 
484  snprintf (buf, sizeof (buf), "CLIENT (fd %d) RESULTS", tsock->fd);
485  vcl_test_stats_dump (buf, &tsock->stats,
486  test == VCL_TEST_TYPE_BI /* show_rx */ ,
487  1 /* show tx */ , ctrl->cfg.verbose);
488  }
489 
490  vcl_test_stats_accumulate (&ctrl->stats, &tsock->stats);
491  }
492 
493  vcl_test_stats_dump ("CLIENT RESULTS", &ctrl->stats,
494  test == VCL_TEST_TYPE_BI /* show_rx */ ,
495  1 /* show tx */ , ctrl->cfg.verbose);
496  vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
497 
498  if (ctrl->cfg.verbose)
499  {
500  printf (" ctrl socket info\n"
502  " fd: %d (0x%08x)\n"
503  " rxbuf: %p\n"
504  " rxbuf size: %u (0x%08x)\n"
505  " txbuf: %p\n"
506  " txbuf size: %u (0x%08x)\n"
508  ctrl->fd, (uint32_t) ctrl->fd,
509  ctrl->rxbuf, ctrl->rxbuf_size, ctrl->rxbuf_size,
510  ctrl->txbuf, ctrl->txbuf_size, ctrl->txbuf_size);
511  }
512 
513  ctrl->cfg.test = VCL_TEST_TYPE_ECHO;
514  if (sock_test_cfg_sync (ctrl))
515  fprintf (stderr, "CLIENT: ERROR: post-test cfg sync failed!");
516 
517  printf ("CLIENT (fd %d): %s-directional Stream Test Complete!\n"
518  SOCK_TEST_BANNER_STRING "\n", ctrl->fd,
519  test == VCL_TEST_TYPE_BI ? "Bi" : "Uni");
520 }
521 
522 static void
524 {
526  vcl_test_session_t *ctrl = &scm->ctrl_socket;
527  vcl_test_session_t *tsock;
528  int i;
529 
530  printf ("CLIENT: af_unix_echo_tx %d, af_unix_echo_rx %d\n",
531  scm->af_unix_echo_tx, scm->af_unix_echo_rx);
532  for (i = 0; i < ctrl->cfg.num_test_sessions; i++)
533  {
534  tsock = &scm->test_socket[i];
535  tsock->cfg.test = VCL_TEST_TYPE_EXIT;
536 
537  /* coverity[COPY_PASTE_ERROR] */
538  if (ctrl->cfg.verbose)
539  {
540  printf ("\nCLIENT (fd %d): Sending exit cfg to server...\n",
541  tsock->fd);
542  vcl_test_cfg_dump (&tsock->cfg, 1 /* is_client */ );
543  }
544  (void) sock_test_write (tsock->fd, (uint8_t *) & tsock->cfg,
545  sizeof (tsock->cfg), &tsock->stats,
546  ctrl->cfg.verbose);
547  }
548 
549  ctrl->cfg.test = VCL_TEST_TYPE_EXIT;
550  if (ctrl->cfg.verbose)
551  {
552  printf ("\nCLIENT (fd %d): Sending exit cfg to server...\n", ctrl->fd);
553  vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
554  }
555  (void) sock_test_write (ctrl->fd, (uint8_t *) & ctrl->cfg,
556  sizeof (ctrl->cfg), &ctrl->stats,
557  ctrl->cfg.verbose);
558  printf ("\nCLIENT: So long and thanks for all the fish!\n\n");
559  sleep (1);
560 }
561 
562 static int
563 sock_test_connect_test_sockets (uint32_t num_test_sockets)
564 {
566  vcl_test_session_t *ctrl = &scm->ctrl_socket;
567  vcl_test_session_t *tsock;
568  int i, rv, errno_val;
569 
570  if (num_test_sockets < 1)
571  {
572  errno = EINVAL;
573  return -1;
574  }
575 
576  if (num_test_sockets < scm->num_test_sockets)
577  {
578  for (i = scm->num_test_sockets - 1; i >= num_test_sockets; i--)
579  {
580  tsock = &scm->test_socket[i];
581  close (tsock->fd);
582  free (tsock->txbuf);
583  free (tsock->rxbuf);
584  }
585  }
586 
587  else if (num_test_sockets > scm->num_test_sockets)
588  {
589  tsock = realloc (scm->test_socket,
590  sizeof (vcl_test_session_t) * num_test_sockets);
591  if (!tsock)
592  {
593  errno_val = errno;
594  perror ("ERROR in sock_test_connect_test_sockets()");
595  fprintf (stderr, "CLIENT: ERROR: socket failed (errno = %d)!\n",
596  errno_val);
597  return -1;
598  }
599 
600  memset (&tsock[scm->num_test_sockets], 0,
601  sizeof (vcl_test_session_t) * (num_test_sockets -
602  scm->num_test_sockets));
603 
604  scm->test_socket = tsock;
605  for (i = scm->num_test_sockets; i < num_test_sockets; i++)
606  {
607  tsock = &scm->test_socket[i];
608  tsock->fd = socket (ctrl->cfg.address_ip6 ? AF_INET6 : AF_INET,
609  ctrl->cfg.transport_udp ?
610  SOCK_DGRAM : SOCK_STREAM, 0);
611 
612  if (tsock->fd < 0)
613  {
614  errno_val = errno;
615  perror ("ERROR in sock_test_connect_test_sockets()");
616  fprintf (stderr, "CLIENT: ERROR: socket failed (errno = %d)!\n",
617  errno_val);
618  return tsock->fd;
619  }
620 
621  rv = connect (tsock->fd, (struct sockaddr *) &scm->server_addr,
622  scm->server_addr_size);
623 
624  if (rv < 0)
625  {
626  errno_val = errno;
627  perror ("ERROR in sock_test_connect_test_sockets()");
628  fprintf (stderr, "CLIENT: ERROR: connect failed "
629  "(errno = %d)!\n", errno_val);
630  return -1;
631  }
632  if (fcntl (tsock->fd, F_SETFL, O_NONBLOCK) < 0)
633  {
634  errno_val = errno;
635  perror ("ERROR in sock_test_connect_test_sockets()");
636  fprintf (stderr, "CLIENT: ERROR: fcntl failed (errno = %d)!\n",
637  errno_val);
638  return -1;
639  }
640  tsock->cfg = ctrl->cfg;
642  sock_test_cfg_sync (tsock);
643 
644  printf ("CLIENT (fd %d): Test socket %d connected.\n",
645  tsock->fd, i);
646  }
647  }
648 
649  scm->num_test_sockets = num_test_sockets;
650  printf ("CLIENT: All sockets (%d) connected!\n", scm->num_test_sockets + 1);
651  return 0;
652 }
653 
654 static void
656 {
658  vcl_test_session_t *ctrl = &scm->ctrl_socket;
659  char *p = ctrl->txbuf + strlen (VCL_TEST_TOKEN_TXBUF_SIZE);
660  uint64_t txbuf_size = strtoull ((const char *) p, NULL, 10);
661 
662  if (txbuf_size >= VCL_TEST_CFG_BUF_SIZE_MIN)
663  {
664  ctrl->cfg.txbuf_size = txbuf_size;
665  ctrl->cfg.total_bytes = ctrl->cfg.num_writes * ctrl->cfg.txbuf_size;
666  vcl_test_buf_alloc (&ctrl->cfg, 0 /* is_rxbuf */ ,
667  (uint8_t **) & ctrl->txbuf, &ctrl->txbuf_size);
668  vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
669  }
670  else
671  fprintf (stderr, "CLIENT: ERROR: Invalid txbuf size (%lu) < "
672  "minimum buf size (%u)!\n",
673  txbuf_size, VCL_TEST_CFG_BUF_SIZE_MIN);
674 }
675 
676 static void
678 {
680  vcl_test_session_t *ctrl = &scm->ctrl_socket;
681  char *p = ctrl->txbuf + strlen (VCL_TEST_TOKEN_NUM_WRITES);
682  uint32_t num_writes = strtoul ((const char *) p, NULL, 10);
683 
684  if (num_writes > 0)
685  {
686  ctrl->cfg.num_writes = num_writes;
687  ctrl->cfg.total_bytes = ctrl->cfg.num_writes * ctrl->cfg.txbuf_size;
688  vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
689  }
690  else
691  {
692  fprintf (stderr, "CLIENT: ERROR: invalid num writes: %u\n", num_writes);
693  }
694 }
695 
696 static void
698 {
700  vcl_test_session_t *ctrl = &scm->ctrl_socket;
701  char *p = ctrl->txbuf + strlen (VCL_TEST_TOKEN_NUM_TEST_SESS);
702  uint32_t num_test_sockets = strtoul ((const char *) p, NULL, 10);
703 
704  if ((num_test_sockets > 0) &&
705  (num_test_sockets <= VCL_TEST_CFG_MAX_TEST_SESS))
706  {
707  ctrl->cfg.num_test_sessions = num_test_sockets;
708  sock_test_connect_test_sockets (num_test_sockets);
709 
710  vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
711  }
712  else
713  {
714  fprintf (stderr, "CLIENT: ERROR: invalid num test sockets: "
715  "%u, (%d max)\n",
716  num_test_sockets, VCL_TEST_CFG_MAX_TEST_SESS);
717  }
718 }
719 
720 static void
722 {
724  vcl_test_session_t *ctrl = &scm->ctrl_socket;
725  char *p = ctrl->txbuf + strlen (VCL_TEST_TOKEN_RXBUF_SIZE);
726  uint64_t rxbuf_size = strtoull ((const char *) p, NULL, 10);
727 
728  if (rxbuf_size >= VCL_TEST_CFG_BUF_SIZE_MIN)
729  {
730  ctrl->cfg.rxbuf_size = rxbuf_size;
731  vcl_test_buf_alloc (&ctrl->cfg, 1 /* is_rxbuf */ ,
732  (uint8_t **) & ctrl->rxbuf, &ctrl->rxbuf_size);
733  vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
734  }
735  else
736  fprintf (stderr, "CLIENT: ERROR: Invalid rxbuf size (%lu) < "
737  "minimum buf size (%u)!\n",
738  rxbuf_size, VCL_TEST_CFG_BUF_SIZE_MIN);
739 }
740 
741 static void
743 {
745  vcl_test_session_t *ctrl = &scm->ctrl_socket;
746 
747  ctrl->cfg.verbose = ctrl->cfg.verbose ? 0 : 1;
748  vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
749 
750 }
751 
752 static vcl_test_t
754 {
756  vcl_test_session_t *ctrl = &scm->ctrl_socket;
758 
759  if (!strncmp (VCL_TEST_TOKEN_EXIT, ctrl->txbuf,
760  strlen (VCL_TEST_TOKEN_EXIT)))
761  rv = VCL_TEST_TYPE_EXIT;
762 
763  else if (!strncmp (VCL_TEST_TOKEN_HELP, ctrl->txbuf,
764  strlen (VCL_TEST_TOKEN_HELP)))
765  dump_help ();
766 
767  else if (!strncmp (VCL_TEST_TOKEN_SHOW_CFG, ctrl->txbuf,
768  strlen (VCL_TEST_TOKEN_SHOW_CFG)))
769  scm->dump_cfg = 1;
770 
771  else if (!strncmp (VCL_TEST_TOKEN_VERBOSE, ctrl->txbuf,
772  strlen (VCL_TEST_TOKEN_VERBOSE)))
774 
775  else if (!strncmp (VCL_TEST_TOKEN_TXBUF_SIZE, ctrl->txbuf,
776  strlen (VCL_TEST_TOKEN_TXBUF_SIZE)))
778 
779  else if (!strncmp (VCL_TEST_TOKEN_NUM_TEST_SESS, ctrl->txbuf,
782 
783  else if (!strncmp (VCL_TEST_TOKEN_NUM_WRITES, ctrl->txbuf,
784  strlen (VCL_TEST_TOKEN_NUM_WRITES)))
786 
787  else if (!strncmp (VCL_TEST_TOKEN_RXBUF_SIZE, ctrl->txbuf,
788  strlen (VCL_TEST_TOKEN_RXBUF_SIZE)))
790 
791  else if (!strncmp (VCL_TEST_TOKEN_RUN_UNI, ctrl->txbuf,
792  strlen (VCL_TEST_TOKEN_RUN_UNI)))
793  rv = ctrl->cfg.test = VCL_TEST_TYPE_UNI;
794 
795  else if (!strncmp (VCL_TEST_TOKEN_RUN_BI, ctrl->txbuf,
796  strlen (VCL_TEST_TOKEN_RUN_BI)))
797  rv = ctrl->cfg.test = VCL_TEST_TYPE_BI;
798 
799  else
800  rv = VCL_TEST_TYPE_ECHO;
801 
802  return rv;
803 }
804 
805 void
807 {
808  fprintf (stderr,
809  "sock_test_client [OPTIONS] <ipaddr> <port>\n"
810  " OPTIONS\n"
811  " -h Print this message and exit.\n"
812  " -6 Use IPv6\n"
813  " -u Use UDP transport layer\n"
814  " -c Print test config before test.\n"
815  " -w <dir> Write test results to <dir>.\n"
816  " -X Exit after running test.\n"
817  " -E Run Echo test.\n"
818  " -N <num-writes> Test Cfg: number of writes.\n"
819  " -R <rxbuf-size> Test Cfg: rx buffer size.\n"
820  " -T <txbuf-size> Test Cfg: tx buffer size.\n"
821  " -U Run Uni-directional test.\n"
822  " -B Run Bi-directional test.\n"
823  " -V Verbose mode.\n");
824  exit (1);
825 }
826 
827 int
828 main (int argc, char **argv)
829 {
831  vcl_test_session_t *ctrl = &scm->ctrl_socket;
832  int c, rv, errno_val;
833  vcl_test_t post_test = VCL_TEST_TYPE_NONE;
834 
835  vcl_test_cfg_init (&ctrl->cfg);
837 
838  opterr = 0;
839  while ((c = getopt (argc, argv, "chn:w:XE:I:N:R:T:UBV6D")) != -1)
840  switch (c)
841  {
842  case 'c':
843  scm->dump_cfg = 1;
844  break;
845 
846  case 's':
847  if (sscanf (optarg, "0x%x", &ctrl->cfg.num_test_sessions) != 1)
848  if (sscanf (optarg, "%u", &ctrl->cfg.num_test_sessions) != 1)
849  {
850  fprintf (stderr, "CLIENT: ERROR: Invalid value for "
851  "option -%c!\n", c);
853  }
854  if (!ctrl->cfg.num_test_sessions ||
855  (ctrl->cfg.num_test_sessions > FD_SETSIZE))
856  {
857  fprintf (stderr, "CLIENT: ERROR: Invalid number of "
858  "sockets (%d) specified for option -%c!\n"
859  " Valid range is 1 - %d\n",
860  ctrl->cfg.num_test_sessions, c, FD_SETSIZE);
862  }
863  break;
864 
865  case 'w':
866  fprintf (stderr, "CLIENT: Writing test results to files is TBD.\n");
867  break;
868 
869  case 'X':
870  post_test = VCL_TEST_TYPE_EXIT;
871  break;
872 
873  case 'E':
874  if (strlen (optarg) > ctrl->txbuf_size)
875  {
876  fprintf (stderr, "CLIENT: ERROR: Option -%c value "
877  "larger than txbuf size (%d)!\n",
878  optopt, ctrl->txbuf_size);
880  }
881  strncpy (ctrl->txbuf, optarg, ctrl->txbuf_size);
882  ctrl->cfg.test = VCL_TEST_TYPE_ECHO;
883  break;
884 
885  case 'I':
886  if (sscanf (optarg, "0x%x", &ctrl->cfg.num_test_sessions) != 1)
887  if (sscanf (optarg, "%d", &ctrl->cfg.num_test_sessions) != 1)
888  {
889  fprintf (stderr, "CLIENT: ERROR: Invalid value for "
890  "option -%c!\n", c);
892  }
894  {
895  fprintf (stderr, "CLIENT: ERROR: value greater than max "
896  "number test sockets (%d)!", VCL_TEST_CFG_MAX_TEST_SESS);
898  }
899  break;
900 
901  case 'N':
902  if (sscanf (optarg, "0x%lx", &ctrl->cfg.num_writes) != 1)
903  if (sscanf (optarg, "%ld", &ctrl->cfg.num_writes) != 1)
904  {
905  fprintf (stderr, "CLIENT: ERROR: Invalid value for "
906  "option -%c!\n", c);
908  }
909  ctrl->cfg.total_bytes = ctrl->cfg.num_writes * ctrl->cfg.txbuf_size;
910  break;
911 
912  case 'R':
913  if (sscanf (optarg, "0x%lx", &ctrl->cfg.rxbuf_size) != 1)
914  if (sscanf (optarg, "%ld", &ctrl->cfg.rxbuf_size) != 1)
915  {
916  fprintf (stderr, "CLIENT: ERROR: Invalid value for "
917  "option -%c!\n", c);
919  }
921  {
922  ctrl->rxbuf_size = ctrl->cfg.rxbuf_size;
923  vcl_test_buf_alloc (&ctrl->cfg, 1 /* is_rxbuf */ ,
924  (uint8_t **) & ctrl->rxbuf,
925  &ctrl->rxbuf_size);
926  }
927  else
928  {
929  fprintf (stderr, "CLIENT: ERROR: rxbuf size (%lu) "
930  "less than minumum (%u)\n",
933  }
934 
935  break;
936 
937  case 'T':
938  if (sscanf (optarg, "0x%lx", &ctrl->cfg.txbuf_size) != 1)
939  if (sscanf (optarg, "%ld", &ctrl->cfg.txbuf_size) != 1)
940  {
941  fprintf (stderr, "CLIENT: ERROR: Invalid value "
942  "for option -%c!\n", c);
944  }
946  {
947  ctrl->txbuf_size = ctrl->cfg.txbuf_size;
948  vcl_test_buf_alloc (&ctrl->cfg, 0 /* is_rxbuf */ ,
949  (uint8_t **) & ctrl->txbuf,
950  &ctrl->txbuf_size);
951  ctrl->cfg.total_bytes =
952  ctrl->cfg.num_writes * ctrl->cfg.txbuf_size;
953  }
954  else
955  {
956  fprintf (stderr, "CLIENT: ERROR: txbuf size (%lu) "
957  "less than minumum (%u)!\n",
960  }
961  break;
962 
963  case 'U':
964  ctrl->cfg.test = VCL_TEST_TYPE_UNI;
965  break;
966 
967  case 'B':
968  ctrl->cfg.test = VCL_TEST_TYPE_BI;
969  break;
970 
971  case 'V':
972  ctrl->cfg.verbose = 1;
973  break;
974 
975  case '6':
976  ctrl->cfg.address_ip6 = 1;
977  break;
978 
979  case 'D':
980  ctrl->cfg.transport_udp = 1;
981  break;
982 
983  case '?':
984  switch (optopt)
985  {
986  case 'E':
987  case 'I':
988  case 'N':
989  case 'R':
990  case 'T':
991  case 'w':
992  fprintf (stderr, "CLIENT: ERROR: Option -%c "
993  "requires an argument.\n", optopt);
994  break;
995 
996  default:
997  if (isprint (optopt))
998  fprintf (stderr, "CLIENT: ERROR: Unknown "
999  "option `-%c'.\n", optopt);
1000  else
1001  fprintf (stderr, "CLIENT: ERROR: Unknown "
1002  "option character `\\x%x'.\n", optopt);
1003  }
1004  /* fall thru */
1005  case 'h':
1006  default:
1008  }
1009 
1010  if (argc < (optind + 2))
1011  {
1012  fprintf (stderr, "CLIENT: ERROR: Insufficient number of arguments!\n");
1014  }
1015 
1016  ctrl->fd = socket (ctrl->cfg.address_ip6 ? AF_INET6 : AF_INET,
1017  ctrl->cfg.transport_udp ? SOCK_DGRAM : SOCK_STREAM, 0);
1018 
1019  if (ctrl->fd < 0)
1020  {
1021  errno_val = errno;
1022  perror ("ERROR in main()");
1023  fprintf (stderr, "CLIENT: ERROR: socket "
1024  "failed (errno = %d)!\n", errno_val);
1025  return ctrl->fd;
1026  }
1027 
1028  memset (&scm->server_addr, 0, sizeof (scm->server_addr));
1029  if (ctrl->cfg.address_ip6)
1030  {
1031  struct sockaddr_in6 *server_addr =
1032  (struct sockaddr_in6 *) &scm->server_addr;
1033  scm->server_addr_size = sizeof (*server_addr);
1034  server_addr->sin6_family = AF_INET6;
1035  inet_pton (AF_INET6, argv[optind++], &(server_addr->sin6_addr));
1036  server_addr->sin6_port = htons (atoi (argv[optind]));
1037  }
1038  else
1039  {
1040  struct sockaddr_in *server_addr =
1041  (struct sockaddr_in *) &scm->server_addr;
1042  scm->server_addr_size = sizeof (*server_addr);
1043  server_addr->sin_family = AF_INET;
1044  inet_pton (AF_INET, argv[optind++], &(server_addr->sin_addr));
1045  server_addr->sin_port = htons (atoi (argv[optind]));
1046  }
1047 
1048  do
1049  {
1050  printf ("\nCLIENT: Connecting to server...\n");
1051 
1052  rv = connect (ctrl->fd, (struct sockaddr *) &scm->server_addr,
1053  scm->server_addr_size);
1054 
1055  if (rv < 0)
1056  {
1057  errno_val = errno;
1058  perror ("ERROR in main()");
1059  fprintf (stderr, "CLIENT: ERROR: connect failed (errno = %d)!\n",
1060  errno_val);
1061  return -1;
1062  }
1063 
1064  sock_test_cfg_sync (ctrl);
1065  printf ("CLIENT (fd %d): Control socket connected.\n", ctrl->fd);
1066  }
1067  while (rv < 0);
1068 
1070 
1071  while (ctrl->cfg.test != VCL_TEST_TYPE_EXIT)
1072  {
1073  if (scm->dump_cfg)
1074  {
1075  vcl_test_cfg_dump (&ctrl->cfg, 1 /* is_client */ );
1076  scm->dump_cfg = 0;
1077  }
1078 
1079  switch (ctrl->cfg.test)
1080  {
1081  case VCL_TEST_TYPE_ECHO:
1082  echo_test_client ();
1083  break;
1084 
1085  case VCL_TEST_TYPE_UNI:
1086  case VCL_TEST_TYPE_BI:
1087  stream_test_client (ctrl->cfg.test);
1088  break;
1089 
1090  case VCL_TEST_TYPE_EXIT:
1091  continue;
1092 
1093  case VCL_TEST_TYPE_NONE:
1094  default:
1095  break;
1096  }
1097  switch (post_test)
1098  {
1099  case VCL_TEST_TYPE_EXIT:
1100  switch (ctrl->cfg.test)
1101  {
1102  case VCL_TEST_TYPE_EXIT:
1103  case VCL_TEST_TYPE_UNI:
1104  case VCL_TEST_TYPE_BI:
1105  case VCL_TEST_TYPE_ECHO:
1106  ctrl->cfg.test = VCL_TEST_TYPE_EXIT;
1107  continue;
1108 
1109  case VCL_TEST_TYPE_NONE:
1110  default:
1111  break;
1112  }
1113  break;
1114 
1115  case VCL_TEST_TYPE_NONE:
1116  case VCL_TEST_TYPE_ECHO:
1117  case VCL_TEST_TYPE_UNI:
1118  case VCL_TEST_TYPE_BI:
1119  default:
1120  break;
1121  }
1122 
1123  memset (ctrl->txbuf, 0, ctrl->txbuf_size);
1124  memset (ctrl->rxbuf, 0, ctrl->rxbuf_size);
1125 
1126  printf ("\nCLIENT: Type some characters and hit <return>\n"
1127  "('" VCL_TEST_TOKEN_HELP "' for help): ");
1128 
1129  if (fgets (ctrl->txbuf, ctrl->txbuf_size, stdin) != NULL)
1130  {
1131  if (strlen (ctrl->txbuf) == 1)
1132  {
1133  printf ("\nCLIENT: Nothing to send! Please try again...\n");
1134  continue;
1135  }
1136  ctrl->txbuf[strlen (ctrl->txbuf) - 1] = 0; // chomp the newline.
1137 
1138  /* Parse input for keywords */
1139  ctrl->cfg.test = parse_input ();
1140  }
1141  }
1142 
1143  exit_client ();
1144  close (ctrl->fd);
1145  return (scm->af_unix_echo_tx == scm->af_unix_echo_rx) ? 0 : -1;
1146 }
1147 
1148 /*
1149  * fd.io coding-style-patch-verification: ON
1150  *
1151  * Local Variables:
1152  * eval: (c-set-style "gnu")
1153  * End:
1154  */
static int sock_test_read(int fd, uint8_t *buf, uint32_t nbytes, vcl_test_stats_t *stats)
Definition: sock_test.h:33
vcl_test_session_t ctrl_socket
#define VCL_TEST_TOKEN_RXBUF_SIZE
Definition: vcl_test.h:54
static void sock_client_echo_af_unix(sock_client_main_t *scm)
struct timespec stop
Definition: vcl_test.h:111
#define EINVAL
Definition: string.h:93
static void dump_help(void)
Definition: vcl_test.h:522
struct sockaddr_storage server_addr
uint32_t num_test_sessions
Definition: vcl_test.h:88
uint32_t transport_udp
Definition: vcl_test.h:93
int main(int argc, char **argv)
#define VCL_TEST_CFG_BUF_SIZE_MIN
Definition: vcl_test.h:66
struct timespec start
Definition: vcl_test.h:110
static vcl_test_t parse_input()
#define VCL_TEST_TOKEN_NUM_WRITES
Definition: vcl_test.h:53
uint64_t num_writes
Definition: vcl_test.h:96
#define VCL_TEST_TOKEN_SHOW_CFG
Definition: vcl_test.h:55
vcl_test_t
Definition: vcl_test.h:73
#define SOCK_TEST_BANNER_STRING
Definition: sock_test.h:29
#define SOCK_TEST_AF_UNIX_FILENAME
Definition: sock_test.h:25
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
uint32_t txbuf_size
Definition: vcl_test.h:117
static void exit_client(void)
uint32_t seq_num
Definition: vcl_test.h:85
vcl_test_cfg_t cfg
Definition: vcl_test.h:121
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
uint32_t verbose
Definition: vcl_test.h:91
static int sock_test_connect_test_sockets(uint32_t num_test_sockets)
#define VCL_TEST_SEPARATOR_STRING
Definition: vcl_test.h:71
static void vcl_test_session_buf_alloc(vcl_test_session_t *socket)
Definition: vcl_test.h:252
static void vcl_test_cfg_dump(vcl_test_cfg_t *cfg, uint8_t is_client)
Definition: vcl_test.h:288
static void echo_test_client()
static void stream_test_client(vcl_test_t test)
static void cfg_verbose_toggle(void)
#define VCL_TEST_CFG_CTRL_MAGIC
Definition: vcl_test.h:62
#define VCL_TEST_TOKEN_RUN_BI
Definition: vcl_test.h:57
uint32_t address_ip6
Definition: vcl_test.h:92
svmdb_client_t * c
sll srl srl sll sra u16x4 i
Definition: vector_sse42.h:317
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
#define VCL_TEST_TOKEN_TXBUF_SIZE
Definition: vcl_test.h:51
#define VCL_TEST_TOKEN_VERBOSE
Definition: vcl_test.h:50
static void cfg_rxbuf_size_set(void)
static void cfg_num_writes_set(void)
#define VCL_TEST_TOKEN_HELP
Definition: vcl_test.h:48
uint32_t magic
Definition: vcl_test.h:84
static void cfg_txbuf_size_set(void)
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
vcl_test_stats_t stats
Definition: vcl_test.h:122
vcl_test_session_t * test_socket
uint64_t tx_bytes
Definition: vcl_test.h:107
sock_client_main_t sock_client_main
#define VCL_TEST_TOKEN_RUN_UNI
Definition: vcl_test.h:56
uint32_t rxbuf_size
Definition: vcl_test.h:119
uint32_t test
Definition: vcl_test.h:86
static void vcl_test_stats_accumulate(vcl_test_stats_t *accum, vcl_test_stats_t *incr)
Definition: vcl_test.h:187
void print_usage_and_exit(void)
static void cfg_num_test_sockets_set(void)
static int sock_test_cfg_sync(vcl_test_session_t *socket)
#define VCL_TEST_TOKEN_NUM_TEST_SESS
Definition: vcl_test.h:52
#define VCL_TEST_TOKEN_EXIT
Definition: vcl_test.h:49
static int vcl_test_cfg_verify(vcl_test_cfg_t *cfg, vcl_test_cfg_t *valid_cfg)
Definition: vcl_test.h:215
uint64_t rx_bytes
Definition: vcl_test.h:103
uint64_t total_bytes
Definition: vcl_test.h:97
#define VCL_TEST_CFG_MAX_TEST_SESS
Definition: vcl_test.h:67