4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2001-2003 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
26 * sock_test.c. Implementing a CLI for inetboot testing.
28 #pragma ident "%Z%%M% %I% %E% SMI"
30 #include <sys/types.h>
31 #include "socket_impl.h"
32 #include "socket_inet.h"
33 #include <sys/socket.h>
34 #include <sys/sysmacros.h>
35 #include <netinet/in_systm.h>
36 #include <sys/promif.h>
37 #include <sys/salib.h>
40 #include <netinet/in.h>
43 #include <netinet/tcp.h>
45 static int atoi(const char *);
46 static int st_accept(void);
47 static int st_bind(void);
48 static int st_connect(void);
49 static int st_echo(void);
50 static int st_getsockname(void);
51 static int st_getsockopt(void);
52 static int st_get_addr_and_port(in_addr_t
*, unsigned short *);
53 static int st_get_buf_and_cnt(char **, int *);
54 static int st_listen(void);
55 static int st_match_option(char *, int *, int *);
56 static int st_send(void);
57 static int st_sendto(void);
58 static int st_recv(void);
59 static int st_recvfrom(void);
60 static int st_set_addr(void);
61 static int st_set_netmask(void);
62 static int st_set_router(void);
63 static int st_setsockopt(void);
64 static int st_socket(void);
65 static int st_sock_close(void);
66 static int st_tcp_tw_report(void);
67 static int st_toggle_promiscuous(void);
68 static int st_use_obp(void);
70 /* Wrapper for socket calls. */
71 static int st_local_accept(int, struct sockaddr
*, socklen_t
*);
72 static int st_local_bind(int, const struct sockaddr
*, socklen_t
);
73 static int st_local_connect(int, const struct sockaddr
*, socklen_t
);
74 static int st_local_getsockname(int, struct sockaddr
*, socklen_t
*);
75 static int st_local_getsockopt(int, int, int, void *, socklen_t
*);
76 static int st_local_listen(int, int);
77 static int st_local_recv(int, void *, size_t, int);
78 static int st_local_recvfrom(int, void *, size_t, int, struct sockaddr
*,
80 static int st_local_send(int, const void *, size_t, int);
81 static int st_local_sendto(int, const void *, size_t, int,
82 const struct sockaddr
*, socklen_t
);
83 static int st_local_setsockopt(int, int, int, const void *, socklen_t
);
84 static int st_local_socket(int, int, int);
85 static int st_local_socket_close(int);
87 struct sock_test_cmd_s
{
92 static struct sock_test_cmd_s st_cmds
[] = {
93 { "set_addr", st_set_addr
},
94 { "set_netmask", st_set_netmask
},
95 { "set_router", st_set_router
},
96 { "socket", st_socket
},
98 { "accept", st_accept
},
99 { "connect", st_connect
},
100 { "listen", st_listen
},
102 { "sendto", st_sendto
},
104 { "recvfrom", st_recvfrom
},
105 { "setsockopt", st_setsockopt
},
106 { "getsockopt", st_getsockopt
},
107 { "getsockname", st_getsockname
},
108 { "close", st_sock_close
},
110 { "toggle_promiscous", st_toggle_promiscuous
},
111 { "use_obp", st_use_obp
},
112 { "tcp_tw_report", st_tcp_tw_report
},
116 struct so_option_string_s
{
120 } so_option_array
[] = {
121 { "rcvtimeo", SO_RCVTIMEO
, SOL_SOCKET
},
122 { "dontroute", SO_DONTROUTE
, SOL_SOCKET
},
123 { "reuseaddr", SO_REUSEADDR
, SOL_SOCKET
},
124 { "rcvbuf", SO_RCVBUF
, SOL_SOCKET
},
125 { "sndbuf", SO_SNDBUF
, SOL_SOCKET
},
129 #define NO_OPENED_SOCKET -1
131 /* Right now, we only allow one socket at one time. */
132 static int g_sock_fd
= NO_OPENED_SOCKET
;
133 static int save_g_sock_fd
= NO_OPENED_SOCKET
;
135 /* Boolean to decide if OBP network routines should be used. */
136 static boolean_t use_obp
= B_FALSE
;
140 * The following routines are wrappers for the real socket routines. The
141 * boolean use_obp is used to decide whether the real socket routines is
142 * called or the "equivalent" OBP provided routines should be called.
145 st_local_socket(int domain
, int type
, int protocol
)
148 return (socket(domain
, type
, protocol
));
155 st_local_socket_close(int sd
)
158 return (socket_close(sd
));
165 st_local_accept(int sd
, struct sockaddr
*addr
, socklen_t
*addr_len
)
168 return (accept(sd
, addr
, addr_len
));
175 st_local_bind(int sd
, const struct sockaddr
*name
, socklen_t namelen
)
178 return (bind(sd
, name
, namelen
));
185 st_local_connect(int sd
, const struct sockaddr
*addr
, socklen_t addr_len
)
188 return (connect(sd
, addr
, addr_len
));
195 st_local_listen(int sd
, int backlog
)
198 return (listen(sd
, backlog
));
205 st_local_send(int sd
, const void *msg
, size_t len
, int flags
)
208 return (send(sd
, msg
, len
, flags
));
215 st_local_sendto(int sd
, const void *msg
, size_t len
, int flags
,
216 const struct sockaddr
*to
, socklen_t tolen
)
219 return (sendto(sd
, msg
, len
, flags
, to
, tolen
));
226 st_local_recv(int sd
, void *buf
, size_t len
, int flags
)
229 return (recv(sd
, buf
, len
, flags
));
236 st_local_recvfrom(int sd
, void *buf
, size_t len
, int flags
,
237 struct sockaddr
*from
, socklen_t
*fromlen
)
240 return (recvfrom(sd
, buf
, len
, flags
, from
, fromlen
));
247 st_local_getsockname(int sd
, struct sockaddr
*name
, socklen_t
*namelen
)
250 return (getsockname(sd
, name
, namelen
));
258 st_local_getsockopt(int sd
, int level
, int option
, void *optval
,
262 return (getsockopt(sd
, level
, option
, optval
, optlen
));
269 st_local_setsockopt(int sd
, int level
, int option
, const void *optval
,
273 return (setsockopt(sd
, level
, option
, optval
, optlen
));
283 int c
= *p
++, neg
= 0;
297 for (n
= 0; isdigit(c
); c
= *p
++) {
298 n
*= 10; /* two steps to avoid unnecessary overflow */
299 n
+= '0' - c
; /* accum neg to avoid surprises at MAX */
301 return (neg
? n
: -n
);
305 st_interpret(char *buf
)
310 if ((cmd
= strtok(buf
, " ")) == NULL
)
313 for (i
= 0; st_cmds
[i
].st_cmd
!= NULL
; i
++) {
314 if (strcmp(cmd
, st_cmds
[i
].st_cmd
) == 0) {
315 return (st_cmds
[i
].st_fn());
318 printf("! Unknown command: %s\n", cmd
);
328 if ((type
= strtok(NULL
, " ")) == NULL
) {
329 printf("! usage: socket type\n");
332 if (g_sock_fd
!= NO_OPENED_SOCKET
) {
333 printf("! Cannot open more than 1 socket\n");
337 if (strcmp(type
, "stream") == 0) {
338 if ((g_sock_fd
= st_local_socket(AF_INET
, SOCK_STREAM
,
340 printf("! Error in opening TCP socket: %d\n", errno
);
343 printf("@ TCP socket opened\n");
345 } else if (strcmp(type
, "dgram") == 0) {
346 if ((g_sock_fd
= st_local_socket(AF_INET
, SOCK_DGRAM
,
348 printf("! Error in opening UDP socket: %d\n", errno
);
351 printf("@ UDP socket opened\n");
353 } else if (strcmp(type
, "raw") == 0) {
354 if ((g_sock_fd
= st_local_socket(AF_INET
, SOCK_RAW
, 0)) < 0) {
355 printf("! Error in opening RAW socket: %d\n", errno
);
358 printf("@ RAW socket opened\n");
361 printf("! Unknown socket type: %s\n", type
);
374 tmp
= strtok(NULL
, " ");
376 printf("! No address given\n");
379 if ((addr
.s_addr
= inet_addr(tmp
)) == (uint32_t)-1) {
380 printf("! Malformed address\n");
384 ipv4_setipaddr(&addr
);
385 printf("@ IP address %s set\n", inet_ntoa(addr
));
396 tmp
= strtok(NULL
, " ");
398 printf("! No netmask given\n");
401 if ((addr
.s_addr
= inet_addr(tmp
)) == (uint32_t)-1) {
402 printf("! Malformed netmask\n");
406 ipv4_setnetmask(&addr
);
407 printf("@ Netmask %s set\n", inet_ntoa(addr
));
418 tmp
= strtok(NULL
, " ");
420 printf("! No router address given\n");
423 if ((addr
.s_addr
= inet_addr(tmp
)) == (uint32_t)-1) {
424 printf("! Malformed router address\n");
428 ipv4_setdefaultrouter(&addr
);
429 if (ipv4_route(IPV4_ADD_ROUTE
, RT_DEFAULT
, NULL
, &addr
) < 0) {
430 printf("! Cannot add default route\n");
432 printf("@ Default router %s set\n", inet_ntoa(addr
));
439 st_get_addr_and_port(in_addr_t
*addr
, unsigned short *port
)
443 if (g_sock_fd
== NO_OPENED_SOCKET
) {
444 printf("! No socket opened\n");
448 tmp
= strtok(NULL
, "/");
450 printf("! No address given\n");
453 if ((*addr
= inet_addr(tmp
)) == (uint32_t)-1) {
454 printf("! Malformed address\n");
458 tmp
= strtok(NULL
, " ");
460 printf("! No port given\n");
463 *port
= htons(atoi(tmp
));
471 struct sockaddr_in local_addr
;
473 if (st_get_addr_and_port(&(local_addr
.sin_addr
.s_addr
),
474 &(local_addr
.sin_port
)) < 0) {
478 local_addr
.sin_family
= AF_INET
;
479 if (st_local_bind(g_sock_fd
, (struct sockaddr
*)&local_addr
,
480 sizeof (local_addr
)) < 0) {
481 printf("! Bind failed: %d\n", errno
);
484 printf("@ Socket bound to %s/%d\n", inet_ntoa(local_addr
.sin_addr
),
485 ntohs(local_addr
.sin_port
));
494 if (g_sock_fd
== NO_OPENED_SOCKET
) {
495 printf("! No socket opened\n");
498 if ((tmp
= strtok(NULL
, " ")) == NULL
) {
499 printf("! No backlog given\n");
502 if (st_local_listen(g_sock_fd
, atoi(tmp
)) < 0) {
503 printf("! Listen failed: %d\n", errno
);
506 printf("@ Listen succeeded\n");
513 struct sockaddr_in addr
;
517 if (g_sock_fd
== NO_OPENED_SOCKET
) {
518 printf("! No socket opened\n");
521 addr_len
= sizeof (struct sockaddr_in
);
522 if ((sd
= st_local_accept(g_sock_fd
, (struct sockaddr
*)&addr
,
524 printf("! Accept failed: %d\n", errno
);
527 printf("@ Accept succeeded from %s:%d. Socket descriptor saved\n",
528 inet_ntoa(addr
.sin_addr
), ntohs(addr
.sin_port
));
529 save_g_sock_fd
= g_sock_fd
;
537 struct sockaddr_in peer_addr
;
539 if (st_get_addr_and_port(&(peer_addr
.sin_addr
.s_addr
),
540 &(peer_addr
.sin_port
)) < 0) {
544 peer_addr
.sin_family
= AF_INET
;
545 if (st_local_connect(g_sock_fd
, (struct sockaddr
*)&peer_addr
,
546 sizeof (peer_addr
)) < 0) {
547 printf("! Connect failed: %d\n", errno
);
550 printf("@ Socket connected to %s/%d\n", inet_ntoa(peer_addr
.sin_addr
),
551 ntohs(peer_addr
.sin_port
));
557 st_get_buf_and_cnt(char **buf
, int *send_cnt
)
561 if ((*buf
= strtok(NULL
, " ")) == NULL
) {
562 printf("! No send buffer\n");
565 if ((cnt
= strtok(NULL
, " ")) == NULL
) {
566 printf("! Missing send length\n");
570 if ((*send_cnt
= atoi(cnt
)) < 0) {
571 printf("! Invalid send count\n");
583 if (g_sock_fd
== NO_OPENED_SOCKET
) {
584 printf("! No socket opened\n");
588 if (st_get_buf_and_cnt(&buf
, &send_cnt
) < 0)
591 if ((send_cnt
= st_local_send(g_sock_fd
, buf
, send_cnt
, 0)) < 0) {
592 printf("! Send failed: %d\n", errno
);
595 printf("@ Send %d bytes\n", send_cnt
);
603 struct sockaddr_in peer_addr
;
607 if (st_get_addr_and_port(&(peer_addr
.sin_addr
.s_addr
),
608 &(peer_addr
.sin_port
)) < 0) {
611 peer_addr
.sin_family
= AF_INET
;
613 if (st_get_buf_and_cnt(&buf
, &send_cnt
) < 0)
616 if ((send_cnt
= st_local_sendto(g_sock_fd
, buf
, send_cnt
, 0,
617 (struct sockaddr
*)&peer_addr
, sizeof (peer_addr
))) < 0) {
618 printf("! Sendto failed: %d\n", errno
);
621 printf("@ Send %d bytes\n", send_cnt
);
633 if (g_sock_fd
== NO_OPENED_SOCKET
) {
634 printf("! No socket opened\n");
638 if ((tmp
= strtok(NULL
, " ")) == NULL
) {
639 printf("! No buffer len given\n");
644 if ((buf
= bkmem_zalloc(buf_len
)) == NULL
) {
645 printf("! Cannot allocate buffer: %d\n", errno
);
648 if ((ret
= st_local_recv(g_sock_fd
, buf
, buf_len
, 0)) <= 0) {
650 printf("@ EOF received: %d\n", errno
);
653 printf("! Cannot recv: %d\n", errno
);
656 printf("@ Bytes received: %d\n", ret
);
658 bkmem_free(buf
, buf_len
);
668 struct sockaddr_in from
;
671 if (g_sock_fd
== NO_OPENED_SOCKET
) {
672 printf("! No socket opened\n");
676 if ((tmp
= strtok(NULL
, " ")) == NULL
) {
677 printf("! No buffer len given\n");
682 if ((buf
= bkmem_zalloc(buf_len
)) == NULL
) {
683 printf("! Cannot allocate buffer: %d\n", errno
);
686 fromlen
= sizeof (from
);
687 if ((ret
= st_local_recvfrom(g_sock_fd
, buf
, buf_len
, 0,
688 (struct sockaddr
*)&from
, &fromlen
)) <= 0) {
690 printf("@ EOF received: %d\n", errno
);
693 printf("! Cannot recv: %d\n", errno
);
696 printf("@ Bytes received from %s/%d: %d\n",
697 inet_ntoa(from
.sin_addr
), ntohs(from
.sin_port
), ret
);
699 bkmem_free(buf
, buf_len
);
704 * To act as an echo server. Note that it assumes the address and
705 * netmask have been set.
711 int listen_fd
, newfd
;
713 struct sockaddr_in addr
;
717 int buf_len
, ret
, snd_cnt
;
719 tmp
= strtok(NULL
, " ");
721 printf("! No echo port given\n");
724 echo_port
= atoi(tmp
);
725 tmp
= strtok(NULL
, " ");
727 printf("! No buffer size given\n");
732 /* Create local socket for echo server */
733 if ((listen_fd
= st_local_socket(AF_INET
, SOCK_STREAM
, 0)) < 0) {
734 printf("! Error in opening TCP socket: %d\n", errno
);
737 printf("@ Local TCP socket opened\n");
740 /* Bind local socket */
741 addr
.sin_family
= AF_INET
;
742 addr
.sin_port
= htons(echo_port
);
743 addr
.sin_addr
.s_addr
= INADDR_ANY
;
745 if (st_local_bind(listen_fd
, (struct sockaddr
*)&addr
,
746 sizeof (addr
)) < 0) {
747 printf("! Bind failed: %d\n", errno
);
750 if (st_local_listen(listen_fd
, backlog
) < 0) {
751 printf("! Listen failed: %d\n", errno
);
755 addr_size
= sizeof (addr
);
756 if ((newfd
= st_local_accept(listen_fd
, (struct sockaddr
*)&addr
,
758 printf("! Accept failed: %d\n", errno
);
759 (void) st_local_socket_close(listen_fd
);
762 printf("@ Accepted connection: %s/%d\n", inet_ntoa(addr
.sin_addr
),
763 ntohs(addr
.sin_port
));
764 (void) st_local_socket_close(listen_fd
);
766 if ((buf
= bkmem_zalloc(buf_len
)) == NULL
) {
767 printf("! Cannot allocate buffer: %d\n", errno
);
768 (void) st_local_socket_close(newfd
);
771 while ((ret
= st_local_recv(newfd
, buf
, buf_len
, 0)) > 0) {
772 printf("@ Bytes received: %d\n", ret
);
774 if ((snd_cnt
= st_local_send(newfd
, buf
, ret
, 0)) < ret
) {
775 printf("! Send failed: %d\n", errno
);
776 bkmem_free(buf
, buf_len
);
779 printf("@ Sent %d bytes\n", snd_cnt
);
781 (void) st_local_socket_close(newfd
);
783 printf("! Cannot recv: %d\n", errno
);
784 bkmem_free(buf
, buf_len
);
792 st_match_option(char *opt_s
, int *opt
, int *opt_level
)
796 for (i
= 0; so_option_array
[i
].so_name
!= NULL
; i
++) {
797 if (strcmp(so_option_array
[i
].so_name
, opt_s
) == 0) {
798 *opt
= so_option_array
[i
].so_opt
;
799 *opt_level
= so_option_array
[i
].so_opt_level
;
803 printf("! Unknown option\n");
811 int opt
, opt_level
, opt_val
;
813 if (g_sock_fd
== NO_OPENED_SOCKET
) {
814 printf("! No socket opened\n");
818 if ((tmp
= strtok(NULL
, " ")) == NULL
) {
819 printf("! No option given\n");
822 if (st_match_option(tmp
, &opt
, &opt_level
) < 0) {
826 /* We only support integer option for the moment. */
827 if ((tmp
= strtok(NULL
, " ")) == NULL
) {
828 printf("! No option value given\n");
833 if (st_local_setsockopt(g_sock_fd
, opt_level
, opt
, &opt_val
,
835 printf("! Cannot set option: %d\n", errno
);
838 printf("@ Option set successfully\n");
845 struct sockaddr_in addr
;
848 if (g_sock_fd
== NO_OPENED_SOCKET
) {
849 printf("! No socket opened\n");
854 if (st_local_getsockname(g_sock_fd
, (struct sockaddr
*)&addr
,
856 printf("! getsockname failed: %d\n", errno
);
859 printf("@ Local socket name: %s/%d\n", inet_ntoa(addr
.sin_addr
),
860 ntohs(addr
.sin_port
));
868 int opt
, opt_level
, opt_val
;
871 if (g_sock_fd
== NO_OPENED_SOCKET
) {
872 printf("! No socket opened\n");
876 if ((tmp
= strtok(NULL
, " ")) == NULL
) {
877 printf("! No option given\n");
880 if (st_match_option(tmp
, &opt
, &opt_level
) < 0) {
884 opt_len
= sizeof (opt_val
);
885 if (st_local_getsockopt(g_sock_fd
, opt_level
, opt
, &opt_val
,
887 printf("! Cannot get option: %d\n", errno
);
890 printf("@ Option value is %d\n", opt_val
);
897 if (g_sock_fd
== NO_OPENED_SOCKET
) {
898 printf("! No socket opened\n");
901 if (st_local_socket_close(g_sock_fd
) < 0) {
902 printf("! Error in closing socket: %d\n", errno
);
905 printf("@ Socket closed");
906 if (save_g_sock_fd
!= NO_OPENED_SOCKET
) {
907 g_sock_fd
= save_g_sock_fd
;
908 save_g_sock_fd
= NO_OPENED_SOCKET
;
909 printf(", switching to saved socket descriptor\n");
911 g_sock_fd
= NO_OPENED_SOCKET
;
918 st_toggle_promiscuous(void)
920 /* We always start with non-promiscuous mode. */
921 static boolean_t promiscuous
= B_FALSE
;
923 promiscuous
= !promiscuous
;
924 (void) ipv4_setpromiscuous(promiscuous
);
925 printf("@ Setting promiscuous to %d\n", promiscuous
);
932 if ((use_obp
= !use_obp
) == B_TRUE
) {
933 printf("@ Now using OBP routines\n");
935 printf("@ Now using socket routines\n");
941 st_tcp_tw_report(void)
943 printf("@ TCP Time Wait report\n");
944 tcp_time_wait_report();