1 /* SCTP kernel reference Implementation
2 * (C) Copyright Fujitsu Ltd. 2008, 2009
4 * The SCTP reference implementation is free software;
5 * you can redistribute it and/or modify it under the terms of
6 * the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * The SCTP reference implementation is distributed in the hope that it
11 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
12 * ************************
13 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 * See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with GNU CC; see the file COPYING. If not, write to
18 * the Free Software Foundation, 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
21 * Please send any bug reports or fixes you make to the
23 * lksctp developers <lksctp-developers@lists.sourceforge.net>
25 * Or submit a bug report through the following website:
26 * http://www.sf.net/projects/lksctp
28 * Any bugs reported to us we will try to fix... any fixes shared will
29 * be incorporated into the next SCTP release.
31 * Written or modified by:
32 * Wei Yongjun <yjwei@cn.fujitsu.com>
37 #include <sys/types.h>
38 #include <sys/socket.h>
39 #include <arpa/inet.h>
41 #include <netinet/sctp.h>
50 #define DEFAULT_USEC 5000
52 #define REALLY_BIG 65536
56 #define NOT_DEFINED 666
62 #define ORDER_PATTERN_UNORDERED 0
63 #define ORDER_PATTERN_ORDERED 1
64 #define ORDER_PATTERN_ALTERNATE 2
65 #define ORDER_PATTERN_RANDOM 3
67 #define STREAM_PATTERN_SEQUENTIAL 0
68 #define STREAM_PATTERN_RANDOM 1
70 #define MAX_BIND_RETRYS 10
71 #define BIG_REPEAT 1000000
74 #define DEFAULT_MAX_WINDOW 32768
75 #define DEFAULT_MIN_WINDOW 1500
79 #define DEBUG_PRINT(level, print_this...) \
81 if (debug_level >= level) { \
82 fprintf(stdout, print_this); \
87 char *local_host = NULL;
89 char *remote_host = NULL;
91 struct sockaddr_storage s_rem, s_loc;
94 int debug_level = DEBUG_NONE;
95 int order_pattern = ORDER_PATTERN_UNORDERED;
97 int stream_pattern = STREAM_PATTERN_SEQUENTIAL;
100 int repeat_count = 0;
101 int max_msgsize = DEFAULT_MAX_WINDOW;
102 int msg_cnt = MSG_CNT;
107 char *statusfile = NULL;
109 void printstatus(int sk);
110 void sighandler(int signo);
111 void settimerhandle(void);
112 void usage(char *argv0);
113 void start_test(int role);
115 unsigned char msg[] = "012345678901234567890123456789012345678901234567890";
117 /* Convenience structure to determine space needed for cmsg. */
119 struct sctp_initmsg init;
120 struct sctp_sndrcvinfo sndrcvinfo;
123 int main(int argc, char *argv[]) {
124 int c, role = NOT_DEFINED;
125 char *interface = NULL;
126 struct sockaddr_in *t_addr;
127 struct sockaddr_in6 *t_addr6;
129 /* Parse the arguments. */
130 while ((c = getopt(argc, argv, ":H:L:P:h:p:c:d:lm:sx:X:o:M:r:Di:I:f:")) >= 0 ) {
136 local_port = atoi(optarg);
139 remote_host = optarg;
142 remote_port = atoi(optarg);
145 if (role != NOT_DEFINED) {
146 printf("%s: only -s or -l\n", argv[0]);
153 if (role != NOT_DEFINED) {
154 printf("%s: only -s or -l\n", argv[0]);
164 debug_level = atoi(optarg);
165 if (debug_level < DEBUG_NONE
166 || debug_level > DEBUG_MAX) {
172 period = atoi(optarg);
179 repeat = atoi(optarg);
185 msg_cnt = atoi(optarg);
186 if ((msg_cnt <= 0) || (msg_cnt > MSG_CNT)) {
192 size_arg = atoi(optarg);
200 order_pattern = atoi(optarg);
201 if (order_pattern < ORDER_PATTERN_UNORDERED
202 || order_pattern > ORDER_PATTERN_RANDOM ) {
208 max_stream = atoi(optarg);
210 || max_stream >= (1<<16)) {
216 max_msgsize = atoi(optarg);
231 if (NOT_DEFINED == role) {
236 if (SERVER == role && NULL == local_host && remote_host != NULL) {
237 fprintf(stderr, "%s: Server needs local address, "
238 "not remote address\n", argv[0]);
242 if (CLIENT == role && NULL == remote_host) {
243 fprintf(stderr, "%s: Client needs at least remote address "
244 "& port\n", argv[0]);
250 fprintf(stderr, "%s: non-option arguments are illegal: ", argv[0]);
251 while (optind < argc)
252 fprintf(stderr, "%s ", argv[optind++]);
253 fprintf (stderr, "\n");
258 if (remote_host != NULL && remote_port != 0) {
259 struct addrinfo *res;
261 char *host_s, *serv_s;
263 if ((host_s = malloc(NI_MAXHOST)) == NULL) {
264 fprintf(stderr, "\n*** host_s malloc failed!!! ***\n");
267 if ((serv_s = malloc(NI_MAXSERV)) == NULL) {
268 fprintf(stderr, "\n*** serv_s malloc failed!!! ***\n");
272 error = getaddrinfo(remote_host, 0, NULL, &res);
274 printf("%s.\n", gai_strerror(error));
279 switch (res->ai_family) {
281 t_addr = (struct sockaddr_in *)&s_rem;
283 t_addr->sin_family = AF_INET;
284 t_addr->sin_port = htons(remote_port);
285 inet_pton(AF_INET, remote_host, &t_addr->sin_addr);
287 r_len = sizeof (struct sockaddr_in);
289 t_addr->sin_len = r_len;
293 t_addr6 = (struct sockaddr_in6 *)&s_rem;
296 t_addr6->sin6_scope_id = if_nametoindex(interface);
297 t_addr6->sin6_family = AF_INET6;
298 t_addr6->sin6_port = htons(remote_port);
299 inet_pton(AF_INET6, remote_host, &t_addr6->sin6_addr);
301 r_len = sizeof (struct sockaddr_in6);
304 t_addr6->sin6_len = r_len;
309 getnameinfo((struct sockaddr *)&s_rem, r_len, host_s,
310 NI_MAXHOST, serv_s, NI_MAXSERV, NI_NUMERICHOST);
312 DEBUG_PRINT(DEBUG_MAX, "remote:addr=%s, port=%s, family=%d\n",
313 host_s, serv_s, res->ai_family);
316 if (local_host != NULL) {
317 struct addrinfo *res;
319 char *host_s, *serv_s;
320 struct sockaddr_in *t_addr;
321 struct sockaddr_in6 *t_addr6;
323 if ((host_s = malloc(NI_MAXHOST)) == NULL) {
324 fprintf(stderr, "\n*** host_s malloc failed!!! ***\n");
327 if ((serv_s = malloc(NI_MAXSERV)) == NULL) {
328 fprintf(stderr, "\n*** serv_s malloc failed!!! ***\n");
332 if (strcmp(local_host, "0") == 0)
333 local_host = "0.0.0.0";
335 error = getaddrinfo(local_host, 0, NULL, &res);
337 printf("%s.\n", gai_strerror(error));
342 switch (res->ai_family) {
344 t_addr = (struct sockaddr_in *)&s_loc;
345 t_addr->sin_family = AF_INET;
346 t_addr->sin_port = htons(local_port);
347 inet_pton(AF_INET, local_host, &t_addr->sin_addr);
349 l_len = sizeof (struct sockaddr_in);
351 t_addr->sin_len = l_len;
355 t_addr6 = (struct sockaddr_in6 *)&s_loc;
358 t_addr6->sin6_scope_id = if_nametoindex(interface);
359 t_addr6->sin6_family = AF_INET6;
360 t_addr6->sin6_port = htons(local_port);
362 inet_pton(AF_INET6, local_host, &t_addr6->sin6_addr);
364 l_len = sizeof (struct sockaddr_in6);
367 t_addr6->sin6_len = l_len;
372 error = getnameinfo((struct sockaddr *)&s_loc, l_len, host_s,
373 NI_MAXHOST, serv_s, NI_MAXSERV, NI_NUMERICHOST);
376 printf("%s..\n", gai_strerror(error));
378 DEBUG_PRINT(DEBUG_MAX, "local:addr=%s, port=%s, family=%d\n",
379 host_s, serv_s, res->ai_family);
382 /* Let the testing begin. */
388 int bind_r(int sk, struct sockaddr_storage *saddr) {
389 int error = 0, i = 0;
390 char *host_s, *serv_s;
392 if ((host_s = malloc(NI_MAXHOST)) == NULL) {
393 fprintf(stderr, "\n\t\t*** host_s malloc failed!!! ***\n");
396 if ((serv_s = malloc(NI_MAXSERV)) == NULL) {
397 fprintf(stderr, "\n\t\t*** serv_s malloc failed!!! ***\n");
402 if (i > 0) sleep(1); /* sleep a while before new try... */
404 error = getnameinfo((struct sockaddr *)saddr, l_len, host_s,
405 NI_MAXHOST, serv_s, NI_MAXSERV,
409 printf("%s\n", gai_strerror(error));
411 DEBUG_PRINT(DEBUG_MIN,
412 "\tbind(sk=%d, [a:%s,p:%s]) -- attempt %d/%d\n",
413 sk, host_s, serv_s, i+1, MAX_BIND_RETRYS);
415 error = bind(sk, (struct sockaddr *)saddr, l_len);
418 if( errno != EADDRINUSE ) {
419 fprintf(stderr, "\n\n\t\t***bind: can "
420 "not bind to %s:%s: %s ****\n",
421 host_s, serv_s, strerror(errno));
426 if (i >= MAX_BIND_RETRYS) {
427 fprintf(stderr, "Maximum bind() attempts. "
431 } while (error < 0 && i < MAX_BIND_RETRYS);
436 int listen_r(int sk, int listen_count) {
439 DEBUG_PRINT(DEBUG_MIN, "\tlisten(sk=%d,backlog=%d)\n",
442 /* Mark sk as being able to accept new associations */
443 error = listen(sk, 1);
445 fprintf(stderr, "\n\n\t\t*** listen: %s ***\n\n\n", strerror(errno));
452 int accept_r(int sk){
455 DEBUG_PRINT(DEBUG_MIN, "\taccept(sk=%d)\n", sk);
457 gsk = accept(sk, NULL, &len);
459 fprintf(stderr, "\n\n\t\t*** accept: %s ***\n\n\n", strerror(errno));
466 int connect_r(int sk, const struct sockaddr *serv_addr, socklen_t addrlen) {
469 DEBUG_PRINT(DEBUG_MIN, "\tconnect(sk=%d)\n", sk);
471 /* Mark sk as being able to accept new associations */
472 error = connect(sk, serv_addr, addrlen);
474 fprintf(stderr, "\n\n\t\t*** connect: %s ***\n\n\n",
484 int close_r(int sk) {
487 DEBUG_PRINT(DEBUG_MIN, "\tclose(sk=%d)\n",sk);
491 fprintf(stderr, "\n\n\t\t*** close: %s ***\n\n",
499 int receive_r(int sk)
502 char incmsg[CMSG_SPACE(sizeof(_sctp_cmsg_data_t))];
504 struct msghdr inmessage;
506 /* Initialize inmessage with enough space for DATA... */
507 memset(&inmessage, 0, sizeof(inmessage));
508 if ((iov.iov_base = malloc(REALLY_BIG)) == NULL) {
509 fprintf(stderr, "\n\t\t*** malloc not enough memory!!! ***\n");
512 iov.iov_len = REALLY_BIG;
513 inmessage.msg_iov = &iov;
514 inmessage.msg_iovlen = 1;
515 /* or a control message. */
516 inmessage.msg_control = incmsg;
517 inmessage.msg_controllen = sizeof(incmsg);
519 /* Get the messages sent */
521 DEBUG_PRINT(DEBUG_MIN, "\trecvmsg(sk=%d) ", sk);
523 error = recvmsg(sk, &inmessage, MSG_WAITALL);
524 if (error < 0 && error != EAGAIN) {
525 fprintf(stderr, "\n\t\t*** recvmsg: %s ***\n\n",
531 } else if (error == 0) {
532 printf("\n\t\trecvmsg() returned 0 !!!!\n");
536 if(MSG_NOTIFICATION & inmessage.msg_flags)
537 continue; /* got a notification... */
539 inmessage.msg_control = incmsg;
540 inmessage.msg_controllen = sizeof(incmsg);
541 iov.iov_len = REALLY_BIG;
549 void server(int sk) {
550 if (max_msgsize > DEFAULT_MAX_WINDOW) {
551 if (setsockopt(sk, IPPROTO_SCTP, SO_RCVBUF, &max_msgsize,
552 sizeof(max_msgsize)) < 0) {
553 perror("setsockopt(SO_RCVBUF)");
561 void * build_msg(int len) {
566 msg_buf = malloc(len);
567 if (NULL == msg_buf) {
568 fprintf(stderr, "\n\t\t*** malloc not enough memory!!! ***\n");
575 memcpy(p, msg, ((i > 50)?50:i));
580 msg_buf[len-1] = '\0';
586 int send_r(int sk, int stream, int order, int send_size, int assoc_i) {
588 struct msghdr outmsg;
590 char *message = NULL;
592 char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
593 struct cmsghdr *cmsg;
594 struct sctp_sndrcvinfo *sinfo;
597 message = build_msg(send_size);
598 msglen = strlen(message) + 1;
599 iov.iov_base = message;
600 iov.iov_len = msglen;
605 outmsg.msg_name = &s_rem;
606 outmsg.msg_namelen = sizeof(struct sockaddr_storage);
607 outmsg.msg_iov = &iov;
608 outmsg.msg_iovlen = 1;
609 outmsg.msg_control = outcmsg;
610 outmsg.msg_controllen = sizeof(outcmsg);
611 outmsg.msg_flags = 0;
613 cmsg = CMSG_FIRSTHDR(&outmsg);
614 cmsg->cmsg_level = IPPROTO_SCTP;
615 cmsg->cmsg_type = SCTP_SNDRCV;
616 cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
618 outmsg.msg_controllen = cmsg->cmsg_len;
619 sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
620 memset(sinfo, 0, sizeof(struct sctp_sndrcvinfo));
621 sinfo->sinfo_ppid = rand();
622 sinfo->sinfo_stream = stream;
623 sinfo->sinfo_flags = 0;
625 sinfo->sinfo_flags = SCTP_UNORDERED;
627 DEBUG_PRINT(DEBUG_MIN, "\tsendmsg(sk=%d, assoc=%d) %4d bytes.\n",
628 sk, assoc_i, send_size);
629 DEBUG_PRINT(DEBUG_MAX, "\t SNDRCV");
630 if (DEBUG_MAX == debug_level) {
631 printf("(stream=%u ", sinfo->sinfo_stream);
632 printf("flags=0x%x ", sinfo->sinfo_flags);
633 printf("ppid=%u)\n", sinfo->sinfo_ppid);
636 /* Send to our neighbor. */
637 error = sendmsg(sk, &outmsg, MSG_WAITALL);
638 if (error != msglen) {
639 fprintf(stderr, "\n\t\t*** sendmsg: %s ***\n\n",
645 if (send_size > 0) free(message);
649 int next_order(int state, int pattern)
652 case ORDER_PATTERN_UNORDERED:
655 case ORDER_PATTERN_ORDERED:
658 case ORDER_PATTERN_ALTERNATE:
659 state = state ? 0 : 1;
661 case ORDER_PATTERN_RANDOM:
669 int next_stream(int state, int pattern)
672 case STREAM_PATTERN_RANDOM:
673 state = rand() % (max_stream + 1);
675 case STREAM_PATTERN_SEQUENTIAL:
677 if (state > max_stream)
685 int next_msg_size(int msg_cnt)
692 msg_size = (rand() % max_msgsize) + 1;
697 } /* next_msg_size() */
699 void client(int sk) {
703 for (i = 0; i < msg_cnt; i++) {
704 msg_size = next_msg_size(i);
705 order_state = next_order(order_state, order_pattern);
706 stream_state = next_stream(stream_state, stream_pattern);
708 if (send_r(sk, stream_state, order_state, msg_size, 0) < 0) {
713 /* The sender is echoing so do discard the echoed data. */
714 if (drain && ((i + 1) % period == 0)) {
720 void start_test(int role) {
724 DEBUG_PRINT(DEBUG_NONE, "\nStarting tests...\n");
726 repeat_count = repeat;
728 DEBUG_PRINT(DEBUG_MIN, "\tsocket(SOCK_STREAM, IPPROTO_SCTP)");
730 if ((sk = socket(s_loc.ss_family, SOCK_STREAM, IPPROTO_SCTP)) < 0 ) {
731 fprintf(stderr, "\n\n\t\t*** socket: failed to create"
732 " socket: %s ***\n", strerror(errno));
735 DEBUG_PRINT(DEBUG_MIN, " -> sk=%d\n", sk);
739 if (role == SERVER) {
743 connect_r(sk, (struct sockaddr *)&s_rem, r_len);
746 if ((pid = fork()) == 0) {
755 for(i = 0; i < repeat_count; i++) {
757 if (role == SERVER) {
758 DEBUG_PRINT(DEBUG_NONE, "Server: Receiving packets.(%d/%d)\n",
762 DEBUG_PRINT(DEBUG_NONE, "Client: Sending packets.(%d/%d)\n",
770 if (role == SERVER) close_r(gsk);
775 void settimerhandle(void) {
776 struct sigaction act;
777 struct itimerval interval;
779 act.sa_handler = sighandler;
781 sigemptyset(&act.sa_mask);
782 sigaction(SIGPROF, &act, NULL);
784 interval.it_value.tv_sec = DEFAULT_SEC;
785 interval.it_value.tv_usec = DEFAULT_USEC;
786 interval.it_interval = interval.it_value;
788 setitimer(ITIMER_PROF, &interval, NULL);
791 void usage(char *argv0) {
792 fprintf(stderr, "\nusage:\n");
793 fprintf(stderr, " server:\n");
794 fprintf(stderr, " %8s -H local-addr -P local-port -l [-d level] [-x]\n"
795 "\t [-L num-ports] [-S num-ports]\n"
796 "\t [-a assoc-pattern]\n"
797 "\t [-i interface]\n"
798 "\t [-f status-file]\n",
800 fprintf(stderr, "\n");
801 fprintf(stderr, " client:\n");
802 fprintf(stderr, " %8s -H local-addr -P local-port -h remote-addr\n"
803 "\t -p remote-port -s [-c case ] [-d level]\n"
804 "\t [-x repeat] [-o order-pattern] ream-pattern]\n"
805 "\t [-M max-stream]\n"
806 "\t [-m max-msgsize]\n"
807 "\t [-L num-ports] [-S num-ports]\n"
808 "\t [-i interface]\n"
809 "\t [-f status-file]\n",
811 fprintf(stderr, "\n");
812 fprintf(stderr, "\t-c value = Packets of specifed size.\n");
813 fprintf(stderr, "\t-m msgsize(1500-65515, default value 32768)\n");
814 fprintf(stderr, "\t-x number of repeats\n");
815 fprintf(stderr, "\t-o order-pattern\n");
816 fprintf(stderr, "\t 0 = all unordered(default) \n");
817 fprintf(stderr, "\t 1 = all ordered \n");
818 fprintf(stderr, "\t 2 = alternating \n");
819 fprintf(stderr, "\t 3 = random\n");
820 fprintf(stderr, "\t-M max-stream (default value 0)\n");
821 fprintf(stderr, "\t-D drain. If in client mode do a read following send.\n");
822 fprintf(stderr, "\n");
827 void sighandler(int signo) {
828 DEBUG_PRINT(DEBUG_MAX, "timeout sig\n");
832 char* get_sstat_state(int state) {
838 case SCTP_COOKIE_WAIT:
839 return "COOKIE_WAIT";
840 case SCTP_COOKIE_ECHOED:
841 return "COOKIE_ECHOED";
842 case SCTP_ESTABLISHED:
843 return "ESTABLISHED";
844 case SCTP_SHUTDOWN_PENDING:
845 return "SHUTDOWN_PENDING";
846 case SCTP_SHUTDOWN_SENT:
847 return "SHUTDOWN_SENT";
848 case SCTP_SHUTDOWN_RECEIVED:
849 return "SHUTDOWN_RECEIVED";
850 case SCTP_SHUTDOWN_ACK_SENT:
851 return "SHUTDOWN_ACK_SENT";
857 void printstatus(int sk) {
859 static int count = 0;
860 struct sctp_status status;
864 optlen = sizeof(struct sctp_status);
865 if(getsockopt(sk, IPPROTO_SCTP, SCTP_STATUS, &status, &optlen) < 0) {
866 fprintf(stderr, "Error getting status: %s.\n", strerror(errno));
870 if (statusfile != NULL) {
874 if((fp = fopen(statusfile, "a+")) == NULL) {
882 fprintf(fp, "NO. ASSOC-ID STATE RWND UNACKDATA PENDDATA INSTRMS OUTSTRMS "
883 "FRAG-POINT SPINFO-STATE SPINFO-CWDN SPINFO-SRTT SPINFO-RTO SPINFO-MTU\n");
885 if (cwnd != status.sstat_primary.spinfo_cwnd) {
888 fprintf(fp, "%-3d %-8d %-17s %-8d %-9d %-8d %-7d %-8d %-10d %-12s %-11d %-11d %-10d %d\n", count,
889 status.sstat_assoc_id, get_sstat_state(status.sstat_state),
890 status.sstat_rwnd, status.sstat_unackdata, status.sstat_penddata,
891 status.sstat_instrms, status.sstat_outstrms, status.sstat_fragmentation_point,
892 (status.sstat_primary.spinfo_state == 1) ? "ACTIVE" : "INACTIVE",
893 status.sstat_primary.spinfo_cwnd, status.sstat_primary.spinfo_srtt,
894 status.sstat_primary.spinfo_rto, status.sstat_primary.spinfo_mtu);
897 cwnd = status.sstat_primary.spinfo_cwnd;
904 if (status.sstat_primary.spinfo_state != 1) {