2 * Copyright (c) 2017 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include <sys/types.h>
19 #include <sys/socket.h>
24 #include <uri/sock_test.h>
33 sock_test_stats_t stats;
40 #define SOCK_SERVER_MAX_TEST_CONN 10
45 size_t conn_pool_size;
46 sock_server_conn_t *conn_pool;
50 struct timeval timeout;
53 sock_server_main_t sock_server_main;
58 sock_server_main_t *ssm = &sock_server_main;
61 for (nfds = i = 0; i < FD_SETSIZE; i++)
63 if (FD_ISSET (i, &ssm->rd_fdset) || FD_ISSET (i, &ssm->wr_fdset))
70 conn_fdset_set (sock_server_conn_t * conn, fd_set * fdset)
72 sock_server_main_t *ssm = &sock_server_main;
74 FD_SET (conn->fd, fdset);
75 ssm->nfds = get_nfds ();
79 conn_fdset_clr (sock_server_conn_t * conn, fd_set * fdset)
81 sock_server_main_t *ssm = &sock_server_main;
83 FD_CLR (conn->fd, fdset);
84 ssm->nfds = get_nfds ();
88 conn_pool_expand (size_t expand_size)
90 sock_server_main_t *ssm = &sock_server_main;
91 sock_server_conn_t *conn_pool;
92 size_t new_size = ssm->conn_pool_size + expand_size;
95 conn_pool = realloc (ssm->conn_pool, new_size * sizeof (*ssm->conn_pool));
98 for (i = ssm->conn_pool_size; i < new_size; i++)
100 sock_server_conn_t *conn = &conn_pool[i];
101 memset (conn, 0, sizeof (*conn));
102 sock_test_cfg_init (&conn->cfg);
103 sock_test_buf_alloc (&conn->cfg, 1 /* is_rxbuf */ ,
104 &conn->buf, &conn->buf_size);
105 conn->cfg.txbuf_size = conn->cfg.rxbuf_size;
108 ssm->conn_pool = conn_pool;
109 ssm->conn_pool_size = new_size;
113 int errno_val = errno;
114 perror ("ERROR in conn_pool_expand()");
115 fprintf (stderr, "ERROR: Memory allocation failed (errno = %d)!\n",
120 static inline sock_server_conn_t *
121 conn_pool_alloc (void)
123 sock_server_main_t *ssm = &sock_server_main;
126 for (i = 0; i < ssm->conn_pool_size; i++)
128 if (!ssm->conn_pool[i].is_alloc)
131 ssm->conn_pool[i].endpt.ip = ssm->conn_pool[i].ip;
133 ssm->conn_pool[i].is_alloc = 1;
134 return (&ssm->conn_pool[i]);
142 conn_pool_free (sock_server_conn_t * conn)
144 sock_server_main_t *ssm = &sock_server_main;
146 conn_fdset_clr (conn, &ssm->rd_fdset);
147 conn_fdset_clr (conn, &ssm->wr_fdset);
153 sync_config_and_reply (sock_server_conn_t * conn, sock_test_cfg_t * rx_cfg)
156 sock_test_buf_alloc (&conn->cfg, 1 /* is_rxbuf */ ,
157 &conn->buf, &conn->buf_size);
158 conn->cfg.txbuf_size = conn->cfg.rxbuf_size;
160 if (conn->cfg.verbose)
162 printf ("\nSERVER (fd %d): Replying to cfg message!\n", conn->fd);
163 sock_test_cfg_dump (&conn->cfg, 0 /* is_client */ );
165 (void) sock_test_write (conn->fd, (uint8_t *) & conn->cfg,
166 sizeof (conn->cfg), NULL, conn->cfg.verbose);
170 stream_test_server_start_stop (sock_server_conn_t * conn,
171 sock_test_cfg_t * rx_cfg)
173 sock_server_main_t *ssm = &sock_server_main;
174 int client_fd = conn->fd;
175 sock_test_t test = rx_cfg->test;
177 if (rx_cfg->ctrl_handle == conn->fd)
180 clock_gettime (CLOCK_REALTIME, &conn->stats.stop);
182 for (i = 0; i < ssm->conn_pool_size; i++)
184 sock_server_conn_t *tc = &ssm->conn_pool[i];
186 if (tc->cfg.ctrl_handle == conn->fd)
188 sock_test_stats_accumulate (&conn->stats, &tc->stats);
190 if (conn->cfg.verbose)
194 sprintf (buf, "SERVER (fd %d) RESULTS", tc->fd);
195 sock_test_stats_dump (buf, &tc->stats, 1 /* show_rx */ ,
196 test == SOCK_TEST_TYPE_BI
203 sock_test_stats_dump ("SERVER RESULTS", &conn->stats, 1 /* show_rx */ ,
204 (test == SOCK_TEST_TYPE_BI) /* show_tx */ ,
206 sock_test_cfg_dump (&conn->cfg, 0 /* is_client */ );
207 if (conn->cfg.verbose)
209 printf (" sock server main\n"
210 SOCK_TEST_SEPARATOR_STRING
212 " buf size: %u (0x%08x)\n"
213 SOCK_TEST_SEPARATOR_STRING,
214 conn->buf, conn->buf_size, conn->buf_size);
217 sync_config_and_reply (conn, rx_cfg);
218 printf ("\nSERVER (fd %d): %s-directional Stream Test Complete!\n"
219 SOCK_TEST_BANNER_STRING "\n", conn->fd,
220 test == SOCK_TEST_TYPE_BI ? "Bi" : "Uni");
224 printf ("\n" SOCK_TEST_BANNER_STRING
225 "SERVER (fd %d): %s-directional Stream Test!\n"
226 " Sending client the test cfg to start streaming data...\n",
227 client_fd, test == SOCK_TEST_TYPE_BI ? "Bi" : "Uni");
229 rx_cfg->ctrl_handle = (rx_cfg->ctrl_handle == ~0) ? conn->fd :
232 sync_config_and_reply (conn, rx_cfg);
234 /* read the 1st chunk, record start time */
235 memset (&conn->stats, 0, sizeof (conn->stats));
236 clock_gettime (CLOCK_REALTIME, &conn->stats.start);
242 stream_test_server (sock_server_conn_t * conn, int rx_bytes)
244 int client_fd = conn->fd;
245 sock_test_t test = conn->cfg.test;
247 if (test == SOCK_TEST_TYPE_BI)
248 (void) sock_test_write (client_fd, conn->buf, rx_bytes, &conn->stats,
251 if (conn->stats.rx_bytes >= conn->cfg.total_bytes)
253 clock_gettime (CLOCK_REALTIME, &conn->stats.stop);
260 sock_server_main_t *ssm = &sock_server_main;
262 sock_server_conn_t *conn;
264 if (ssm->conn_pool_size < (ssm->num_conn + SOCK_SERVER_MAX_TEST_CONN + 1))
265 conn_pool_expand (SOCK_SERVER_MAX_TEST_CONN + 1);
267 conn = conn_pool_alloc ();
270 fprintf (stderr, "\nERROR: No free connections!\n");
275 client_fd = vppcom_session_accept (ssm->listen_fd, &conn->endpt,
276 -1.0 /* wait forever */ );
278 client_fd = accept (ssm->listen_fd, (struct sockaddr *) NULL, NULL);
284 perror ("ERROR in main()");
285 fprintf (stderr, "ERROR: accept failed (errno = %d)!\n", errno_val);
288 printf ("SERVER: Got a connection -- fd = %d (0x%08x)!\n",
289 client_fd, client_fd);
291 conn->fd = client_fd;
292 conn_fdset_set (conn, &ssm->rd_fdset);
296 main (int argc, char **argv)
298 sock_server_main_t *ssm = &sock_server_main;
299 int client_fd, rv, main_rv = 0;
300 int tx_bytes, rx_bytes, nbytes;
301 sock_server_conn_t *conn;
302 sock_test_cfg_t *rx_cfg;
304 uint64_t xtra_bytes = 0;
305 struct sockaddr_in servaddr;
308 uint16_t port = SOCK_TEST_SERVER_PORT;
309 fd_set _rfdset, *rfdset = &_rfdset;
311 vppcom_endpt_t endpt;
313 fd_set _wfdset, *wfdset = &_wfdset;
316 if ((argc == 2) && (sscanf (argv[1], "%d", &v) == 1))
319 conn_pool_expand (SOCK_SERVER_MAX_TEST_CONN + 1);
322 rv = vppcom_app_create ("vcl_test_server");
331 vppcom_session_create (VPPCOM_VRF_DEFAULT, VPPCOM_PROTO_TCP,
332 0 /* is_nonblocking */ );
335 ssm->listen_fd = socket (AF_INET, SOCK_STREAM, 0);
337 if (ssm->listen_fd < 0)
340 perror ("ERROR in main()");
341 fprintf (stderr, "ERROR: socket() failed (errno = %d)!\n", errno_val);
342 return ssm->listen_fd;
345 memset (&servaddr, 0, sizeof (servaddr));
347 servaddr.sin_family = AF_INET;
348 servaddr.sin_addr.s_addr = htonl (INADDR_ANY);
349 servaddr.sin_port = htons (port);
352 endpt.vrf = VPPCOM_VRF_DEFAULT;
353 endpt.is_ip4 = (servaddr.sin_family == AF_INET);
354 endpt.ip = (uint8_t *) & servaddr.sin_addr;
355 endpt.port = (uint16_t) servaddr.sin_port;
357 rv = vppcom_session_bind (ssm->listen_fd, &endpt);
365 bind (ssm->listen_fd, (struct sockaddr *) &servaddr, sizeof (servaddr));
370 perror ("ERROR in main()");
371 fprintf (stderr, "ERROR: bind failed (errno = %d)!\n", errno_val);
376 rv = vppcom_session_listen (ssm->listen_fd, 10);
383 rv = listen (ssm->listen_fd, 10);
388 perror ("ERROR in main()");
389 fprintf (stderr, "ERROR: listen failed (errno = %d)!\n", errno_val);
393 FD_ZERO (&ssm->wr_fdset);
394 FD_ZERO (&ssm->rd_fdset);
396 FD_SET (ssm->listen_fd, &ssm->rd_fdset);
397 ssm->nfds = ssm->listen_fd + 1;
399 printf ("\nSERVER: Waiting for a client to connect on port %d...\n", port);
403 _rfdset = ssm->rd_fdset;
406 rv = vppcom_select (ssm->nfds, (uint64_t *) rfdset, NULL, NULL, 0);
409 struct timeval timeout;
410 timeout = ssm->timeout;
411 _wfdset = ssm->wr_fdset;
412 rv = select (ssm->nfds, rfdset, wfdset, NULL, &timeout);
418 fprintf (stderr, "\nERROR: select() failed -- aborting!\n");
425 if (FD_ISSET (ssm->listen_fd, rfdset))
428 for (i = 0; i < ssm->conn_pool_size; i++)
430 if (!ssm->conn_pool[i].is_alloc)
433 conn = &ssm->conn_pool[i];
434 client_fd = conn->fd;
436 if (FD_ISSET (client_fd, rfdset))
438 rx_bytes = sock_test_read (client_fd, conn->buf,
439 conn->buf_size, &conn->stats);
442 rx_cfg = (sock_test_cfg_t *) conn->buf;
443 if (rx_cfg->magic == SOCK_TEST_CFG_CTRL_MAGIC)
447 printf ("SERVER (fd %d): Received a cfg message!\n",
449 sock_test_cfg_dump (rx_cfg, 0 /* is_client */ );
452 if (rx_bytes != sizeof (*rx_cfg))
454 printf ("SERVER (fd %d): Invalid cfg message "
455 "size (%d)!\n Should be %lu bytes.\n",
456 client_fd, rx_bytes, sizeof (*rx_cfg));
457 conn->cfg.rxbuf_size = 0;
458 conn->cfg.num_writes = 0;
459 if (conn->cfg.verbose)
461 printf ("SERVER (fd %d): Replying to "
462 "cfg message!\n", client_fd);
463 sock_test_cfg_dump (rx_cfg, 0 /* is_client */ );
465 sock_test_write (client_fd, (uint8_t *) & conn->cfg,
466 sizeof (conn->cfg), NULL,
471 switch (rx_cfg->test)
473 case SOCK_TEST_TYPE_NONE:
474 case SOCK_TEST_TYPE_ECHO:
475 sync_config_and_reply (conn, rx_cfg);
478 case SOCK_TEST_TYPE_BI:
479 case SOCK_TEST_TYPE_UNI:
480 stream_test_server_start_stop (conn, rx_cfg);
483 case SOCK_TEST_TYPE_EXIT:
484 printf ("SERVER: Have a great day, "
485 "connection %d!\n", client_fd);
487 vppcom_session_close (client_fd);
491 conn_pool_free (conn);
493 if (ssm->nfds == (ssm->listen_fd + 1))
495 printf ("SERVER: All client connections "
496 "closed.\n\nSERVER: "
497 "May the force be with you!\n\n");
503 fprintf (stderr, "ERROR: Unknown test type!\n");
504 sock_test_cfg_dump (rx_cfg, 0 /* is_client */ );
510 else if ((conn->cfg.test == SOCK_TEST_TYPE_UNI) ||
511 (conn->cfg.test == SOCK_TEST_TYPE_BI))
513 stream_test_server (conn, rx_bytes);
517 else if (strlen ((char *) conn->buf))
518 printf ("\nSERVER (fd %d): RX (%d bytes) - '%s'\n",
519 conn->fd, rx_bytes, conn->buf);
523 if (errno == ECONNRESET)
525 printf ("\nSERVER: Connection reset by remote peer.\n"
526 " Y'all have a great day now!\n\n");
533 if (isascii (conn->buf[0]) && strlen ((const char *) conn->buf))
537 "ERROR: FIFO not drained in previous test!\n"
538 " extra chunks %u (0x%x)\n"
539 " extra bytes %lu (0x%lx)\n",
540 xtra, xtra, xtra_bytes, xtra_bytes);
545 if (conn->cfg.verbose)
546 printf ("SERVER (fd %d): Echoing back\n", client_fd);
548 nbytes = strlen ((const char *) conn->buf) + 1;
550 tx_bytes = sock_test_write (client_fd, conn->buf,
551 nbytes, &conn->stats,
554 printf ("SERVER (fd %d): TX (%d bytes) - '%s'\n",
555 conn->fd, tx_bytes, conn->buf);
558 else // Extraneous read data from non-echo tests???
561 xtra_bytes += rx_bytes;
569 vppcom_session_close (ssm->listen_fd);
570 vppcom_app_destroy ();
572 close (ssm->listen_fd);
575 free (ssm->conn_pool);
581 * fd.io coding-style-patch-verification: ON
584 * eval: (c-set-style "gnu")