blob: 8563cbe67e13736065c12b0bd86f47ed84bc1b12 [file] [log] [blame]
Austin Schuh8d0a2852019-12-28 22:54:28 -08001/* SCTP kernel reference Implementation
2 * (C) Copyright Fujitsu Ltd. 2008, 2009
3 *
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)
8 * any later version.
9 *
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.
15 *
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.
20 *
21 * Please send any bug reports or fixes you make to the
22 * email address(es):
23 * lksctp developers <lksctp-developers@lists.sourceforge.net>
24 *
25 * Or submit a bug report through the following website:
26 * http://www.sf.net/projects/lksctp
27 *
28 * Any bugs reported to us we will try to fix... any fixes shared will
29 * be incorporated into the next SCTP release.
30 *
31 * Written or modified by:
32 * Wei Yongjun <yjwei@cn.fujitsu.com>
33 */
34
35#include <stdio.h>
36#include <stdlib.h>
37#include <sys/types.h>
38#include <sys/socket.h>
39#include <arpa/inet.h>
40#include <net/if.h>
41#include <netinet/sctp.h>
42#include <signal.h>
43#include <sys/time.h>
44#include <unistd.h>
45#include <errno.h>
46#include <netdb.h>
47#include <string.h>
48
49#define DEFAULT_SEC 0
50#define DEFAULT_USEC 5000
51
52#define REALLY_BIG 65536
53
54#define SERVER 0
55#define CLIENT 1
56#define NOT_DEFINED 666
57
58#define DEBUG_NONE 0
59#define DEBUG_MIN 1
60#define DEBUG_MAX 2
61
62#define ORDER_PATTERN_UNORDERED 0
63#define ORDER_PATTERN_ORDERED 1
64#define ORDER_PATTERN_ALTERNATE 2
65#define ORDER_PATTERN_RANDOM 3
66
67#define STREAM_PATTERN_SEQUENTIAL 0
68#define STREAM_PATTERN_RANDOM 1
69
70#define MAX_BIND_RETRYS 10
71#define BIG_REPEAT 1000000
72#define REPEAT 10
73
74#define DEFAULT_MAX_WINDOW 32768
75#define DEFAULT_MIN_WINDOW 1500
76
77#define MSG_CNT 10
78
79#define DEBUG_PRINT(level, print_this...) \
80{ \
81 if (debug_level >= level) { \
82 fprintf(stdout, print_this); \
83 fflush(stdout); \
84 } \
85} /* DEBUG_PRINT */
86
87char *local_host = NULL;
88int local_port = 0;
89char *remote_host = NULL;
90int remote_port = 0;
91struct sockaddr_storage s_rem, s_loc;
92int r_len, l_len;
93int size_arg = 0;
94int debug_level = DEBUG_NONE;
95int order_pattern = ORDER_PATTERN_UNORDERED;
96int order_state = 0;
97int stream_pattern = STREAM_PATTERN_SEQUENTIAL;
98int stream_state = 0;
99int repeat = REPEAT;
100int repeat_count = 0;
101int max_msgsize = DEFAULT_MAX_WINDOW;
102int msg_cnt = MSG_CNT;
103int drain = 0;
104int max_stream = 0;
105int gsk = -1;
106int period = 1;
107char *statusfile = NULL;
108
109void printstatus(int sk);
110void sighandler(int signo);
111void settimerhandle(void);
112void usage(char *argv0);
113void start_test(int role);
114
115unsigned char msg[] = "012345678901234567890123456789012345678901234567890";
116
117/* Convenience structure to determine space needed for cmsg. */
118typedef union {
119 struct sctp_initmsg init;
120 struct sctp_sndrcvinfo sndrcvinfo;
121} _sctp_cmsg_data_t;
122
123int 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;
128
129 /* Parse the arguments. */
130 while ((c = getopt(argc, argv, ":H:L:P:h:p:c:d:lm:sx:X:o:M:Di:I:f:")) >= 0 ) {
131 switch (c) {
132 case 'H':
133 local_host = optarg;
134 break;
135 case 'P':
136 local_port = atoi(optarg);
137 break;
138 case 'h':
139 remote_host = optarg;
140 break;
141 case 'p':
142 remote_port = atoi(optarg);
143 break;
144 case 'l':
145 if (role != NOT_DEFINED) {
146 printf("%s: only -s or -l\n", argv[0]);
147 usage(argv[0]);
148 exit(1);
149 }
150 role = SERVER;
151 break;
152 case 's':
153 if (role != NOT_DEFINED) {
154 printf("%s: only -s or -l\n", argv[0]);
155 usage(argv[0]);
156 exit(1);
157 }
158 role = CLIENT;
159 break;
160 case 'D':
161 drain = 1;
162 break;
163 case 'd':
164 debug_level = atoi(optarg);
165 if (debug_level < DEBUG_NONE
166 || debug_level > DEBUG_MAX) {
167 usage(argv[0]);
168 exit(1);
169 }
170 break;
171 case 'I':
172 period = atoi(optarg);
173 if (period < 0) {
174 usage(argv[0]);
175 exit(1);
176 }
177 break;
178 case 'x':
179 repeat = atoi(optarg);
180 if (!repeat) {
181 repeat = BIG_REPEAT;
182 }
183 break;
184 case 'X':
185 msg_cnt = atoi(optarg);
186 if ((msg_cnt <= 0) || (msg_cnt > MSG_CNT)) {
187 usage(argv[0]);
188 exit(1);
189 }
190 break;
191 case 'c':
192 size_arg = atoi(optarg);
193 if (size_arg < 0) {
194 usage(argv[0]);
195 exit(1);
196 }
197
198 break;
199 case 'o':
200 order_pattern = atoi(optarg);
201 if (order_pattern < ORDER_PATTERN_UNORDERED
202 || order_pattern > ORDER_PATTERN_RANDOM ) {
203 usage(argv[0]);
204 exit(1);
205 }
206 break;
207 case 'M':
208 max_stream = atoi(optarg);
209 if (max_stream < 0
210 || max_stream >= (1<<16)) {
211 usage(argv[0]);
212 exit(1);
213 }
214 break;
215 case 'm':
216 max_msgsize = atoi(optarg);
217 break;
218 case 'i':
219 interface = optarg;
220 break;
221 case 'f':
222 statusfile = optarg;
223 break;
224 case '?':
225 default:
226 usage(argv[0]);
227 exit(0);
228 }
229 } /* while() */
230
231 if (NOT_DEFINED == role) {
232 usage(argv[0]);
233 exit(1);
234 }
235
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]);
239 usage(argv[0]);
240 exit(1);
241 }
242 if (CLIENT == role && NULL == remote_host) {
243 fprintf(stderr, "%s: Client needs at least remote address "
244 "& port\n", argv[0]);
245 usage(argv[0]);
246 exit(1);
247 }
248
249 if (optind < argc) {
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");
254 usage(argv[0]);
255 exit(1);
256 }
257
258 if (remote_host != NULL && remote_port != 0) {
259 struct addrinfo *res;
260 int error;
261 char *host_s, *serv_s;
262
263 if ((host_s = malloc(NI_MAXHOST)) == NULL) {
264 fprintf(stderr, "\n*** host_s malloc failed!!! ***\n");
265 exit(1);
266 }
267 if ((serv_s = malloc(NI_MAXSERV)) == NULL) {
268 fprintf(stderr, "\n*** serv_s malloc failed!!! ***\n");
269 exit(1);
270 }
271
272 error = getaddrinfo(remote_host, 0, NULL, &res);
273 if (error) {
274 printf("%s.\n", gai_strerror(error));
275 usage(argv[0]);
276 exit(1);
277 }
278
279 switch (res->ai_family) {
280 case AF_INET:
281 t_addr = (struct sockaddr_in *)&s_rem;
282
283 memcpy(t_addr, res->ai_addr,
284 res->ai_addrlen);
285 t_addr->sin_family = res->ai_family;
286 t_addr->sin_port = htons(remote_port);
287
288 r_len = res->ai_addrlen;
289#ifdef __FreeBSD__
290 t_addr->sin_len = r_len;
291#endif
292 break;
293 case AF_INET6:
294 t_addr6 = (struct sockaddr_in6 *)&s_rem;
295
296 memcpy(t_addr6, res->ai_addr,
297 res->ai_addrlen);
298 t_addr6->sin6_family = res->ai_family;
299 t_addr6->sin6_port = htons(remote_port);
300 if (interface)
301 t_addr6->sin6_scope_id = if_nametoindex(interface);
302
303 r_len = res->ai_addrlen;
304
305#ifdef __FreeBSD__
306 t_addr6->sin6_len = r_len;
307#endif
308 break;
309 }
310
311 getnameinfo((struct sockaddr *)&s_rem, r_len, host_s,
312 NI_MAXHOST, serv_s, NI_MAXSERV, NI_NUMERICHOST);
313
314 DEBUG_PRINT(DEBUG_MAX, "remote:addr=%s, port=%s, family=%d\n",
315 host_s, serv_s, res->ai_family);
316
317 freeaddrinfo(res);
318 }
319
320 if (local_host != NULL) {
321 struct addrinfo *res;
322 int error;
323 char *host_s, *serv_s;
324 struct sockaddr_in *t_addr;
325 struct sockaddr_in6 *t_addr6;
326
327 if ((host_s = malloc(NI_MAXHOST)) == NULL) {
328 fprintf(stderr, "\n*** host_s malloc failed!!! ***\n");
329 exit(1);
330 }
331 if ((serv_s = malloc(NI_MAXSERV)) == NULL) {
332 fprintf(stderr, "\n*** serv_s malloc failed!!! ***\n");
333 exit(1);
334 }
335
336 if (strcmp(local_host, "0") == 0)
337 local_host = "0.0.0.0";
338
339 error = getaddrinfo(local_host, 0, NULL, &res);
340 if (error) {
341 printf("%s.\n", gai_strerror(error));
342 usage(argv[0]);
343 exit(1);
344 }
345
346 switch (res->ai_family) {
347 case AF_INET:
348 t_addr = (struct sockaddr_in *)&s_loc;
349
350 memcpy(t_addr, res->ai_addr,
351 res->ai_addrlen);
352 t_addr->sin_family = res->ai_family;
353 t_addr->sin_port = htons(local_port);
354
355 l_len = res->ai_addrlen;
356#ifdef __FreeBSD__
357 t_addr->sin_len = l_len;
358#endif
359 break;
360 case AF_INET6:
361 t_addr6 = (struct sockaddr_in6 *)&s_loc;
362
363 memcpy(t_addr6, res->ai_addr,
364 res->ai_addrlen);
365 t_addr6->sin6_family = res->ai_family;
366 t_addr6->sin6_port = htons(local_port);
367 if (interface)
368 t_addr6->sin6_scope_id = if_nametoindex(interface);
369
370 l_len = res->ai_addrlen;
371
372#ifdef __FreeBSD__
373 t_addr6->sin6_len = l_len;
374#endif
375 break;
376 }
377
378 error = getnameinfo((struct sockaddr *)&s_loc, l_len, host_s,
379 NI_MAXHOST, serv_s, NI_MAXSERV, NI_NUMERICHOST);
380
381 if (error)
382 printf("%s..\n", gai_strerror(error));
383
384 DEBUG_PRINT(DEBUG_MAX, "local:addr=%s, port=%s, family=%d\n",
385 host_s, serv_s, res->ai_family);
386
387 freeaddrinfo(res);
388 }
389
390 /* Let the testing begin. */
391 start_test(role);
392
393 return 0;
394}
395
396int bind_r(int sk, struct sockaddr_storage *saddr) {
397 int error = 0, i = 0;
398 char *host_s, *serv_s;
399
400 if ((host_s = malloc(NI_MAXHOST)) == NULL) {
401 fprintf(stderr, "\n\t\t*** host_s malloc failed!!! ***\n");
402 exit(1);
403 }
404 if ((serv_s = malloc(NI_MAXSERV)) == NULL) {
405 fprintf(stderr, "\n\t\t*** serv_s malloc failed!!! ***\n");
406 exit(1);
407 }
408
409 do {
410 if (i > 0) sleep(1); /* sleep a while before new try... */
411
412 error = getnameinfo((struct sockaddr *)saddr, l_len, host_s,
413 NI_MAXHOST, serv_s, NI_MAXSERV,
414 NI_NUMERICHOST);
415
416 if (error)
417 printf("%s\n", gai_strerror(error));
418
419 DEBUG_PRINT(DEBUG_MIN,
420 "\tbind(sk=%d, [a:%s,p:%s]) -- attempt %d/%d\n",
421 sk, host_s, serv_s, i+1, MAX_BIND_RETRYS);
422
423 error = bind(sk, (struct sockaddr *)saddr, l_len);
424
425 if (error != 0) {
426 if( errno != EADDRINUSE ) {
427 fprintf(stderr, "\n\n\t\t***bind: can "
428 "not bind to %s:%s: %s ****\n",
429 host_s, serv_s, strerror(errno));
430 exit(1);
431 }
432 }
433 i++;
434 if (i >= MAX_BIND_RETRYS) {
435 fprintf(stderr, "Maximum bind() attempts. "
436 "Die now...\n\n");
437 exit(1);
438 }
439 } while (error < 0 && i < MAX_BIND_RETRYS);
440
441 return 0;
442} /* bind_r() */
443
444int listen_r(int sk, int listen_count) {
445 int error = 0;
446
447 DEBUG_PRINT(DEBUG_MIN, "\tlisten(sk=%d,backlog=%d)\n",
448 sk, listen_count);
449
450 /* Mark sk as being able to accept new associations */
451 error = listen(sk, 1);
452 if (error != 0) {
453 fprintf(stderr, "\n\n\t\t*** listen: %s ***\n\n\n", strerror(errno));
454 exit(1);
455 }
456
457 return 0;
458} /* listen_r() */
459
460int accept_r(int sk){
461 socklen_t len = 0;
462
463 DEBUG_PRINT(DEBUG_MIN, "\taccept(sk=%d)\n", sk);
464
465 gsk = accept(sk, NULL, &len);
466 if (gsk < 0) {
467 fprintf(stderr, "\n\n\t\t*** accept: %s ***\n\n\n", strerror(errno));
468 exit(1);
469 }
470
471 return 0;
472} /* accept_r() */
473
474int connect_r(int sk, const struct sockaddr *serv_addr, socklen_t addrlen) {
475 int error = 0;
476
477 DEBUG_PRINT(DEBUG_MIN, "\tconnect(sk=%d)\n", sk);
478
479 /* Mark sk as being able to accept new associations */
480 error = connect(sk, serv_addr, addrlen);
481 if (error != 0) {
482 fprintf(stderr, "\n\n\t\t*** connect: %s ***\n\n\n",
483 strerror(errno));
484 exit(1);
485 }
486
487 gsk = sk;
488
489 return 0;
490} /* connect_r() */
491
492int close_r(int sk) {
493 int error = 0;
494
495 DEBUG_PRINT(DEBUG_MIN, "\tclose(sk=%d)\n",sk);
496
497 error = close(sk);
498 if (error != 0) {
499 fprintf(stderr, "\n\n\t\t*** close: %s ***\n\n",
500 strerror(errno));
501 exit(1);
502 }
503 fflush(stdout);
504 return 0;
505} /* close_r() */
506
507int receive_r(int sk)
508{
509 int error = 0;
510 char incmsg[CMSG_SPACE(sizeof(_sctp_cmsg_data_t))];
511 struct iovec iov;
512 struct msghdr inmessage;
513
514 /* Initialize inmessage with enough space for DATA... */
515 memset(&inmessage, 0, sizeof(inmessage));
516 if ((iov.iov_base = malloc(REALLY_BIG)) == NULL) {
517 fprintf(stderr, "\n\t\t*** malloc not enough memory!!! ***\n");
518 exit(1);
519 }
520 iov.iov_len = REALLY_BIG;
521 inmessage.msg_iov = &iov;
522 inmessage.msg_iovlen = 1;
523 /* or a control message. */
524 inmessage.msg_control = incmsg;
525 inmessage.msg_controllen = sizeof(incmsg);
526
527 /* Get the messages sent */
528 while (1) {
529 DEBUG_PRINT(DEBUG_MIN, "\trecvmsg(sk=%d) ", sk);
530
531 error = recvmsg(sk, &inmessage, MSG_WAITALL);
532 if (error < 0 && errno != EAGAIN) {
533 fprintf(stderr, "\n\t\t*** recvmsg: %s ***\n\n",
534 strerror(errno));
535 fflush(stdout);
536 close(sk);
537 free(iov.iov_base);
538 exit(1);
539 } else if (error == 0) {
540 printf("\n\t\trecvmsg() returned 0 !!!!\n");
541 fflush(stdout);
542 }
543
544 if(MSG_NOTIFICATION & inmessage.msg_flags)
545 continue; /* got a notification... */
546
547 inmessage.msg_control = incmsg;
548 inmessage.msg_controllen = sizeof(incmsg);
549 iov.iov_len = REALLY_BIG;
550 break;
551 }
552
553 free(iov.iov_base);
554 return 0;
555} /* receive_r () */
556
557void server(int sk) {
558 int i;
559
560 if (max_msgsize > DEFAULT_MAX_WINDOW) {
561 if (setsockopt(sk, IPPROTO_SCTP, SO_RCVBUF, &max_msgsize,
562 sizeof(max_msgsize)) < 0) {
563 perror("setsockopt(SO_RCVBUF)");
564 exit(1);
565 }
566 }
567
568 for (i = 0; i < msg_cnt; i++) {
569 receive_r(sk);
570 DEBUG_PRINT(DEBUG_MIN, "count %d\n", i+1);
571 }
572} /* server() */
573
574void * build_msg(int len) {
575 int i = len - 1;
576 int n;
577 char *msg_buf, *p;
578
579 msg_buf = malloc(len);
580 if (NULL == msg_buf) {
581 fprintf(stderr, "\n\t\t*** malloc not enough memory!!! ***\n");
582 exit(1);
583 }
584 p = msg_buf;
585
586 do {
587 n = ((i > 50)?50:i);
588 memcpy(p, msg, ((i > 50)?50:i));
589 p += n;
590 i -= n;
591 } while (i > 0);
592
593 msg_buf[len-1] = '\0';
594
595 return(msg_buf);
596
597} /* build_msg() */
598
599int send_r(int sk, int stream, int order, int send_size, int assoc_i) {
600 int error = 0;
601 struct msghdr outmsg;
602 struct iovec iov;
603 char *message = NULL;
604 int msglen = 0;
605 char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
606 struct cmsghdr *cmsg;
607 struct sctp_sndrcvinfo *sinfo;
608
609 if (send_size > 0) {
610 message = build_msg(send_size);
611 msglen = strlen(message) + 1;
612 iov.iov_base = message;
613 iov.iov_len = msglen;
614 } else {
615 exit(1);
616 }
617
618 outmsg.msg_name = &s_rem;
619 outmsg.msg_namelen = sizeof(struct sockaddr_storage);
620 outmsg.msg_iov = &iov;
621 outmsg.msg_iovlen = 1;
622 outmsg.msg_control = outcmsg;
623 outmsg.msg_controllen = sizeof(outcmsg);
624 outmsg.msg_flags = 0;
625
626 cmsg = CMSG_FIRSTHDR(&outmsg);
627 cmsg->cmsg_level = IPPROTO_SCTP;
628 cmsg->cmsg_type = SCTP_SNDRCV;
629 cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
630
631 outmsg.msg_controllen = cmsg->cmsg_len;
632 sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
633 memset(sinfo, 0, sizeof(struct sctp_sndrcvinfo));
634 sinfo->sinfo_ppid = rand();
635 sinfo->sinfo_stream = stream;
636 sinfo->sinfo_flags = 0;
637 if (!order)
638 sinfo->sinfo_flags = SCTP_UNORDERED;
639
640 DEBUG_PRINT(DEBUG_MIN, "\tsendmsg(sk=%d, assoc=%d) %4d bytes.\n",
641 sk, assoc_i, send_size);
642 DEBUG_PRINT(DEBUG_MAX, "\t SNDRCV");
643 if (DEBUG_MAX == debug_level) {
644 printf("(stream=%u ", sinfo->sinfo_stream);
645 printf("flags=0x%x ", sinfo->sinfo_flags);
646 printf("ppid=%u)\n", sinfo->sinfo_ppid);
647 }
648
649 /* Send to our neighbor. */
650 error = sendmsg(sk, &outmsg, MSG_WAITALL);
651 if (error != msglen) {
652 fprintf(stderr, "\n\t\t*** sendmsg: %s ***\n\n",
653 strerror(errno));
654 fflush(stdout);
655 exit(1);
656 }
657
658 if (send_size > 0) free(message);
659 return 0;
660} /* send_r() */
661
662int next_order(int state, int pattern)
663{
664 switch (pattern){
665 case ORDER_PATTERN_UNORDERED:
666 state = 0;
667 break;
668 case ORDER_PATTERN_ORDERED:
669 state = 1;
670 break;
671 case ORDER_PATTERN_ALTERNATE:
672 state = state ? 0 : 1;
673 break;
674 case ORDER_PATTERN_RANDOM:
675 state = rand() % 2;
676 break;
677 }
678
679 return state;
680}
681
682int next_stream(int state, int pattern)
683{
684 switch (pattern){
685 case STREAM_PATTERN_RANDOM:
686 state = rand() % max_stream;
687 break;
688 case STREAM_PATTERN_SEQUENTIAL:
689 state = state + 1;
690 if (state >= max_stream)
691 state = 0;
692 break;
693 }
694
695 return state;
696}
697
698int next_msg_size(int msg_cnt)
699{
700 int msg_size;
701
702 if (size_arg) {
703 msg_size = size_arg;
704 } else {
705 msg_size = (rand() % max_msgsize) + 1;
706 }
707
708 return msg_size;
709
710} /* next_msg_size() */
711
712void client(int sk) {
713 int msg_size;
714 int i;
715
716 for (i = 0; i < msg_cnt; i++) {
717 msg_size = next_msg_size(i);
718 order_state = next_order(order_state, order_pattern);
719 stream_state = next_stream(stream_state, stream_pattern);
720
721 if (send_r(sk, stream_state, order_state, msg_size, 0) < 0) {
722 close(sk);
723 break;
724 }
725
726 /* The sender is echoing so do discard the echoed data. */
727 if (drain && ((i + 1) % period == 0)) {
728 receive_r(sk);
729 }
730 }
731} /* client() */
732
733void start_test(int role) {
734 int sk, pid, ret;
735 int i = 0;
736
737 DEBUG_PRINT(DEBUG_NONE, "\nStarting tests...\n");
738
739 repeat_count = repeat;
740
741 DEBUG_PRINT(DEBUG_MIN, "\tsocket(SOCK_STREAM, IPPROTO_SCTP)");
742
743 if ((sk = socket(s_loc.ss_family, SOCK_STREAM, IPPROTO_SCTP)) < 0 ) {
744 fprintf(stderr, "\n\n\t\t*** socket: failed to create"
745 " socket: %s ***\n", strerror(errno));
746 exit(1);
747 }
748 DEBUG_PRINT(DEBUG_MIN, " -> sk=%d\n", sk);
749
750 bind_r(sk, &s_loc);
751
752 if (role == SERVER) {
753 listen_r(sk, 1);
754 accept_r(sk);
755 } else {
756 if (max_stream > 0) {
757 struct sctp_initmsg initmsg;
758
759 memset(&initmsg, 0, sizeof(initmsg));
760 initmsg.sinit_num_ostreams = max_stream;
761 initmsg.sinit_max_instreams = max_stream;
762 initmsg.sinit_max_attempts = 3;
763
764 ret = setsockopt(sk, IPPROTO_SCTP, SCTP_INITMSG,
765 &initmsg, sizeof(initmsg));
766 if (ret < 0) {
767 perror("setsockopt(SCTP_INITMSG)");
768 exit(0);
769 }
770 }
771
772 connect_r(sk, (struct sockaddr *)&s_rem, r_len);
773 }
774
775 if ((pid = fork()) == 0) {
776 settimerhandle();
777 printstatus(gsk);
778 while(1);
779 } else {
780 if (!debug_level) {
781 printf(" ");
782 }
783
784 for(i = 0; i < repeat_count; i++) {
785
786 if (role == SERVER) {
787 DEBUG_PRINT(DEBUG_NONE, "Server: Receiving packets.(%d/%d)\n",
788 i+1, repeat_count);
789 server(gsk);
790 } else {
791 DEBUG_PRINT(DEBUG_NONE, "Client: Sending packets.(%d/%d)\n",
792 i+1, repeat_count);
793 client(sk);
794 }
795
796 fflush(stdout);
797 }
798
799 if (role == SERVER) close_r(gsk);
800 close_r(sk);
801 }
802} /* start_test() */
803
804void settimerhandle(void) {
805 struct sigaction act;
806 struct itimerval interval;
807
808 act.sa_handler = sighandler;
809 act.sa_flags = 0;
810 sigemptyset(&act.sa_mask);
811 sigaction(SIGPROF, &act, NULL);
812
813 interval.it_value.tv_sec = DEFAULT_SEC;
814 interval.it_value.tv_usec = DEFAULT_USEC;
815 interval.it_interval = interval.it_value;
816
817 setitimer(ITIMER_PROF, &interval, NULL);
818}
819
820void usage(char *argv0) {
821 fprintf(stderr, "\nusage:\n");
822 fprintf(stderr, " server:\n");
823 fprintf(stderr, " %8s -H local-addr -P local-port -l [-d level] [-x]\n"
824 "\t [-L num-ports] [-S num-ports]\n"
825 "\t [-a assoc-pattern]\n"
826 "\t [-i interface]\n"
827 "\t [-f status-file]\n",
828 argv0);
829 fprintf(stderr, "\n");
830 fprintf(stderr, " client:\n");
831 fprintf(stderr, " %8s -H local-addr -P local-port -h remote-addr\n"
832 "\t -p remote-port -s [-c case ] [-d level]\n"
833 "\t [-x repeat] [-o order-pattern] ream-pattern]\n"
834 "\t [-M max-stream]\n"
835 "\t [-m max-msgsize]\n"
836 "\t [-L num-ports] [-S num-ports]\n"
837 "\t [-i interface]\n"
838 "\t [-f status-file]\n",
839 argv0);
840 fprintf(stderr, "\n");
841 fprintf(stderr, "\t-c value = Packets of specifed size.\n");
842 fprintf(stderr, "\t-m msgsize(1500-65515, default value 32768)\n");
843 fprintf(stderr, "\t-x number of repeats\n");
844 fprintf(stderr, "\t-X number of messages\n");
845 fprintf(stderr, "\t-o order-pattern\n");
846 fprintf(stderr, "\t 0 = all unordered(default) \n");
847 fprintf(stderr, "\t 1 = all ordered \n");
848 fprintf(stderr, "\t 2 = alternating \n");
849 fprintf(stderr, "\t 3 = random\n");
850 fprintf(stderr, "\t-M max-stream (default value 0)\n");
851 fprintf(stderr, "\t-D drain. If in client mode do a read following send.\n");
852 fprintf(stderr, "\t-I receive after <n> times of send, default value 1.\n");
853 fprintf(stderr, "\n");
854 fflush(stderr);
855
856} /* usage() */
857
858void sighandler(int signo) {
859 DEBUG_PRINT(DEBUG_MAX, "timeout sig\n");
860 printstatus(gsk);
861}
862
863char* get_sstat_state(int state) {
864 switch(state) {
865 case SCTP_EMPTY:
866 return "EMPTY";
867 case SCTP_CLOSED:
868 return "CLOSED";
869 case SCTP_COOKIE_WAIT:
870 return "COOKIE_WAIT";
871 case SCTP_COOKIE_ECHOED:
872 return "COOKIE_ECHOED";
873 case SCTP_ESTABLISHED:
874 return "ESTABLISHED";
875 case SCTP_SHUTDOWN_PENDING:
876 return "SHUTDOWN_PENDING";
877 case SCTP_SHUTDOWN_SENT:
878 return "SHUTDOWN_SENT";
879 case SCTP_SHUTDOWN_RECEIVED:
880 return "SHUTDOWN_RECEIVED";
881 case SCTP_SHUTDOWN_ACK_SENT:
882 return "SHUTDOWN_ACK_SENT";
883 default:
884 return "UNKNOW";
885 }
886}
887
888void printstatus(int sk) {
889 static int cwnd = 0;
890 static int count = 0;
891 struct sctp_status status;
892 socklen_t optlen;
893 FILE * fp;
894 const char *state_to_str[] = {
895 [SCTP_INACTIVE] = "INACTIVE",
896 [SCTP_PF] = "PF",
897 [SCTP_ACTIVE] = "ACTIVE",
898 [SCTP_UNCONFIRMED] = "UNCONFIRMED",
899 };
900
901 optlen = sizeof(struct sctp_status);
902 if(getsockopt(sk, IPPROTO_SCTP, SCTP_STATUS, &status, &optlen) < 0) {
903 fprintf(stderr, "Error getting status: %s.\n", strerror(errno));
904 exit(1);
905 }
906
907 if (statusfile != NULL) {
908 if (count == 0)
909 unlink(statusfile);
910
911 if((fp = fopen(statusfile, "a+")) == NULL) {
912 perror("fopen");
913 exit(1);
914 }
915 } else
916 fp = stdout;
917
918 if (count == 0)
919 fprintf(fp, "NO. ASSOC-ID STATE RWND UNACKDATA PENDDATA INSTRMS OUTSTRMS "
920 "FRAG-POINT SPINFO-STATE SPINFO-CWDN SPINFO-SRTT SPINFO-RTO SPINFO-MTU\n");
921
922 if (cwnd != status.sstat_primary.spinfo_cwnd) {
923 count++;
924
925 fprintf(fp, "%-3d %-8d %-17s %-8d %-9d %-8d %-7d %-8d %-10d %-12s %-11d %-11d %-10d %d\n", count,
926 status.sstat_assoc_id, get_sstat_state(status.sstat_state),
927 status.sstat_rwnd, status.sstat_unackdata, status.sstat_penddata,
928 status.sstat_instrms, status.sstat_outstrms, status.sstat_fragmentation_point,
929 state_to_str[status.sstat_primary.spinfo_state],
930 status.sstat_primary.spinfo_cwnd, status.sstat_primary.spinfo_srtt,
931 status.sstat_primary.spinfo_rto, status.sstat_primary.spinfo_mtu);
932 }
933
934 cwnd = status.sstat_primary.spinfo_cwnd;
935
936 fflush(fp);
937
938 if (fp != stdout)
939 fclose(fp);
940
941 if (status.sstat_primary.spinfo_state != SCTP_ACTIVE) {
942 close_r(sk);
943 exit(1);
944 }
945}