1 /* SCTP kernel Implementation
2 * (C) Copyright IBM Corp. 2001, 2003
3 * Copyright (c) 1999 Cisco
4 * Copyright (c) 1999, 2000, 2001 Motorola
5 * Copyright (c) 2001 Nokia
6 * Copyright (c) 2001 La Monte H.P. Yarroll
8 * The SCTP implementation is free software;
9 * you can redistribute it and/or modify it under the terms of
10 * the GNU General Public License as published by
11 * the Free Software Foundation; either version 2, or (at your option)
14 * The SCTP implementation is distributed in the hope that it
15 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
16 * ************************
17 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18 * See the GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with GNU CC; see the file COPYING. If not, write to
22 * the Free Software Foundation, 59 Temple Place - Suite 330,
23 * Boston, MA 02111-1307, USA.
25 * Please send any bug reports or fixes you make to the
27 * lksctp developers <lksctp-developers@lists.sourceforge.net>
29 * Or submit a bug report through the following website:
30 * http://www.sf.net/projects/lksctp
32 * Any bugs reported to us we will try to fix... any fixes shared will
33 * be incorporated into the next SCTP release.
35 * Written or modified by:
36 * La Monte H.P. Yarroll <piggy@acm.org>
37 * Karl Knutson <karl@athena.chicago.il.us>
38 * Hui Huang <hui.huang@nokia.com>
39 * Daisy Chang <daisyc@us.ibm.com>
40 * Sridhar Samudrala <sri@us.ibm.com>
43 /* This is a userspace test application for the SCTP kernel
44 * implementation state machine. It is vaguely inspired by Stevens'
47 * It has the limited ability to send messages and to listen for messages
59 #include <sys/types.h>
60 #include <sys/socket.h>
62 #include <netinet/in.h>
63 #include <sys/errno.h>
64 #include <sys/param.h>
66 #include <arpa/inet.h>
69 #include <netinet/sctp.h>
73 #include "sctp_darn.h"
75 char *TCID = __FILE__;
79 #define GEN_DATA_FIRST 0x21
80 #define GEN_DATA_LAST 0x7e
82 /* Display an IPv4 address in readable format. */
83 #define NIPQUAD(addr) \
84 ((unsigned char *)&addr)[0], \
85 ((unsigned char *)&addr)[1], \
86 ((unsigned char *)&addr)[2], \
87 ((unsigned char *)&addr)[3]
89 /* Display an IPv6 address in readable format. */
91 ntohs((addr).s6_addr16[0]), \
92 ntohs((addr).s6_addr16[1]), \
93 ntohs((addr).s6_addr16[2]), \
94 ntohs((addr).s6_addr16[3]), \
95 ntohs((addr).s6_addr16[4]), \
96 ntohs((addr).s6_addr16[5]), \
97 ntohs((addr).s6_addr16[6]), \
98 ntohs((addr).s6_addr16[7])
100 /* These are the global options. */
101 char *local_host = NULL;
103 char *remote_host = NULL;
105 command_t command = COMMAND_NONE;
106 struct sockaddr *bindx_add_addrs = NULL;
107 int bindx_add_count = 0;
108 struct sockaddr *bindx_rem_addrs = NULL;
109 int bindx_rem_count = 0;
110 struct sockaddr *connectx_addrs = NULL;
111 int connectx_count = 0;
112 int interactive_mode = 0;
116 char gen_data = GEN_DATA_FIRST;
117 char *inter_outbuf = NULL;
118 int inter_outlen = 0;
120 int poll_snd_size = 0;
122 int socket_type = SOCK_SEQPACKET;
123 sctp_assoc_t associd = 0;
125 char *interface = "eth0";
127 sockaddr_storage_t remote_addr;
128 sa_family_t ra_family; /* What family is remote_addr? */
129 int ra_len = 0; /* How long is remote_addr? */
130 void *ra_raw; /* This is the addr part of remote_addr. */
131 int new_connection = 1;
158 struct inter_entry inter_commands[] = {
161 {"sndbuf", INTER_SNDBUF},
162 {"rcvbuf", INTER_RCVBUF},
163 {"bindx-add", INTER_BINDX_ADD},
164 {"bindx-rem", INTER_BINDX_REM},
165 {"primary", INTER_SET_PRIM},
166 {"peer_primary", INTER_SET_PEER_PRIM},
167 {"shutdown", INTER_SHUTDOWN},
168 {"abort", INTER_ABORT},
169 {"nodelay", INTER_NODELAY},
170 {"maxseg", INTER_MAXSEG},
174 #define POLL_SK_MAX 256 /* The max number of sockets to select/poll. */
175 int poll_sks[POLL_SK_MAX]; /* The array for using select(). */
176 struct pollfd poll_fds[POLL_SK_MAX]; /* The array for using poll(). */
177 #define POLL_SND_SIZE 16384 /* Default message size in the poll mode. */
180 struct sockaddr *append_addr(const char *parm, struct sockaddr *addrs,
182 int build_endpoint(char *argv0, int portnum);
183 static int parse_inter_commands(char *, char *, int);
184 static void snd_func(char *);
185 static void sndbuf_func(char *, int, int, int);
186 static void rcvbuf_func(char *, int, int, int);
187 static struct sockaddr *get_bindx_addr(char *, int *);
188 static int bindx_func(char *, int, struct sockaddr *, int, int, int);
189 static int connectx_func(char *, int, struct sockaddr *, int);
190 static void primary_func(char *, int, char *, int);
191 static void peer_primary_func(char *, int, char *, int);
192 static int nodelay_func(char *, int, int val, int set);
193 static int maxseg_func(char *, int, int val, int set);
194 static int shutdown_func(char *argv0, int *skp, int shutdown_type);
195 static int test_sk_for_assoc(int sk, sctp_assoc_t assoc_id);
196 static char * gen_message(int);
197 static sctp_assoc_t test_recv_assoc_change(int);
198 static sctp_assoc_t test_verify_assoc_change(struct msghdr *);
199 void print_addr_buf(void * laddrs, int n_laddrs);
200 int print_sockaddr(struct sockaddr *sa_addr);
203 main(int argc, char *argv[]) {
208 signal(SIGPIPE, SIG_IGN);
210 parse_arguments(argc, argv);
214 fprintf(stderr, "%s: Please specify a command.\n",
219 sk = build_endpoint(argv[0], local_port);
220 error = command_listen(argv[0], sk);
223 sk = build_endpoint(argv[0], local_port);
224 error = command_send(argv[0], &sk);
228 for (i = 0; i < poll_skn; i++) {
229 poll_fds[i].fd = build_endpoint(argv[0],
233 for (i = 0; i < poll_skn; i++) {
234 poll_sks[i] = build_endpoint(argv[0],
238 error = command_poll(argv[0]);
241 fprintf(stderr, "%s: illegal command %d\n",
246 /* Shut down the link. */
247 if (COMMAND_POLL != command) {
250 /* Shutdown all links. */
252 for (i = 0; i < poll_skn; i++) {
253 close(poll_fds[i].fd);
256 for (i = 0; i < poll_skn; i++) {
265 /********************************************************************
266 * 2nd Level Abstractions
267 ********************************************************************/
270 parse_arguments(int argc, char *argv[]) {
271 int option_index = 0;
273 struct sockaddr *tmp_addrs = NULL;
275 static struct option long_options[] = {
277 {"local-port", 1, 0, 2},
279 {"remote-port", 1, 0, 4},
280 {"listen", 0, 0, 10},
282 {"bindx-add", 1, 0, 15},
283 {"bindx-rem", 1, 0, 16},
284 {"use-poll", 0, 0, 20},
286 {"interface", optional_argument, 0, 5,},
287 {"connectx", 1, 0, 17},
291 /* Parse the arguments. */
293 c = getopt_long (argc, argv, "B:H:IP:b:h:i:p:lm:nstz:ec:",
294 long_options, &option_index);
300 printf("option %s", long_options[option_index].name);
302 printf(" with arg %s", optarg);
306 case 1: /* local host */
310 case 2: /* local port */
312 local_port = atoi(optarg);
314 case 3: /* remote host */
316 remote_host = optarg;
318 case 4: /* remote port */
320 remote_port = atoi(optarg);
322 case 5: /* interface for sin6_scope_id */
325 if_index = if_nametoindex(interface);
327 printf("Interface %s unknown\n", interface);
332 case 10: /* listen */
336 "%s: pick ONE of listen or send\n",
340 command = COMMAND_LISTEN;
348 "%s: pick ONE of listen or send\n",
352 command = COMMAND_SEND;
356 case 15: /* bindx_add */
359 append_addr(optarg, bindx_add_addrs,
361 if (NULL == tmp_addrs) {
362 /* We have no memory, so keep fprintf()
363 * from trying to allocate more.
365 fprintf(stderr, "No memory to add ");
366 fprintf(stderr, optarg);
367 fprintf(stderr, "\n");
370 bindx_add_addrs = tmp_addrs;
374 case 16: /* bindx_rem */
377 append_addr(optarg, bindx_rem_addrs,
379 if (NULL == tmp_addrs) {
380 /* We have no memory, so keep fprintf()
381 * from trying to allocate more.
383 fprintf(stderr, "No memory to add ");
384 fprintf(stderr, optarg);
385 fprintf(stderr, "\n");
388 bindx_rem_addrs = tmp_addrs;
390 case 17: /* connectx */
393 append_addr(optarg, connectx_addrs,
395 if (NULL == tmp_addrs) {
396 /* We have no memory, so keep fprintf()
397 * from trying to allocate more.
399 fprintf(stderr, "No memory to add ");
400 fprintf(stderr, optarg);
401 fprintf(stderr, "\n");
404 connectx_addrs = tmp_addrs;
406 case 20: /* use-poll */
410 interactive_mode = 1;
413 command = COMMAND_POLL;
414 poll_skn = atoi(optarg);
415 if (poll_skn <= 0 || poll_skn > POLL_SK_MAX) {
416 fprintf(stderr, "Too many sockets for ");
417 fprintf(stderr, "for polling\n");
422 opt_space = atoi(optarg);
428 socket_type = SOCK_STREAM;
431 poll_snd_size = atoi(optarg);
432 if (poll_snd_size <= 0) {
433 fprintf(stderr, "Bad message size.\n");
445 printf ("%s: unrecognized option 0%c\n",
454 fprintf(stderr, "%s: non-option arguments are illegal: ",
456 while (optind < argc)
457 fprintf(stderr, "%s ", argv[optind++]);
458 fprintf (stderr, "\n");
464 if (NULL == local_host) {
465 fprintf(stderr, "%s: You MUST provide a local host.\n",
471 if (command == COMMAND_SEND && NULL == remote_host
472 && connectx_count == 0) {
473 fprintf(stderr, "%s: You MUST provide a remote host for sending.\n",
479 if (remote_host != NULL && connectx_count != 0) {
480 fprintf(stderr, "%s: You can not provide both -h and -c options.\n",
485 } /* parse_arguments() */
487 /* Set up the local endpoint. */
489 build_endpoint(char *argv0, int portnum)
493 sockaddr_storage_t local_addr;
494 sa_family_t la_family; /* What family is local_addr? */
495 int la_len; /* How long is local_addr? */
496 void *la_raw; /* This is the addr part of local_addr. */
498 struct sctp_event_subscribe subscribe;
500 /* Get the transport address for the local host name. */
501 hst = gethostbyname(local_host);
503 hst = gethostbyname2(local_host, AF_INET6);
506 if (hst == NULL || hst->h_length < 1) {
507 fprintf(stderr, "%s: bad hostname: %s\n", argv0, local_host);
511 la_family = hst->h_addrtype;
514 la_len = sizeof(local_addr.v4);
515 la_raw = &local_addr.v4.sin_addr;
516 local_addr.v4.sin_port = htons(portnum);
517 local_addr.v4.sin_family = AF_INET;
520 la_len = sizeof(local_addr.v6);
521 la_raw = &local_addr.v6.sin6_addr;
522 local_addr.v6.sin6_port = htons(portnum);
523 local_addr.v6.sin6_family = AF_INET6;
524 local_addr.v6.sin6_scope_id = if_index;
527 fprintf(stderr, "Invalid address type.\n");
531 memcpy(la_raw, hst->h_addr_list[0], hst->h_length);
533 /* Create the local endpoint. */
534 retval = socket(la_family, socket_type, IPPROTO_SCTP);
536 fprintf(stderr, "%s: failed to create socket: %s.\n",
537 argv0, strerror(errno));
541 if (SOCK_SEQPACKET == socket_type) {
542 memset(&subscribe, 0, sizeof(subscribe));
543 subscribe.sctp_data_io_event = 1;
544 subscribe.sctp_association_event = 1;
545 error = setsockopt(retval, SOL_SCTP, SCTP_EVENTS,
546 (char *)&subscribe, sizeof(subscribe));
548 fprintf(stderr, "SCTP_EVENTS: error: %d\n", error);
553 /* Bind this socket to the test port. */
554 error = bind(retval, &local_addr.sa, la_len);
556 fprintf(stderr, "%s: can not bind to %s:%d: %s.\n",
557 argv0, local_host, portnum,
562 /* Do we need to do bindx() to add any additional addresses? */
563 if (bindx_add_addrs) {
564 if (0 != bindx_func(argv0, retval, bindx_add_addrs,
565 bindx_add_count, SCTP_BINDX_ADD_ADDR, portnum)) {
566 fprintf(stderr, "bindx_func (add) failed.\n");
569 } /* if (bindx_add_addrs) */
571 /* Do we need to do bindx() to remove any bound addresses? */
572 if (bindx_rem_addrs) {
573 if (0 != bindx_func(argv0, retval, bindx_rem_addrs,
574 bindx_rem_count, SCTP_BINDX_REM_ADDR, portnum)) {
575 fprintf(stderr, "bindx_func (remove) failed.\n");
578 } /* if (bindx_rem_addrs) */
580 /* Do we want to run in the non-blocking mode? */
582 error = fcntl(retval, F_SETFL, O_NONBLOCK);
584 fprintf(stderr, "%s: error fcntl: %s.\n",
585 argv0, strerror(errno));
591 sndbuf_func(argv0, retval, opt_space, 1);
592 rcvbuf_func(argv0, retval, opt_space, 1);
597 } /* build_endpoint() */
599 /* Convenience structure to determine space needed for cmsg. */
601 struct sctp_initmsg init;
602 struct sctp_sndrcvinfo sndrcvinfo;
606 /* Listen on the socket, printing out anything that arrives. */
608 command_listen(char *argv0, int sk)
610 char incmsg[CMSG_SPACE(sizeof(_sctp_cmsg_data_t))];
612 struct msghdr inmessage;
613 sockaddr_storage_t msgname;
614 char message[REALLY_BIG];
620 /* Mark sk as being able to accept new associations */
621 error = listen(sk, 5);
623 printf("\n\n\t\tlisten Failure: %s.\n\n\n",
629 if (!interactive_mode) {
630 printf("Use -I for interactive mode with");
631 printf(" -n nonblocking\n");
636 /* Initialize the global value for interactive mode functions. */
637 if (interactive_mode) {
641 /* Initialize inmessage with enough space for DATA... */
642 memset(&inmessage, 0, sizeof(inmessage));
643 if ((iov.iov_base = malloc(REALLY_BIG)) == NULL) {
644 printf("%s: Can't allocate memory.\n", argv0);
647 iov.iov_len = REALLY_BIG;
648 inmessage.msg_iov = &iov;
649 inmessage.msg_iovlen = 1;
650 /* or a control message. */
651 inmessage.msg_control = incmsg;
652 inmessage.msg_controllen = sizeof(incmsg);
653 inmessage.msg_name = &msgname;
654 inmessage.msg_namelen = sizeof(msgname);
656 printf("%s listening...\n", argv0);
657 /* Get the messages sent */
660 if (interactive_mode) {
661 /* Read from the user. */
663 printf("%s:%d-%s:%d Interactive mode> ",
664 local_host, local_port, remote_host,
667 printf("%s:%d-", local_host, local_port);
669 print_sockaddr(&remote_addr.sa);
671 printf("?:%d", remote_port);
673 printf(" Interactive mode> ");
676 if (NULL == fgets(message, REALLY_BIG, stdin)) {
681 if (0 <= (c = parse_inter_commands(argv0, message,
683 if (INTER_RCV != c) {
691 if (socket_type == SOCK_STREAM) {
695 if ((recvsk = accept(sk, NULL, &len)) < 0) {
696 fprintf(stderr, "%s: error: %s.\n",
697 argv0, strerror(errno));
706 error = recvmsg(recvsk, &inmessage, MSG_WAITALL);
708 if (nonblocking && (EAGAIN == errno)) {
713 if (socket_type == SOCK_STREAM) {
714 if (ENOTCONN != errno)
716 printf("No association is present now!!\n");
724 /* Update the associd when a notification is received on a
727 if (inmessage.msg_flags & MSG_NOTIFICATION)
728 associd = test_verify_assoc_change(&inmessage);
731 if( !(MSG_NOTIFICATION & inmessage.msg_flags)) {
732 sendto(recvsk, inmessage.msg_iov->iov_base,
733 error, 0, (struct sockaddr *)&msgname,
738 test_print_message(sk, &inmessage, error);
740 inmessage.msg_control = incmsg;
741 inmessage.msg_controllen = sizeof(incmsg);
742 inmessage.msg_name = &msgname;
743 inmessage.msg_namelen = sizeof(msgname);
744 iov.iov_len = REALLY_BIG;
746 /* Verify that the association is no longer present. */
747 if (0 != test_sk_for_assoc(recvsk, associd)) {
748 printf("No association is present now!!\n");
749 if (socket_type == SOCK_STREAM) {
757 fprintf(stderr, "%s: error: %s.\n",
758 argv0, strerror(errno));
764 } /* command_listen() */
766 /* Read lines from stdin and send them to the socket. */
768 command_send(char *argv0, int *skp)
770 struct msghdr outmsg;
773 char message[REALLY_BIG];
776 struct sockaddr *addrs;
781 /* Set up the destination. */
782 if (remote_host != NULL) {
783 hst = gethostbyname(remote_host);
785 hst = gethostbyname2(remote_host, AF_INET6);
788 if (hst == NULL || hst->h_length < 1) {
789 fprintf(stderr, "%s: bad hostname: %s\n",
794 ra_family = hst->h_addrtype;
797 ra_len = sizeof(remote_addr.v4);
798 ra_raw = &remote_addr.v4.sin_addr;
799 remote_addr.v4.sin_port = htons(remote_port);
800 remote_addr.v4.sin_family = AF_INET;
803 ra_len = sizeof(remote_addr.v6);
804 ra_raw = &remote_addr.v6.sin6_addr;
805 remote_addr.v6.sin6_port = htons(remote_port);
806 remote_addr.v6.sin6_family = AF_INET6;
807 remote_addr.v6.sin6_scope_id = if_index;
810 fprintf(stderr, "Invalid address type.\n");
814 memcpy(ra_raw, hst->h_addr_list[0], hst->h_length);
817 /* Initialize the global value for interactive mode functions. */
818 if (interactive_mode) {
822 printf("%s ready to send...\n", argv0);
824 /* Read from the user. */
826 if (interactive_mode) {
827 printf("%s:%d-%s:%d Interactive mode> ",
828 local_host, local_port, remote_host,
831 printf("%s:%d-%s:%d> ",
832 local_host, local_port,
833 remote_host, remote_port);
836 printf("%s:%d-", local_host, local_port);
838 print_sockaddr(&remote_addr.sa);
840 printf("XXXXXX:%d", remote_port);
842 if (interactive_mode) {
843 printf(" Interactive mode> ");
849 if (NULL == fgets(message, REALLY_BIG, stdin)) {
854 if (interactive_mode) {
855 /* This is the send only agent. */
856 if (0 <= (c = parse_inter_commands(argv0, message,
858 if (INTER_SND == c) {
859 iov.iov_base = inter_outbuf;
860 msglen = inter_outlen;
861 iov.iov_len = msglen;
871 /* Send to our neighbor. */
872 msglen = strlen(message) + 1;
873 iov.iov_len = msglen;
876 /* For a UDP-style socket, verify if an existing association
877 * has gone. If so, receive the pending SCTP_ASSOC_CHANGE
880 if ((SOCK_SEQPACKET == socket_type) && associd &&
881 (0 != test_sk_for_assoc(sk, associd))) {
882 associd = test_recv_assoc_change(sk);
883 printf("Old association gone, Starting a new one!\n");
887 if (new_connection && connectx_count != 0) {
888 /* Do a sctp_connectx() to establish a connection. */
889 error = connectx_func(argv0, sk, connectx_addrs,
893 printf("Connection refused\n");
894 if (SOCK_SEQPACKET == socket_type) {
895 associd = test_recv_assoc_change(sk);
899 fprintf(stderr, "connectx failed.\n");
902 if (SOCK_SEQPACKET == socket_type) {
903 associd = test_recv_assoc_change(sk);
907 int rc = sctp_getpaddrs(sk, associd, &addrs);
910 fprintf(stderr, "sctp_getpaddrs failed, no peers.\n");
912 fprintf(stderr, "sctp_getpaddrs failed %s(%d).\n", strerror(errno), errno);
916 printf("New connection, peer addresses\n");
917 print_addr_buf(addrs, rc);
918 ra_family = addrs[0].sa_family;
921 ra_len = sizeof(remote_addr.v4);
924 ra_len = sizeof(remote_addr.v6);
927 fprintf(stderr, "Invalid address type.\n");
930 memcpy(&remote_addr, &addrs[0], ra_len);
931 sctp_freepaddrs(addrs);
936 if (SOCK_SEQPACKET == socket_type ||
937 (connectx_count == 0 && new_connection)) {
938 /* Initialize the message struct we use to pass
939 * messages to the remote socket.
941 if (!interactive_mode) {
942 iov.iov_base = message;
943 iov.iov_len = msglen;
945 outmsg.msg_iov = &iov;
946 outmsg.msg_iovlen = 1;
947 outmsg.msg_control = NULL;
948 outmsg.msg_controllen = 0;
949 outmsg.msg_name = &remote_addr;
950 outmsg.msg_namelen = ra_len;
952 error = sendmsg(sk, &outmsg, 0);
954 error = send(sk, message, msglen, 0);
955 if (error == -1 && errno == EPIPE) {
958 fprintf(stderr, "close failed %s\n", strerror(errno));
961 *skp = sk = build_endpoint(argv0, local_port);
966 if (error != msglen) {
967 fprintf(stderr, "%s: error: %s.\n",
968 argv0, strerror(errno));
969 if (nonblocking && EAGAIN == errno) {
970 if (interactive_mode) {
979 } while (error != msglen);
981 /* If this is the first message sent over a UDP-style socket,
982 * get the associd from the SCTP_ASSOC_CHANGE notification.
984 if ((SOCK_SEQPACKET == socket_type) && (0 == associd))
985 associd = test_recv_assoc_change(sk);
987 /* Verify there is no association. */
988 if (0 != test_sk_for_assoc(sk, associd)) {
989 printf("No association is present now!!\n");
992 if (new_connection) {
993 int rc = sctp_getpaddrs(sk, associd, &addrs);
996 fprintf(stderr, "sctp_getpaddrs failed, no peers.\n");
998 fprintf(stderr, "sctp_getpaddrs failed %s(%d).\n", strerror(errno), errno);
1002 printf("New connection, peer addresses\n");
1003 print_addr_buf(addrs, rc);
1004 sctp_freepaddrs(addrs);
1010 if (interactive_mode) {
1012 inter_outbuf = NULL;
1014 } /* while(!done) */
1018 } /* command_send() */
1020 /* Listen on the array of sockets, printing out anything that arrives. */
1022 command_poll(char *argv0)
1024 char incmsg[CMSG_SPACE(sizeof(_sctp_cmsg_data_t))];
1026 struct msghdr inmessage;
1031 fd_set *ibitsp = NULL;
1032 fd_set *obitsp = NULL;
1033 fd_set *xbitsp = NULL;
1035 struct msghdr outmsg;
1036 struct hostent *hst;
1038 int temp_fd, temp_set;
1042 /* If a remote host is specified, initialize the destination. */
1044 /* Set up the destination. */
1045 hst = gethostbyname(remote_host);
1047 hst = gethostbyname2(remote_host, AF_INET6);
1050 if (hst == NULL || hst->h_length < 1) {
1051 fprintf(stderr, "%s: bad hostname: %s\n",
1052 argv0, remote_host);
1056 ra_family = hst->h_addrtype;
1057 switch (ra_family) {
1059 ra_len = sizeof(remote_addr.v4);
1060 ra_raw = &remote_addr.v4.sin_addr;
1061 remote_addr.v4.sin_port = htons(remote_port);
1062 remote_addr.v4.sin_family = AF_INET;
1065 ra_len = sizeof(remote_addr.v6);
1066 ra_raw = &remote_addr.v6.sin6_addr;
1067 remote_addr.v6.sin6_port = htons(remote_port);
1068 remote_addr.v6.sin6_family = AF_INET6;
1069 remote_addr.v6.sin6_scope_id = if_index;
1072 fprintf(stderr, "Invalid address type.\n");
1076 memcpy(ra_raw, hst->h_addr_list[0], hst->h_length);
1078 /* Initialize the message struct we use to pass messages to
1079 * the remote socket.
1081 outmsg.msg_iov = &iov;
1082 outmsg.msg_iovlen = 1;
1083 outmsg.msg_control = NULL;
1084 outmsg.msg_controllen = 0;
1085 outmsg.msg_name = &remote_addr;
1086 outmsg.msg_namelen = ra_len;
1092 /* Set all of the sockets to be ready for listening. */
1094 for (i = 0; i < poll_skn; i++) {
1095 error = listen(poll_fds[i].fd, 1);
1097 printf("%s: Listen failed on socket number ",
1099 printf("%d: %s.\n", i, strerror(errno));
1103 printf("%s listening...\n", argv0);
1105 for (i = 0; i < poll_skn; i++) {
1106 error = listen(poll_sks[i], 1);
1108 printf("%s: Listen failed on socket number ",
1110 printf("%d: %s.\n", i, strerror(errno));
1113 if (poll_sks[i] > max_fd) {
1114 max_fd = poll_sks[i];
1117 printf("%s listening...\n", argv0);
1119 size = howmany(max_fd + 1, NFDBITS) * sizeof(fd_mask);
1120 if ((ibitsp = (fd_set *)malloc(size)) == NULL) {
1121 printf("%s: Can't allocate memory.\n", argv0);
1124 if ((obitsp = (fd_set *)malloc(size)) == NULL) {
1125 printf("%s: Can't allocate memory.\n", argv0);
1128 if ((xbitsp = (fd_set *)malloc(size)) == NULL) {
1129 printf("%s: Can't allocate memory.\n", argv0);
1132 memset(ibitsp, 0, size);
1133 memset(obitsp, 0, size);
1134 memset(xbitsp, 0, size);
1138 /* Initialize inmessage with enough space for DATA... */
1139 memset(&inmessage, 0, sizeof(inmessage));
1140 if ((iov.iov_base = malloc(REALLY_BIG)) == NULL) {
1141 printf("%s: Can't allocate memory.\n", argv0);
1144 iov.iov_len = REALLY_BIG;
1145 inmessage.msg_iov = &iov;
1146 inmessage.msg_iovlen = 1;
1147 /* or a control message. */
1148 inmessage.msg_control = incmsg;
1149 inmessage.msg_controllen = sizeof(incmsg);
1153 /* Set the default send message size. */
1154 if (!poll_snd_size) {
1155 poll_snd_size = POLL_SND_SIZE;
1161 for (i = 0; i < poll_skn; i++) {
1162 poll_fds[i].events = POLLIN;
1165 /* Poll output on the first socket. */
1166 poll_fds[0].events |= POLLOUT;
1169 if ((ret = poll(poll_fds, poll_skn, -1))) {
1175 for (i = 0; i < poll_skn; i++) {
1176 FD_SET(poll_sks[i], ibitsp);
1177 FD_SET(poll_sks[i], xbitsp);
1180 /* Only select output on the first socket. */
1181 FD_SET(poll_sks[0], obitsp);
1185 if ((ret = select(max_fd + 1, ibitsp, obitsp, xbitsp,
1186 (struct timeval *)0)) < 0) {
1196 temp_set = poll_fds[0].revents & POLLOUT;
1197 temp_fd = poll_fds[0].fd;
1199 temp_set = FD_ISSET(poll_sks[0], obitsp);
1200 temp_fd = poll_sks[0];
1204 inter_outbuf = gen_message(poll_snd_size);
1205 if (!inter_outbuf) {
1207 "Cannot allocate out message.\n");
1210 iov.iov_base = inter_outbuf;
1211 msglen = poll_snd_size;
1212 iov.iov_len = msglen;
1214 error = sendmsg(temp_fd, &outmsg, 0);
1216 "sent a message, msglen = %d\n",
1219 if (error != msglen) {
1220 fprintf(stderr, "%s: error: %s.\n",
1221 argv0, strerror(errno));
1222 if ((!nonblocking) ||
1223 (EAGAIN != errno)) {
1230 inter_outbuf = NULL;
1233 } /* while(!done) */
1235 for (i = 0; !done && (i < poll_skn); i++) {
1237 temp_set = poll_fds[i].revents & POLLIN;
1238 temp_fd = poll_fds[i].fd;
1240 temp_set = FD_ISSET(poll_sks[i], ibitsp);
1241 temp_fd = poll_sks[i];
1244 error = recvmsg(temp_fd, &inmessage,
1247 if ((EAGAIN == errno)) {
1259 test_print_message(temp_fd, &inmessage, error);
1260 inmessage.msg_control = incmsg;
1261 inmessage.msg_controllen = sizeof(incmsg);
1262 iov.iov_len = REALLY_BIG;
1265 /* Update the associd when a notification is received
1266 * on a UDP-style socket.
1268 if (inmessage.msg_flags & MSG_NOTIFICATION)
1269 associd = test_verify_assoc_change(&inmessage);
1271 /* Verify there is no association. */
1272 if (0 != test_sk_for_assoc(poll_sks[i], associd)) {
1273 printf("No association is present in sk "
1288 } /* command_poll() */
1290 /********************************************************************
1291 * 3rd Level Abstractions
1292 ********************************************************************/
1294 #define FPS(arg) fprintf(stderr, arg)
1300 * The bindx options, --bindx-add and --bindx-rem, are added to
1302 * 1. provide first testcases for the new bindx system call
1304 * 2. continue to grow sctp_darn with more functions and
1305 * features so it will be equivalent to the "sock" tool for
1310 * It is not very effective to use these two options in the
1311 * current command line mode of sctp_darn. For example, the
1312 * --bindx-rem option can only be used in conjunction with the
1313 * --bindx-add simply to test the function in the kernel
1314 * path. Ideally, bindx needs to be tested by a tool which
1315 * provides an interactive mode for users to change parameters
1316 * and configuration dynamically with existing endpoints and
1319 fprintf(stderr, "Usage: %s -H <localhost> -P <localport> "
1320 "[-h <remotehost>] [-p <remoteport>] -l|s\n"
1321 " -H, --local\t\tspecify one of the local addresses,\n"
1322 " -P, --local-port\tspecify the port number for local addresses,\n"
1323 " -h, --remote\t\tspecify the peer address,\n"
1324 " -p, --remote-port\tspecify the port number for the peer address,\n"
1325 " -l, --listen\t\tprint messages received from the peer,\n"
1326 " -s, --send\t\tsend messages to the peer,\n"
1328 "\tadd the specified address(es) as additional bind\n"
1329 "\t\t\taddresses to the local socket. Multiple addresses can\n"
1330 "\t\t\tbe specified by using this argument multiple times.\n"
1331 "\t\t\tFor example, '-B 10.0.0.1 -B 20.0.0.2'.\n"
1333 "\tremove the specified address(es) from the bind\n"
1334 "\t\t\taddresses of the local socket. Multiple addresses can\n"
1335 "\t\t\tbe specified by using this argument multiple times.\n"
1336 "\t\t\tFor example, '-b 10.0.0.1 -b 20.0.0.2'.\n"
1338 "\t\tuse the specified address(es) for connection to the\n"
1339 "\t\t\tpeer socket. Multiple addresses can be specified by\n"
1340 "\t\t\tusing this argument multiple times.\n"
1341 "\t\t\tFor example, '-c 10.0.0.1 -c 20.0.0.2'.\n"
1342 "\t\t\tThis option is incompatible with the -h option.\n"
1343 " -I\t\t\tuse the interactive mode.\n"
1344 " -i\t\t\tsetup the specified number of endpoints by using the\n"
1345 "\t\t\tspecified local host (-H) and local port (-P). The port\n"
1346 "\t\t\tnumber will be incremented by one for each additional\n"
1347 "\t\t\tendpoint. All of these endpoints will be listening.\n"
1348 "\t\t\tIf a remote host (-h) and a remote port are also\n"
1349 "\t\t\tspecified, the first endpoint will start sending fixed\n"
1350 "\t\t\tsized messages to the remote host.\n"
1351 " -m\t\t\tspecify the sockopt sndbuf/rcvbuf size.\n"
1352 " -n\t\t\tset the socket(s) to be in the non-blocking mode.\n"
1353 "\t\t\tcollect messages from stdin and deliver them to the\n"
1355 "--use-poll\t\tuse system call poll() for polling among the\n"
1356 "\t\t\tnumber of endpoints specified by the -i option. Without\n"
1357 "\t\t\tthis option, select() would be used as default.\n"
1358 " -t\t\t\tuse SOCK_STREAM tcp-style sockets.\n"
1359 " -z\t\t\tspecify the message size to be sent. The default\n"
1360 "\t\t\tmessage size generated would be 16K.\n"
1361 " --interface=\"ifname\"\tselect interface for sin6_scope_id.\n",
1366 /* This function checks messages to see if they are of type 'event'
1367 * and if they are well-formed.
1370 user_test_check_message(struct msghdr *msg,
1376 if (msg->msg_controllen != controllen) {
1378 "Got control structure of length %d, not %d\n",
1379 msg->msg_controllen, controllen);
1382 if (controllen > 0 && event != CMSG_FIRSTHDR(msg)->cmsg_type) {
1383 fprintf(stderr, "Wrong kind of event: %d, not %d\n",
1384 CMSG_FIRSTHDR(msg)->cmsg_type, event);
1390 } /* user_test_check_message() */
1392 /* Add another address represented as the string 'parm' to the list
1393 * addrs. The argument count is the number of addrs on input and is
1394 * adjusted for output.
1397 append_addr(const char *parm, struct sockaddr *addrs, int *ret_count)
1399 struct sockaddr *new_addrs = NULL;
1401 struct sockaddr *sa_addr;
1402 struct sockaddr_in *b4ap;
1403 struct sockaddr_in6 *b6ap;
1404 struct hostent *hst4 = NULL;
1405 struct hostent *hst6 = NULL;
1409 int orig_count = *ret_count;
1410 int count = orig_count;
1413 /* Get the entries for this host. */
1414 hst4 = gethostbyname(parm);
1415 hst6 = gethostbyname2(parm, AF_INET6);
1417 if ((NULL == hst4 || hst4->h_length < 1)
1418 && (NULL == hst6 || hst6->h_length < 1)) {
1419 fprintf(stderr, "bad hostname: %s\n", parm);
1424 /* Figure out the number of addresses. */
1426 for (i4 = 0; NULL != hst4->h_addr_list[i4]; ++i4) {
1431 for (i6 = 0; NULL != hst6->h_addr_list[i6]; ++i6) {
1436 /* Expand memory for the new addresses. Assume all the addresses
1439 new_addrs = (struct sockaddr *)
1440 realloc(addrs, sizeof(struct sockaddr_in6) * count);
1442 if (NULL == new_addrs) {
1447 /* Skip the existing addresses. */
1449 for (j = 0; j < orig_count; j++) {
1450 sa_addr = (struct sockaddr *)aptr;
1451 switch(sa_addr->sa_family) {
1453 aptr += sizeof(struct sockaddr_in);
1456 aptr += sizeof(struct sockaddr_in6);
1464 /* Put the new addresses away. */
1466 for (j = 0; j < i4; ++j) {
1467 b4ap = (struct sockaddr_in *)aptr;
1468 bzero(b4ap, sizeof(*b4ap));
1469 b4ap->sin_family = AF_INET;
1470 b4ap->sin_port = htons(local_port);
1471 bcopy(hst4->h_addr_list[j], &b4ap->sin_addr,
1474 aptr += sizeof(struct sockaddr_in);
1475 } /* for (loop through the new v4 addresses) */
1479 for (j = 0; j < i6; ++j) {
1480 b6ap = (struct sockaddr_in6 *)aptr;
1481 bzero(b6ap, sizeof(*b6ap));
1482 b6ap->sin6_family = AF_INET6;
1483 b6ap->sin6_port = htons(local_port);
1484 b6ap->sin6_scope_id = if_index;
1485 bcopy(hst6->h_addr_list[j], &b6ap->sin6_addr,
1488 aptr += sizeof(struct sockaddr_in6);
1489 } /* for (loop through the new v6 addresses) */
1498 } /* append_addr() */
1501 parse_inter_commands(char *argv0, char *input, int snd_only)
1508 struct sockaddr *tmp_addrs = NULL;
1512 if (*p == '?' || *p == '\n') {
1513 printf("Interactive commands:\n");
1514 printf("snd=<int> - Do a sendmsg with the specified");
1515 printf(" length.\n");
1516 printf("rcv=<int> - Do a recvmsg.");
1517 printf("The length is ignored for now.\n");
1518 printf("bindx-add=<addr> - Add a local address");
1519 printf(" with bindx. \n");
1520 printf("bindx-rem=<addr> - Remove a local address");
1521 printf(" with bindx. \n");
1522 printf("rcvbuf=<int> - Get/Set receive buffer size\n");
1523 printf("sndbuf=<int> - Get/Set send buffer size.\n");
1524 printf("primary=<addr> - Get/Set association's primary\n");
1525 printf("peer_primary=addr- Set association's peer_primary\n");
1526 printf("maxseg=<int> - Get/Set Maximum fragment size.\n");
1527 printf("nodelay=<0|1> - Get/Set NODELAY option.\n");
1528 printf("shutdown - Shutdown the association.\n");
1529 printf("abort - Abort the association.\n");
1530 printf("? - Help. Display this message.\n");
1534 for (i = 0; i < REALLY_BIG; i++) {
1546 if (i >= REALLY_BIG) {
1547 printf("Invalid input.\n");
1552 while (NULL != inter_commands[i].cmd) {
1553 if (!strcmp(input, inter_commands[i].cmd)) {
1557 if (*p < '0' || *p > '9') {
1572 if (*p < '0' || *p > '9') {
1576 len = (set) ? atoi(p) : 0;
1577 sndbuf_func(argv0, inter_sk, len, set);
1581 if (*p < '0' || *p > '9') {
1585 len = (set) ? atoi(p) : 0;
1586 rcvbuf_func(argv0, inter_sk, len, set);
1588 case INTER_BINDX_ADD:
1589 tmp_addrs = get_bindx_addr(p, &len);
1590 bindx_func(argv0, inter_sk, tmp_addrs, len,
1591 SCTP_BINDX_ADD_ADDR, local_port);
1594 case INTER_BINDX_REM:
1595 tmp_addrs = get_bindx_addr(p, &len);
1596 bindx_func(argv0, inter_sk, tmp_addrs, len,
1597 SCTP_BINDX_REM_ADDR, local_port);
1600 case INTER_SET_PRIM:
1601 primary_func(argv0, inter_sk, p, set);
1603 case INTER_SET_PEER_PRIM:
1604 peer_primary_func(argv0, inter_sk, p, set);
1606 case INTER_SHUTDOWN:
1607 shutdown_func(argv0, &inter_sk, SHUTDOWN_SHUTDOWN);
1610 shutdown_func(argv0, &inter_sk, SHUTDOWN_ABORT);
1614 if (*p < '0' || *p > '9') {
1618 val = (set) ? atoi(p) : 0;
1619 nodelay_func(argv0, inter_sk, val, set);
1623 if (*p < '0' || *p > '9') {
1627 val = (set) ? atoi(p) : 0;
1628 maxseg_func(argv0, inter_sk, val, set);
1641 printf("Invalid input.\n");
1644 } /* parse_inter_commands() */
1647 gen_message(int len)
1657 for (i = 0, p = buf; i < len; i++, p++) {
1658 if (gen_data > GEN_DATA_LAST) {
1659 gen_data = GEN_DATA_FIRST;
1667 } /* gen_message() */
1670 snd_func(char *input)
1676 if (!(inter_outbuf = gen_message(len))) {
1677 fprintf(stderr, "Cannot allocate out message.\n");
1685 sndbuf_func(char *argv0, int sk, int len, int set)
1691 error = setsockopt(sk, SOL_SOCKET, SO_SNDBUF,
1692 (char *)&len, sizeof(len));
1694 optlen = sizeof(len);
1695 error = getsockopt(sk, SOL_SOCKET, SO_SNDBUF,
1696 (char *)&len, &optlen);
1699 fprintf(stderr, "%s: Error setting/getting sndbuf: %s.\n",
1700 argv0, strerror(errno));
1705 printf("sndbuf is %d.\n", len);
1708 } /* sndbuf_func() */
1711 rcvbuf_func(char *argv0, int sk, int len, int set)
1717 error = setsockopt(sk, SOL_SOCKET, SO_RCVBUF,
1718 (char *)&len, sizeof(len));
1720 optlen = sizeof(len);
1721 error = getsockopt(sk, SOL_SOCKET, SO_RCVBUF,
1722 (char *)&len, &optlen);
1725 fprintf(stderr, "%s: Error setting/getting rcvbuf: %s.\n",
1726 argv0, strerror(errno));
1731 printf("rcvbuf is %d.\n", len);
1734 } /* rcvbuf_func() */
1737 static struct sockaddr *
1738 get_bindx_addr(char *in, int *count)
1741 struct sockaddr *tmp_addrs = NULL;
1744 /* Set the buffer for address parsing. */
1745 while ('\n' != *p) {
1752 tmp_addrs = append_addr(in, tmp_addrs, count);
1753 if (NULL == tmp_addrs) {
1754 /* We have no memory, so keep fprintf()
1755 * from trying to allocate more.
1757 fprintf(stderr, "No memory to add ");
1758 fprintf(stderr, in);
1759 fprintf(stderr, "\n");
1764 } /* get_bindx_addr() */
1767 bindx_func(char *argv0, int sk, struct sockaddr *addrs, int count, int flag, int portnum)
1772 struct sockaddr *sa_addr;
1777 fprintf(stderr, "%s: A non-0 local port number is ", argv0);
1778 fprintf(stderr, "required for bindx to work!\n");
1782 /* Set the port in every address. */
1784 for (i = 0; i < count; i++) {
1785 sa_addr = (struct sockaddr *)aptr;
1787 switch(sa_addr->sa_family) {
1789 ((struct sockaddr_in *)sa_addr)->sin_port =
1791 aptr += sizeof(struct sockaddr_in);
1794 ((struct sockaddr_in6 *)sa_addr)->sin6_port =
1796 aptr += sizeof(struct sockaddr_in6);
1799 fprintf(stderr, "Invalid address family\n");
1804 error = sctp_bindx(sk, addrs, count, flag);
1807 if (flag == SCTP_BINDX_ADD_ADDR) {
1808 fprintf(stderr, "%s: error adding addrs: %s.\n",
1809 argv0, strerror(errno));
1812 fprintf(stderr, "%s: error removing addrs: %s.\n",
1813 argv0, strerror(errno));
1820 } /* bindx_func() */
1823 connectx_func(char *argv0, int sk, struct sockaddr *addrs, int count)
1828 struct sockaddr *sa_addr;
1832 if (0 == remote_port) {
1833 fprintf(stderr, "%s: A non-0 remote port number is ", argv0);
1834 fprintf(stderr, "required for connectx to work!\n");
1838 /* Set the port in every address. */
1840 for (i = 0; i < count; i++) {
1841 sa_addr = (struct sockaddr *)aptr;
1843 switch(sa_addr->sa_family) {
1845 ((struct sockaddr_in *)sa_addr)->sin_port =
1847 aptr += sizeof(struct sockaddr_in);
1850 ((struct sockaddr_in6 *)sa_addr)->sin6_port =
1852 aptr += sizeof(struct sockaddr_in6);
1855 fprintf(stderr, "Invalid address family\n");
1860 error = sctp_connectx(sk, addrs, count, NULL);
1863 if (errno == ECONNREFUSED)
1865 fprintf(stderr, "%s: error connecting to addrs: %s.\n",
1866 argv0, strerror(errno));
1872 } /* connectx_func() */
1875 primary_func(char *argv0, int sk, char *cp, int set)
1877 struct sctp_prim prim;
1878 struct sockaddr_in *in_addr;
1879 struct sockaddr_in6 *in6_addr;
1880 struct sockaddr *saddr;
1884 char addr_buf[INET6_ADDRSTRLEN];
1885 const char *ap = NULL;
1887 prim_len = sizeof(struct sctp_prim);
1889 prim.ssp_assoc_id = associd;
1890 ret = getsockopt(sk, IPPROTO_SCTP, SCTP_PRIMARY_ADDR,
1895 saddr = (struct sockaddr *)&prim.ssp_addr;
1896 if (AF_INET == saddr->sa_family) {
1897 in_addr = (struct sockaddr_in *)&prim.ssp_addr;
1898 ap = inet_ntop(AF_INET, &in_addr->sin_addr, addr_buf,
1900 } else if (AF_INET6 == saddr->sa_family) {
1901 in6_addr = (struct sockaddr_in6 *)&prim.ssp_addr;
1902 ap = inet_ntop(AF_INET6, &in6_addr->sin6_addr, addr_buf,
1911 /* Set the buffer for address parsing. */
1916 prim.ssp_assoc_id = associd;
1917 if (strchr(cp, '.')) {
1918 in_addr = (struct sockaddr_in *)&prim.ssp_addr;
1919 in_addr->sin_port = htons(remote_port);
1920 in_addr->sin_family = AF_INET;
1921 ret = inet_pton (AF_INET, cp, &in_addr->sin_addr);
1924 } else if (strchr(cp, ':')) {
1925 in6_addr = (struct sockaddr_in6 *)&prim.ssp_addr;
1926 in6_addr->sin6_port = htons(remote_port);
1927 in6_addr->sin6_family = AF_INET6;
1928 ret = inet_pton(AF_INET6, cp, &in6_addr->sin6_addr);
1934 ret = setsockopt(sk, IPPROTO_SCTP, SCTP_PRIMARY_ADDR,
1935 &prim, sizeof(struct sctp_prim));
1943 fprintf(stderr, "%s: error %s primary: %s.\n", argv0,
1944 (set)?"setting":"getting", strerror(errno));
1948 peer_primary_func(char *argv0, int sk, char *cp, int set)
1950 struct sctp_setpeerprim setpeerprim;
1951 struct sockaddr_in *in_addr;
1952 struct sockaddr_in6 *in6_addr;
1953 int peer_prim_len, ret;
1960 peer_prim_len = sizeof(struct sctp_setpeerprim);
1961 /* Set the buffer for address parsing. */
1966 setpeerprim.sspp_assoc_id = associd;
1967 if (strchr(cp, '.')) {
1968 in_addr = (struct sockaddr_in *)&setpeerprim.sspp_addr;
1969 in_addr->sin_port = htons(local_port);
1970 in_addr->sin_family = AF_INET;
1971 ret = inet_pton (AF_INET, cp, &in_addr->sin_addr);
1974 } else if (strchr(cp, ':')) {
1975 in6_addr = (struct sockaddr_in6 *)&setpeerprim.sspp_addr;
1976 in6_addr->sin6_port = htons(local_port);
1977 in6_addr->sin6_family = AF_INET6;
1978 ret = inet_pton(AF_INET6, cp, &in6_addr->sin6_addr);
1984 ret = setsockopt(sk, IPPROTO_SCTP, SCTP_SET_PEER_PRIMARY_ADDR,
1985 &setpeerprim, sizeof(struct sctp_setpeerprim));
1993 fprintf(stderr, "%s: error %s peer_primary: %s.\n", argv0,
1994 (set)?"setting":"getting", strerror(errno));
1998 nodelay_func(char *argv0, int sk, int val, int set)
2004 error = setsockopt(sk, SOL_SCTP, SCTP_NODELAY,
2005 (char *)&val, sizeof(val));
2007 optlen = sizeof(val);
2008 error = getsockopt(sk, SOL_SCTP, SCTP_NODELAY,
2009 (char *)&val, &optlen);
2012 fprintf(stderr, "%s: Error setting/getting nodelay: %s.\n",
2013 argv0, strerror(errno));
2018 printf("nodelay is %d.\n", val);
2025 maxseg_func(char *argv0, int sk, int val, int set)
2031 error = setsockopt(sk, SOL_SCTP, SCTP_MAXSEG,
2032 (char *)&val, sizeof(val));
2034 optlen = sizeof(val);
2035 error = getsockopt(sk, SOL_SCTP, SCTP_MAXSEG,
2036 (char *)&val, &optlen);
2039 fprintf(stderr, "%s: Error setting/getting maxseg: %s.\n",
2040 argv0, strerror(errno));
2045 printf("maxseg is %d.\n", val);
2052 shutdown_func(char *argv0, int *skp, int shutdown_type)
2054 struct msghdr outmessage;
2055 char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
2056 struct cmsghdr *cmsg;
2057 int error=0, bytes_sent;
2058 struct sctp_sndrcvinfo *sinfo;
2059 struct hostent *hst;
2063 if (shutdown_type == SHUTDOWN_ABORT)
2066 sd_type = "SHUTDOWN";
2068 /* Verify that the association is present. */
2069 error = test_sk_for_assoc(sk, associd);
2071 printf("The association isn't present yet! Cannot %s!\n", sd_type);
2075 if (socket_type == SOCK_SEQPACKET) {
2076 /* Set up the destination. */
2078 hst = gethostbyname(remote_host);
2080 hst = gethostbyname2(remote_host, AF_INET6);
2083 if (hst == NULL || hst->h_length < 1) {
2084 fprintf(stderr, "%s: bad hostname: %s\n",
2085 argv0, remote_host);
2089 ra_family = hst->h_addrtype;
2090 switch (ra_family) {
2092 ra_len = sizeof(remote_addr.v4);
2093 ra_raw = &remote_addr.v4.sin_addr;
2094 remote_addr.v4.sin_port = htons(remote_port);
2095 remote_addr.v4.sin_family = AF_INET;
2098 ra_len = sizeof(remote_addr.v6);
2099 ra_raw = &remote_addr.v6.sin6_addr;
2100 remote_addr.v6.sin6_port = htons(remote_port);
2101 remote_addr.v6.sin6_family = AF_INET6;
2104 fprintf(stderr, "Invalid address type.\n");
2108 memcpy(ra_raw, hst->h_addr_list[0], hst->h_length);
2111 /* Initialize the message struct we use to pass messages to
2112 * the remote socket.
2114 outmessage.msg_name = &remote_addr;
2115 outmessage.msg_namelen = ra_len;
2117 outmessage.msg_iov = NULL;
2118 outmessage.msg_iovlen = 0;
2119 outmessage.msg_control = outcmsg;
2120 outmessage.msg_controllen = sizeof(outcmsg);
2121 outmessage.msg_flags = 0;
2123 cmsg = CMSG_FIRSTHDR(&outmessage);
2124 cmsg->cmsg_level = IPPROTO_SCTP;
2125 cmsg->cmsg_type = SCTP_SNDRCV;
2126 cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
2127 outmessage.msg_controllen = cmsg->cmsg_len;
2128 sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
2129 memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
2130 if (shutdown_type == SHUTDOWN_ABORT)
2131 sinfo->sinfo_flags |= SCTP_ABORT;
2133 sinfo->sinfo_flags |= SCTP_EOF;
2135 sinfo->sinfo_assoc_id = associd;
2137 bytes_sent = sendmsg(sk, &outmessage, 0);
2138 if (bytes_sent != 0) {
2139 printf("Failure: %s.\n", strerror(errno));
2143 /* Receive the COMM_LOST or SHUTDOWN_COMP event. */
2144 test_recv_assoc_change(sk);
2146 if (shutdown_type == SHUTDOWN_ABORT) {
2151 error = setsockopt(sk, SOL_SOCKET, SO_LINGER,
2152 (char *)&data, sizeof(data));
2154 printf("setsockopt failed %s\n", strerror(errno));
2160 printf("close failed %s\n", strerror(errno));
2163 *skp = sk = build_endpoint(argv0, local_port);
2166 /* Verify that the association is no longer present. */
2167 error = test_sk_for_assoc(sk, associd);
2169 printf("Successfully %s the original association\n", sd_type);
2173 printf("%s failed\n", sd_type);
2181 test_sk_for_assoc(int sk, sctp_assoc_t assoc_id)
2184 struct sctp_status status;
2185 socklen_t status_len;
2187 memset(&status, 0, sizeof(status));
2189 status.sstat_assoc_id = assoc_id;
2190 status_len = sizeof(struct sctp_status);
2191 error = getsockopt(sk, SOL_SCTP, SCTP_STATUS,
2192 (char *)&status, &status_len);
2196 /* Receive a notification and return the corresponding associd if the event is
2197 * SCTP_COMM_UP. Return 0 for any other event.
2200 test_recv_assoc_change(int sk)
2202 struct msghdr inmessage;
2204 char incmsg[CMSG_SPACE(sizeof(_sctp_cmsg_data_t))];
2207 /* Initialize inmessage with enough space for DATA... */
2208 memset(&inmessage, 0, sizeof(inmessage));
2209 if ((iov.iov_base = malloc(REALLY_BIG)) == NULL) {
2210 printf("%s: Can't allocate memory.\n", __FUNCTION__);
2213 iov.iov_len = REALLY_BIG;
2214 inmessage.msg_iov = &iov;
2215 inmessage.msg_iovlen = 1;
2216 /* or a control message. */
2217 inmessage.msg_control = incmsg;
2218 inmessage.msg_controllen = sizeof(incmsg);
2220 error = recvmsg(sk, &inmessage, MSG_WAITALL);
2222 printf("%s: recvmsg: %s\n", __FUNCTION__, strerror(errno));
2226 return test_verify_assoc_change(&inmessage);
2229 /* Verify a notification and return the corresponding associd if the event is
2230 * SCTP_COMM_UP. Return 0 for any other event.
2233 test_verify_assoc_change(struct msghdr *msg)
2235 union sctp_notification *sn;
2237 if (!(msg->msg_flags & MSG_NOTIFICATION)) {
2238 fprintf(stderr, "%s: Received data when notification is expected\n",
2243 sn = (union sctp_notification *)msg->msg_iov->iov_base;
2244 if (SCTP_ASSOC_CHANGE != sn->sn_header.sn_type) {
2245 fprintf(stderr, "%s: Received unexpected notification: %d",
2246 __FUNCTION__, sn->sn_header.sn_type);
2250 switch(sn->sn_assoc_change.sac_state)
2253 printf("Recieved SCTP_COMM_UP\n");
2255 case SCTP_COMM_LOST:
2256 printf("Recieved SCTP_COMM_LOST\n");
2259 printf("Recieved SCTP_RESTART\n");
2261 case SCTP_SHUTDOWN_COMP:
2262 printf("Recieved SCTP_SHUTDOWN_COMP\n");
2264 case SCTP_CANT_STR_ASSOC:
2265 printf("Recieved SCTP_CANT_STR_ASSOC\n");
2269 if (SCTP_COMM_UP == sn->sn_assoc_change.sac_state)
2270 return sn->sn_assoc_change.sac_assoc_id;
2275 void print_addr_buf(void * laddrs, int n_laddrs)
2277 void *addr_buf = laddrs;
2280 for (i = 0; i < n_laddrs; i++) {
2281 addr_buf += print_sockaddr((struct sockaddr *)addr_buf);
2286 int print_sockaddr(struct sockaddr *sa_addr)
2288 struct sockaddr_in *in_addr;
2289 struct sockaddr_in6 *in6_addr;
2291 if (AF_INET == sa_addr->sa_family) {
2292 in_addr = (struct sockaddr_in *)sa_addr;
2293 printf("%d.%d.%d.%d:%d",
2294 NIPQUAD(in_addr->sin_addr),
2295 ntohs(in_addr->sin_port));
2296 return sizeof(struct sockaddr_in);
2298 in6_addr = (struct sockaddr_in6 *)sa_addr;
2299 printf("%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%d",
2300 NIP6(in6_addr->sin6_addr),
2301 ntohs(in6_addr->sin6_port));
2302 return sizeof(struct sockaddr_in6);