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