blob: 896aeb024d85d27ce550663e312186c4873cdb13 [file] [log] [blame]
Dave Wallace543852a2017-08-03 02:11:34 -04001/*
2 * Copyright (c) 2017 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include <unistd.h>
17#include <errno.h>
18#include <sys/types.h>
19#include <sys/socket.h>
20#include <stdio.h>
21#include <string.h>
22#include <time.h>
23#include <ctype.h>
Dave Wallace5c7cf1c2017-10-24 04:12:18 -040024#include <vcl/sock_test.h>
Dave Wallace35830af2017-10-09 01:43:42 -040025#include <sys/stat.h>
26#include <fcntl.h>
Florin Coras0e88e852018-09-17 22:09:02 -070027#include <sys/ioctl.h>
Dave Wallace543852a2017-08-03 02:11:34 -040028
Dave Wallacef7f809c2017-10-03 01:48:42 -040029#define SOCK_SERVER_USE_EPOLL 1
Dave Wallace35830af2017-10-09 01:43:42 -040030#define VPPCOM_SESSION_ATTR_UNIT_TEST 0
Dave Wallacef7f809c2017-10-03 01:48:42 -040031
32#if SOCK_SERVER_USE_EPOLL
33#include <sys/epoll.h>
Dave Wallace3ee1fe12018-02-23 01:09:11 -050034#if !defined(VCL_TEST)
35#include <sys/un.h>
36#endif
Dave Wallacef7f809c2017-10-03 01:48:42 -040037#endif
38
Dave Wallace35830af2017-10-09 01:43:42 -040039#ifdef VCL_TEST
40#if VPPCOM_SESSION_ATTR_UNIT_TEST
41#define BUFLEN sizeof (uint64_t) * 16
42uint64_t buffer[16];
43uint32_t buflen = BUFLEN;
44uint32_t *flags = (uint32_t *) buffer;
45#endif
46#endif
47
Dave Wallace543852a2017-08-03 02:11:34 -040048typedef struct
49{
50 uint8_t is_alloc;
51 int fd;
52 uint8_t *buf;
53 uint32_t buf_size;
54 sock_test_cfg_t cfg;
55 sock_test_stats_t stats;
56#ifdef VCL_TEST
57 vppcom_endpt_t endpt;
58 uint8_t ip[16];
59#endif
60} sock_server_conn_t;
61
Dave Wallacede910062018-03-20 09:22:13 -040062typedef struct
63{
64 uint32_t port;
65 uint32_t address_ip6;
66 uint32_t transport_udp;
67} sock_server_cfg_t;
68
Dave Wallace543852a2017-08-03 02:11:34 -040069#define SOCK_SERVER_MAX_TEST_CONN 10
Dave Wallacef7f809c2017-10-03 01:48:42 -040070#define SOCK_SERVER_MAX_EPOLL_EVENTS 10
Dave Wallace543852a2017-08-03 02:11:34 -040071typedef struct
72{
73 int listen_fd;
Dave Wallacede910062018-03-20 09:22:13 -040074 sock_server_cfg_t cfg;
Dave Wallacef7f809c2017-10-03 01:48:42 -040075#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];
Dave Wallace3ee1fe12018-02-23 01:09:11 -050079#if !defined (VCL_TEST)
80 int af_unix_listen_fd;
81 int af_unix_fd;
82 struct epoll_event af_unix_listen_ev;
83 struct sockaddr_un serveraddr;
84 uint32_t af_unix_xacts;
85#endif
Dave Wallacef7f809c2017-10-03 01:48:42 -040086#endif
Dave Wallace543852a2017-08-03 02:11:34 -040087 size_t num_conn;
88 size_t conn_pool_size;
89 sock_server_conn_t *conn_pool;
90 int nfds;
91 fd_set rd_fdset;
92 fd_set wr_fdset;
93 struct timeval timeout;
94} sock_server_main_t;
95
96sock_server_main_t sock_server_main;
97
Dave Wallacef7f809c2017-10-03 01:48:42 -040098#if ! SOCK_SERVER_USE_EPOLL
Dave Wallace543852a2017-08-03 02:11:34 -040099static inline int
100get_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
113static inline void
114conn_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
122static inline void
123conn_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}
Dave Wallacef7f809c2017-10-03 01:48:42 -0400130#endif
Dave Wallace543852a2017-08-03 02:11:34 -0400131
132static inline void
133conn_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 sock_test_cfg_init (&conn->cfg);
148 sock_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()");
Dave Wallace048b1d62018-01-03 22:24:41 -0500160 fprintf (stderr, "SERVER: ERROR: Memory allocation "
161 "failed (errno = %d)!\n", errno_val);
Dave Wallace543852a2017-08-03 02:11:34 -0400162 }
163}
164
165static inline sock_server_conn_t *
166conn_pool_alloc (void)
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
186static inline void
187conn_pool_free (sock_server_conn_t * conn)
188{
Dave Wallacef7f809c2017-10-03 01:48:42 -0400189#if ! SOCK_SERVER_USE_EPOLL
Dave Wallace543852a2017-08-03 02:11:34 -0400190 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);
Dave Wallacef7f809c2017-10-03 01:48:42 -0400194#endif
Dave Wallace543852a2017-08-03 02:11:34 -0400195 conn->fd = 0;
196 conn->is_alloc = 0;
197}
198
199static inline void
200sync_config_and_reply (sock_server_conn_t * conn, sock_test_cfg_t * rx_cfg)
201{
202 conn->cfg = *rx_cfg;
203 sock_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 sock_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
216static void
217stream_test_server_start_stop (sock_server_conn_t * conn,
218 sock_test_cfg_t * rx_cfg)
219{
220 sock_server_main_t *ssm = &sock_server_main;
221 int client_fd = conn->fd;
222 sock_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 sock_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 sock_test_stats_dump (buf, &tc->stats, 1 /* show_rx */ ,
243 test == SOCK_TEST_TYPE_BI
244 /* show tx */ ,
245 conn->cfg.verbose);
246 }
247 }
248 }
249
250 sock_test_stats_dump ("SERVER RESULTS", &conn->stats, 1 /* show_rx */ ,
251 (test == SOCK_TEST_TYPE_BI) /* show_tx */ ,
252 conn->cfg.verbose);
253 sock_test_cfg_dump (&conn->cfg, 0 /* is_client */ );
254 if (conn->cfg.verbose)
255 {
256 printf (" sock server main\n"
257 SOCK_TEST_SEPARATOR_STRING
258 " buf: %p\n"
259 " buf size: %u (0x%08x)\n"
260 SOCK_TEST_SEPARATOR_STRING,
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 == SOCK_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 == SOCK_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
288static inline void
289stream_test_server (sock_server_conn_t * conn, int rx_bytes)
290{
291 int client_fd = conn->fd;
292 sock_test_t test = conn->cfg.test;
293
294 if (test == SOCK_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
Dave Wallace3ee1fe12018-02-23 01:09:11 -0500304#if SOCK_SERVER_USE_EPOLL && !defined (VCL_TEST)
305static inline void
306af_unix_echo (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 "\"%s\", nbytes %lu) failed (errno = %d)!\n",
343 af_unix_client_fd, af_unix_client_fd, buffer, nbytes,
344 errno_val);
345 goto done;
346 }
347
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 }
367done:
368 close (af_unix_client_fd);
369}
370
371#endif
372
Dave Wallace543852a2017-08-03 02:11:34 -0400373static inline void
374new_client (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))
381 conn_pool_expand (SOCK_SERVER_MAX_TEST_CONN + 1);
382
383 conn = conn_pool_alloc ();
384 if (!conn)
385 {
Dave Wallace048b1d62018-01-03 22:24:41 -0500386 fprintf (stderr, "\nSERVER: ERROR: No free connections!\n");
Dave Wallace543852a2017-08-03 02:11:34 -0400387 return;
388 }
389
390#ifdef VCL_TEST
Dave Wallace048b1d62018-01-03 22:24:41 -0500391 client_fd = vppcom_session_accept (ssm->listen_fd, &conn->endpt, 0);
Dave Wallacef7f809c2017-10-03 01:48:42 -0400392 if (client_fd < 0)
393 errno = -client_fd;
Dave Wallace59179392017-11-07 02:20:07 -0500394#elif HAVE_ACCEPT4
395 client_fd = accept4 (ssm->listen_fd, (struct sockaddr *) NULL, NULL, NULL);
Dave Wallace543852a2017-08-03 02:11:34 -0400396#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;
Dave Wallacef7f809c2017-10-03 01:48:42 -0400403 perror ("ERROR in new_client()");
Dave Wallace048b1d62018-01-03 22:24:41 -0500404 fprintf (stderr, "SERVER: ERROR: accept failed "
405 "(errno = %d)!\n", errno_val);
Dave Wallaceee45d412017-11-24 21:44:06 -0500406 return;
Dave Wallace543852a2017-08-03 02:11:34 -0400407 }
408
409 printf ("SERVER: Got a connection -- fd = %d (0x%08x)!\n",
410 client_fd, client_fd);
411
412 conn->fd = client_fd;
Dave Wallacef7f809c2017-10-03 01:48:42 -0400413
414#if ! SOCK_SERVER_USE_EPOLL
Dave Wallace543852a2017-08-03 02:11:34 -0400415 conn_fdset_set (conn, &ssm->rd_fdset);
Dave Wallacef7f809c2017-10-03 01:48:42 -0400416 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()");
Dave Wallace048b1d62018-01-03 22:24:41 -0500436 fprintf (stderr, "SERVER: ERROR: epoll_ctl failed (errno = %d)!\n",
Dave Wallacef7f809c2017-10-03 01:48:42 -0400437 errno_val);
438 }
439 else
440 ssm->nfds++;
441 }
442#endif
Dave Wallace543852a2017-08-03 02:11:34 -0400443}
444
Dave Wallacede910062018-03-20 09:22:13 -0400445void
446print_usage_and_exit (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
Dave Wallace543852a2017-08-03 02:11:34 -0400457int
458main (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 sock_test_cfg_t *rx_cfg;
465 uint32_t xtra = 0;
466 uint64_t xtra_bytes = 0;
Dave Wallacede910062018-03-20 09:22:13 -0400467 struct sockaddr_storage servaddr;
Dave Wallace543852a2017-08-03 02:11:34 -0400468 int errno_val;
Dave Wallacede910062018-03-20 09:22:13 -0400469 int c, v, i;
Dave Wallace543852a2017-08-03 02:11:34 -0400470 uint16_t port = SOCK_TEST_SERVER_PORT;
Dave Wallacef7f809c2017-10-03 01:48:42 -0400471#if ! SOCK_SERVER_USE_EPOLL
Dave Wallace543852a2017-08-03 02:11:34 -0400472 fd_set _rfdset, *rfdset = &_rfdset;
Dave Wallacef7f809c2017-10-03 01:48:42 -0400473#endif
Dave Wallace543852a2017-08-03 02:11:34 -0400474#ifdef VCL_TEST
475 vppcom_endpt_t endpt;
476#else
Dave Wallacede910062018-03-20 09:22:13 -0400477 uint32_t servaddr_size;
Dave Wallacef7f809c2017-10-03 01:48:42 -0400478#if ! SOCK_SERVER_USE_EPOLL
Dave Wallace543852a2017-08-03 02:11:34 -0400479 fd_set _wfdset, *wfdset = &_wfdset;
480#endif
Dave Wallacef7f809c2017-10-03 01:48:42 -0400481#endif
Dave Wallace543852a2017-08-03 02:11:34 -0400482
Dave Wallacede910062018-03-20 09:22:13 -0400483 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:
509 print_usage_and_exit ();
510 }
511
512 if (argc < (optind + 1))
513 {
514 fprintf (stderr, "SERVER: ERROR: Insufficient number of arguments!\n");
515 print_usage_and_exit ();
516 }
517
518 if (sscanf (argv[optind], "%d", &v) == 1)
Dave Wallace543852a2017-08-03 02:11:34 -0400519 port = (uint16_t) v;
Dave Wallacede910062018-03-20 09:22:13 -0400520 else
521 {
522 fprintf (stderr, "SERVER: ERROR: Invalid port (%s)!\n", argv[optind]);
523 print_usage_and_exit ();
524 }
Dave Wallace543852a2017-08-03 02:11:34 -0400525
526 conn_pool_expand (SOCK_SERVER_MAX_TEST_CONN + 1);
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 {
Dave Wallacede910062018-03-20 09:22:13 -0400537 ssm->listen_fd = vppcom_session_create (ssm->cfg.transport_udp ?
538 VPPCOM_PROTO_UDP :
539 VPPCOM_PROTO_TCP,
540 0 /* is_nonblocking */ );
Dave Wallace543852a2017-08-03 02:11:34 -0400541 }
542#else
Dave Wallacede910062018-03-20 09:22:13 -0400543 ssm->listen_fd = socket (ssm->cfg.address_ip6 ? AF_INET6 : AF_INET,
544 ssm->cfg.transport_udp ? SOCK_DGRAM : SOCK_STREAM,
545 0);
Dave Wallace3ee1fe12018-02-23 01:09:11 -0500546#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 */
Dave Wallace543852a2017-08-03 02:11:34 -0400590#endif
591 if (ssm->listen_fd < 0)
592 {
593 errno_val = errno;
594 perror ("ERROR in main()");
Dave Wallace048b1d62018-01-03 22:24:41 -0500595 fprintf (stderr, "SERVER: ERROR: socket() failed "
596 "(errno = %d)!\n", errno_val);
Dave Wallace543852a2017-08-03 02:11:34 -0400597 return ssm->listen_fd;
598 }
599
600 memset (&servaddr, 0, sizeof (servaddr));
601
Dave Wallacede910062018-03-20 09:22:13 -0400602 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 }
Dave Wallace543852a2017-08-03 02:11:34 -0400622
623#ifdef VCL_TEST
Dave Wallacede910062018-03-20 09:22:13 -0400624 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 }
Dave Wallace543852a2017-08-03 02:11:34 -0400638
639 rv = vppcom_session_bind (ssm->listen_fd, &endpt);
640 if (rv)
641 {
642 errno = -rv;
643 rv = -1;
644 }
645#else
Dave Wallacede910062018-03-20 09:22:13 -0400646 rv = bind (ssm->listen_fd, (struct sockaddr *) &servaddr, servaddr_size);
Dave Wallace543852a2017-08-03 02:11:34 -0400647#endif
648 if (rv < 0)
649 {
650 errno_val = errno;
651 perror ("ERROR in main()");
Dave Wallace048b1d62018-01-03 22:24:41 -0500652 fprintf (stderr, "SERVER: ERROR: bind failed (errno = %d)!\n",
653 errno_val);
Dave Wallace543852a2017-08-03 02:11:34 -0400654 return rv;
655 }
656
657#ifdef VCL_TEST
658 rv = vppcom_session_listen (ssm->listen_fd, 10);
659 if (rv)
660 {
661 errno = -rv;
662 rv = -1;
663 }
664#else
665 rv = listen (ssm->listen_fd, 10);
666#endif
667 if (rv < 0)
668 {
669 errno_val = errno;
670 perror ("ERROR in main()");
Dave Wallace048b1d62018-01-03 22:24:41 -0500671 fprintf (stderr, "SERVER: ERROR: listen failed "
672 "(errno = %d)!\n", errno_val);
Dave Wallace543852a2017-08-03 02:11:34 -0400673 return rv;
674 }
675
Dave Wallacef7f809c2017-10-03 01:48:42 -0400676#if ! SOCK_SERVER_USE_EPOLL
677
Dave Wallace543852a2017-08-03 02:11:34 -0400678 FD_ZERO (&ssm->wr_fdset);
679 FD_ZERO (&ssm->rd_fdset);
680
681 FD_SET (ssm->listen_fd, &ssm->rd_fdset);
682 ssm->nfds = ssm->listen_fd + 1;
683
Dave Wallacef7f809c2017-10-03 01:48:42 -0400684#else
685#ifdef VCL_TEST
686 ssm->epfd = vppcom_epoll_create ();
687 if (ssm->epfd < 0)
688 errno = -ssm->epfd;
689#else
690 ssm->epfd = epoll_create (1);
691#endif
692 if (ssm->epfd < 0)
693 {
694 errno_val = errno;
695 perror ("ERROR in main()");
Dave Wallace048b1d62018-01-03 22:24:41 -0500696 fprintf (stderr, "SERVER: ERROR: epoll_create failed (errno = %d)!\n",
Dave Wallacef7f809c2017-10-03 01:48:42 -0400697 errno_val);
698 return ssm->epfd;
699 }
700
701 ssm->listen_ev.events = EPOLLIN;
702 ssm->listen_ev.data.u32 = ~0;
703#ifdef VCL_TEST
704 rv = vppcom_epoll_ctl (ssm->epfd, EPOLL_CTL_ADD, ssm->listen_fd,
705 &ssm->listen_ev);
706 if (rv < 0)
707 errno = -rv;
708#else
Dave Wallace3ee1fe12018-02-23 01:09:11 -0500709 ssm->af_unix_listen_ev.events = EPOLLIN;
710 ssm->af_unix_listen_ev.data.u32 = SOCK_TEST_AF_UNIX_ACCEPT_DATA;
711 rv = epoll_ctl (ssm->epfd, EPOLL_CTL_ADD, ssm->af_unix_listen_fd,
712 &ssm->af_unix_listen_ev);
713 if (rv < 0)
714 {
715 errno_val = errno;
716 perror ("ERROR in main(): mixed epoll_ctl(EPOLL_CTL_ADD)");
717 fprintf (stderr, "SERVER: ERROR: mixed epoll_ctl(epfd %d (0x%x), "
718 "EPOLL_CTL_ADD, af_unix_listen_fd %d (0x%x), EPOLLIN) failed "
719 "(errno = %d)!\n", ssm->epfd, ssm->epfd,
720 ssm->af_unix_listen_fd, ssm->af_unix_listen_fd, errno_val);
721 close (ssm->af_unix_listen_fd);
722 unlink ((const char *) SOCK_TEST_AF_UNIX_FILENAME);
723 return rv;
724 }
725
Dave Wallacef7f809c2017-10-03 01:48:42 -0400726 rv = epoll_ctl (ssm->epfd, EPOLL_CTL_ADD, ssm->listen_fd, &ssm->listen_ev);
727#endif
728 if (rv < 0)
729 {
730 errno_val = errno;
731 perror ("ERROR in main()");
Dave Wallace048b1d62018-01-03 22:24:41 -0500732 fprintf (stderr, "SERVER: ERROR: epoll_ctl failed "
733 "(errno = %d)!\n", errno_val);
Dave Wallacef7f809c2017-10-03 01:48:42 -0400734 return rv;
735 }
736#endif
Dave Wallace543852a2017-08-03 02:11:34 -0400737
Dave Wallace3ee1fe12018-02-23 01:09:11 -0500738 printf ("\nSERVER: Waiting for a client to connect on port %d...\n", port);
739
Dave Wallace543852a2017-08-03 02:11:34 -0400740 while (1)
741 {
Dave Wallacef7f809c2017-10-03 01:48:42 -0400742#if ! SOCK_SERVER_USE_EPOLL
Dave Wallace543852a2017-08-03 02:11:34 -0400743 _rfdset = ssm->rd_fdset;
744
745#ifdef VCL_TEST
746 rv = vppcom_select (ssm->nfds, (uint64_t *) rfdset, NULL, NULL, 0);
747#else
748 {
749 struct timeval timeout;
750 timeout = ssm->timeout;
751 _wfdset = ssm->wr_fdset;
752 rv = select (ssm->nfds, rfdset, wfdset, NULL, &timeout);
753 }
754#endif
755 if (rv < 0)
756 {
757 perror ("select()");
Dave Wallace048b1d62018-01-03 22:24:41 -0500758 fprintf (stderr, "\nSERVER: ERROR: select() failed -- aborting!\n");
Dave Wallace543852a2017-08-03 02:11:34 -0400759 main_rv = -1;
760 goto done;
761 }
762 else if (rv == 0)
763 continue;
764
765 if (FD_ISSET (ssm->listen_fd, rfdset))
766 new_client ();
767
768 for (i = 0; i < ssm->conn_pool_size; i++)
769 {
770 if (!ssm->conn_pool[i].is_alloc)
771 continue;
772
773 conn = &ssm->conn_pool[i];
Dave Wallacef7f809c2017-10-03 01:48:42 -0400774#else
775 int num_ev;
776#ifdef VCL_TEST
777 num_ev = vppcom_epoll_wait (ssm->epfd, ssm->wait_events,
778 SOCK_SERVER_MAX_EPOLL_EVENTS, 60.0);
Dave Wallace0fd6ad62017-10-20 13:23:40 -0400779 if (num_ev < 0)
780 errno = -num_ev;
Dave Wallacef7f809c2017-10-03 01:48:42 -0400781#else
782 num_ev = epoll_wait (ssm->epfd, ssm->wait_events,
783 SOCK_SERVER_MAX_EPOLL_EVENTS, 60000);
784#endif
785 if (num_ev < 0)
786 {
787 perror ("epoll_wait()");
Dave Wallace048b1d62018-01-03 22:24:41 -0500788 fprintf (stderr, "\nSERVER: ERROR: epoll_wait() "
789 "failed -- aborting!\n");
Dave Wallacef7f809c2017-10-03 01:48:42 -0400790 main_rv = -1;
791 goto done;
792 }
793 if (num_ev == 0)
794 {
Dave Wallace048b1d62018-01-03 22:24:41 -0500795 fprintf (stderr, "\nSERVER: epoll_wait() timeout!\n");
Dave Wallacef7f809c2017-10-03 01:48:42 -0400796 continue;
797 }
798 for (i = 0; i < num_ev; i++)
799 {
Dave Wallace63f18592018-03-13 19:37:54 -0400800 conn = &ssm->conn_pool[ssm->wait_events[i].data.u32];
801 if (ssm->wait_events[i].events & (EPOLLHUP | EPOLLRDHUP))
802 {
803#ifdef VCL_TEST
804 vppcom_session_close (conn->fd);
805#else
806 close (conn->fd);
807#endif
808 continue;
809 }
Dave Wallacef7f809c2017-10-03 01:48:42 -0400810 if (ssm->wait_events[i].data.u32 == ~0)
811 {
812 new_client ();
813 continue;
814 }
Dave Wallace3ee1fe12018-02-23 01:09:11 -0500815#if !defined (VCL_TEST)
816 else if (ssm->wait_events[i].data.u32 ==
817 SOCK_TEST_AF_UNIX_ACCEPT_DATA)
818 {
819 af_unix_echo ();
820 continue;
821 }
822#endif
Dave Wallacef7f809c2017-10-03 01:48:42 -0400823#endif
Dave Wallace543852a2017-08-03 02:11:34 -0400824 client_fd = conn->fd;
825
Dave Wallacef7f809c2017-10-03 01:48:42 -0400826#if ! SOCK_SERVER_USE_EPOLL
Dave Wallace543852a2017-08-03 02:11:34 -0400827 if (FD_ISSET (client_fd, rfdset))
Dave Wallacef7f809c2017-10-03 01:48:42 -0400828#else
829 if (EPOLLIN & ssm->wait_events[i].events)
830#endif
Dave Wallace543852a2017-08-03 02:11:34 -0400831 {
Florin Coras0e88e852018-09-17 22:09:02 -0700832 read_again:
Dave Wallace543852a2017-08-03 02:11:34 -0400833 rx_bytes = sock_test_read (client_fd, conn->buf,
834 conn->buf_size, &conn->stats);
835 if (rx_bytes > 0)
836 {
837 rx_cfg = (sock_test_cfg_t *) conn->buf;
838 if (rx_cfg->magic == SOCK_TEST_CFG_CTRL_MAGIC)
839 {
840 if (rx_cfg->verbose)
841 {
842 printf ("SERVER (fd %d): Received a cfg message!\n",
843 client_fd);
844 sock_test_cfg_dump (rx_cfg, 0 /* is_client */ );
845 }
846
847 if (rx_bytes != sizeof (*rx_cfg))
848 {
849 printf ("SERVER (fd %d): Invalid cfg message "
850 "size (%d)!\n Should be %lu bytes.\n",
851 client_fd, rx_bytes, sizeof (*rx_cfg));
852 conn->cfg.rxbuf_size = 0;
853 conn->cfg.num_writes = 0;
854 if (conn->cfg.verbose)
855 {
856 printf ("SERVER (fd %d): Replying to "
857 "cfg message!\n", client_fd);
858 sock_test_cfg_dump (rx_cfg, 0 /* is_client */ );
859 }
860 sock_test_write (client_fd, (uint8_t *) & conn->cfg,
861 sizeof (conn->cfg), NULL,
862 conn->cfg.verbose);
863 continue;
864 }
865
866 switch (rx_cfg->test)
867 {
868 case SOCK_TEST_TYPE_NONE:
869 case SOCK_TEST_TYPE_ECHO:
870 sync_config_and_reply (conn, rx_cfg);
871 break;
872
873 case SOCK_TEST_TYPE_BI:
874 case SOCK_TEST_TYPE_UNI:
875 stream_test_server_start_stop (conn, rx_cfg);
876 break;
877
878 case SOCK_TEST_TYPE_EXIT:
879 printf ("SERVER: Have a great day, "
880 "connection %d!\n", client_fd);
881#ifdef VCL_TEST
882 vppcom_session_close (client_fd);
883#else
884 close (client_fd);
885#endif
886 conn_pool_free (conn);
Dave Wallaceee45d412017-11-24 21:44:06 -0500887 printf ("SERVER: Closed client fd %d\n", client_fd);
Dave Wallacef7f809c2017-10-03 01:48:42 -0400888#if ! SOCK_SERVER_USE_EPOLL
Dave Wallace543852a2017-08-03 02:11:34 -0400889 if (ssm->nfds == (ssm->listen_fd + 1))
Dave Wallacef7f809c2017-10-03 01:48:42 -0400890#else
891 ssm->nfds--;
892 if (!ssm->nfds)
893#endif
Dave Wallace543852a2017-08-03 02:11:34 -0400894 {
895 printf ("SERVER: All client connections "
896 "closed.\n\nSERVER: "
897 "May the force be with you!\n\n");
898 goto done;
899 }
900 break;
901
902 default:
Dave Wallace048b1d62018-01-03 22:24:41 -0500903 fprintf (stderr,
904 "SERVER: ERROR: Unknown test type!\n");
Dave Wallace543852a2017-08-03 02:11:34 -0400905 sock_test_cfg_dump (rx_cfg, 0 /* is_client */ );
906 break;
907 }
908 continue;
909 }
910
911 else if ((conn->cfg.test == SOCK_TEST_TYPE_UNI) ||
912 (conn->cfg.test == SOCK_TEST_TYPE_BI))
913 {
914 stream_test_server (conn, rx_bytes);
Florin Coras0e88e852018-09-17 22:09:02 -0700915 if (ioctl (conn->fd, FIONREAD))
916 goto read_again;
Dave Wallace543852a2017-08-03 02:11:34 -0400917 continue;
918 }
919
Chris Luke879ace32017-09-26 13:15:16 -0400920 else if (isascii (conn->buf[0]))
Chris Lukeab7b8d92017-09-07 07:40:13 -0400921 {
922 // If it looks vaguely like a string, make sure it's terminated
923 ((char *) conn->buf)[rx_bytes <
924 conn->buf_size ? rx_bytes :
925 conn->buf_size - 1] = 0;
Dave Wallacef7f809c2017-10-03 01:48:42 -0400926 printf ("SERVER (fd %d): RX (%d bytes) - '%s'\n",
Chris Lukeab7b8d92017-09-07 07:40:13 -0400927 conn->fd, rx_bytes, conn->buf);
928 }
Dave Wallace543852a2017-08-03 02:11:34 -0400929 }
930 else // rx_bytes < 0
931 {
932 if (errno == ECONNRESET)
933 {
934 printf ("\nSERVER: Connection reset by remote peer.\n"
935 " Y'all have a great day now!\n\n");
936 break;
937 }
938 else
939 continue;
940 }
941
Chris Luke879ace32017-09-26 13:15:16 -0400942 if (isascii (conn->buf[0]))
Dave Wallace543852a2017-08-03 02:11:34 -0400943 {
Dave Wallace048b1d62018-01-03 22:24:41 -0500944 /* If it looks vaguely like a string,
945 * make sure it's terminated
946 */
Chris Luke879ace32017-09-26 13:15:16 -0400947 ((char *) conn->buf)[rx_bytes <
948 conn->buf_size ? rx_bytes :
949 conn->buf_size - 1] = 0;
Dave Wallace543852a2017-08-03 02:11:34 -0400950 if (xtra)
Dave Wallace048b1d62018-01-03 22:24:41 -0500951 fprintf (stderr, "SERVER: ERROR: "
952 "FIFO not drained in previous test!\n"
Dave Wallace543852a2017-08-03 02:11:34 -0400953 " extra chunks %u (0x%x)\n"
954 " extra bytes %lu (0x%lx)\n",
955 xtra, xtra, xtra_bytes, xtra_bytes);
956
957 xtra = 0;
958 xtra_bytes = 0;
959
960 if (conn->cfg.verbose)
961 printf ("SERVER (fd %d): Echoing back\n", client_fd);
962
963 nbytes = strlen ((const char *) conn->buf) + 1;
964
965 tx_bytes = sock_test_write (client_fd, conn->buf,
966 nbytes, &conn->stats,
967 conn->cfg.verbose);
968 if (tx_bytes >= 0)
969 printf ("SERVER (fd %d): TX (%d bytes) - '%s'\n",
970 conn->fd, tx_bytes, conn->buf);
971 }
972
973 else // Extraneous read data from non-echo tests???
974 {
975 xtra++;
976 xtra_bytes += rx_bytes;
977 }
978 }
979 }
980 }
981
982done:
983#ifdef VCL_TEST
984 vppcom_session_close (ssm->listen_fd);
985 vppcom_app_destroy ();
986#else
987 close (ssm->listen_fd);
Dave Wallace3ee1fe12018-02-23 01:09:11 -0500988
989#if SOCK_SERVER_USE_EPOLL && !defined (VCL_TEST)
990 close (ssm->af_unix_listen_fd);
991 unlink ((const char *) SOCK_TEST_AF_UNIX_FILENAME);
992#endif /* SOCK_SERVER_USE_EPOLL */
993
Dave Wallace543852a2017-08-03 02:11:34 -0400994#endif
995 if (ssm->conn_pool)
996 free (ssm->conn_pool);
997
998 return main_rv;
999}
1000
1001/*
1002 * fd.io coding-style-patch-verification: ON
1003 *
1004 * Local Variables:
1005 * eval: (c-set-style "gnu")
1006 * End:
1007 */