Imported Upstream version 1.0.10
[platform/upstream/lksctp-tools.git] / src / apps / sctp_status.c
1 /* 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
87 char *local_host = NULL;
88 int local_port = 0;
89 char *remote_host = NULL;
90 int remote_port = 0;
91 struct sockaddr_storage s_rem, s_loc;
92 int r_len, l_len;
93 int size_arg = 0;
94 int debug_level = DEBUG_NONE;
95 int order_pattern = ORDER_PATTERN_UNORDERED;
96 int order_state = 0;
97 int stream_pattern = STREAM_PATTERN_SEQUENTIAL;
98 int stream_state = 0;
99 int repeat = REPEAT;
100 int repeat_count = 0;
101 int max_msgsize = DEFAULT_MAX_WINDOW;
102 int msg_cnt = MSG_CNT;
103 int drain = 0;
104 int max_stream = 0;
105 int gsk = -1;
106 int period = 1;
107 char *statusfile = NULL;
108
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);
114
115 unsigned char msg[] = "012345678901234567890123456789012345678901234567890";
116
117 /* Convenience structure to determine space needed for cmsg. */
118 typedef union {
119         struct sctp_initmsg init;
120         struct sctp_sndrcvinfo sndrcvinfo;
121 } _sctp_cmsg_data_t;
122
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;
128
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 ) {
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                                 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);
286
287                                 r_len = sizeof (struct sockaddr_in);
288 #ifdef __FreeBSD__
289                                 t_addr->sin_len = r_len;
290 #endif
291                                 break;
292                         case AF_INET6:
293                                 t_addr6 = (struct sockaddr_in6 *)&s_rem;
294
295                                 if (interface)
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);
300
301                                 r_len = sizeof (struct sockaddr_in6);
302
303 #ifdef __FreeBSD__
304                                 t_addr6->sin6_len = r_len;
305 #endif
306                                 break;
307                 }
308
309                 getnameinfo((struct sockaddr *)&s_rem, r_len, host_s,
310                             NI_MAXHOST, serv_s, NI_MAXSERV, NI_NUMERICHOST);
311
312                 DEBUG_PRINT(DEBUG_MAX, "remote:addr=%s, port=%s, family=%d\n",
313                             host_s, serv_s, res->ai_family);
314         }
315
316         if (local_host != NULL) {
317                 struct addrinfo *res;
318                 int error;
319                 char *host_s, *serv_s;
320                 struct sockaddr_in *t_addr;
321                 struct sockaddr_in6 *t_addr6;
322
323                 if ((host_s = malloc(NI_MAXHOST)) == NULL) {
324                         fprintf(stderr, "\n*** host_s malloc failed!!! ***\n");
325                         exit(1);
326                 }
327                 if ((serv_s = malloc(NI_MAXSERV)) == NULL) {
328                         fprintf(stderr, "\n*** serv_s malloc failed!!! ***\n");
329                         exit(1);
330                 }
331
332                 if (strcmp(local_host, "0") == 0)
333                         local_host = "0.0.0.0";
334
335                 error = getaddrinfo(local_host, 0, NULL, &res);
336                 if (error) {
337                         printf("%s.\n", gai_strerror(error));
338                         usage(argv[0]);
339                         exit(1);
340                 }
341
342                 switch (res->ai_family) {
343                         case AF_INET:
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);
348
349                                 l_len = sizeof (struct sockaddr_in);
350 #ifdef __FreeBSD__
351                                 t_addr->sin_len = l_len;
352 #endif
353                                 break;
354                         case AF_INET6:
355                                 t_addr6 = (struct sockaddr_in6 *)&s_loc;
356
357                                 if (interface)
358                                         t_addr6->sin6_scope_id = if_nametoindex(interface);
359                                 t_addr6->sin6_family = AF_INET6;
360                                 t_addr6->sin6_port = htons(local_port);
361
362                                 inet_pton(AF_INET6, local_host, &t_addr6->sin6_addr);
363
364                                 l_len = sizeof (struct sockaddr_in6);
365
366 #ifdef __FreeBSD__
367                                 t_addr6->sin6_len = l_len;
368 #endif
369                                 break;
370                 }
371
372                 error = getnameinfo((struct sockaddr *)&s_loc, l_len, host_s,
373                             NI_MAXHOST, serv_s, NI_MAXSERV, NI_NUMERICHOST);
374
375                 if (error)
376                         printf("%s..\n", gai_strerror(error));
377
378                 DEBUG_PRINT(DEBUG_MAX, "local:addr=%s, port=%s, family=%d\n",
379                             host_s, serv_s, res->ai_family);
380         }
381
382         /* Let the testing begin. */
383         start_test(role);
384
385         return 0;
386 }
387
388 int bind_r(int sk, struct sockaddr_storage *saddr) {
389         int error = 0, i = 0;
390         char *host_s, *serv_s;
391
392         if ((host_s = malloc(NI_MAXHOST)) == NULL) {
393                 fprintf(stderr, "\n\t\t*** host_s malloc failed!!! ***\n");
394                 exit(1);
395         }
396         if ((serv_s = malloc(NI_MAXSERV)) == NULL) {
397                 fprintf(stderr, "\n\t\t*** serv_s malloc failed!!! ***\n");
398                 exit(1);
399         }
400
401         do {
402                 if (i > 0) sleep(1); /* sleep a while before new try... */
403
404                 error = getnameinfo((struct sockaddr *)saddr, l_len, host_s,
405                                     NI_MAXHOST, serv_s, NI_MAXSERV,
406                                     NI_NUMERICHOST);
407
408                 if (error)
409                         printf("%s\n", gai_strerror(error));
410
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);
414
415                 error = bind(sk, (struct sockaddr *)saddr, l_len);
416
417                 if (error != 0) {
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));
422                                 exit(1);
423                         }
424                 }
425                 i++;
426                 if (i >= MAX_BIND_RETRYS) {
427                         fprintf(stderr, "Maximum bind() attempts. "
428                                 "Die now...\n\n");
429                         exit(1);
430                 }
431         } while (error < 0 && i < MAX_BIND_RETRYS);
432
433         return 0;
434 } /* bind_r() */
435
436 int listen_r(int sk, int listen_count) {
437         int error = 0;
438
439         DEBUG_PRINT(DEBUG_MIN, "\tlisten(sk=%d,backlog=%d)\n",
440                 sk, listen_count);
441
442         /* Mark sk as being able to accept new associations */
443         error = listen(sk, 1);
444         if (error != 0) {
445                 fprintf(stderr, "\n\n\t\t*** listen:  %s ***\n\n\n", strerror(errno));
446                 exit(1);
447         }
448
449         return 0;
450 } /* listen_r() */
451
452 int accept_r(int sk){
453         socklen_t len = 0;
454
455         DEBUG_PRINT(DEBUG_MIN, "\taccept(sk=%d)\n", sk);
456
457         gsk = accept(sk, NULL, &len);
458         if (gsk < 0) {
459                 fprintf(stderr, "\n\n\t\t*** accept:  %s ***\n\n\n", strerror(errno));
460                 exit(1);
461         }
462
463         return 0;
464 } /* accept_r() */
465
466 int connect_r(int sk, const struct sockaddr *serv_addr, socklen_t addrlen) {
467         int error = 0;
468
469         DEBUG_PRINT(DEBUG_MIN, "\tconnect(sk=%d)\n", sk);
470
471         /* Mark sk as being able to accept new associations */
472         error = connect(sk, serv_addr, addrlen);
473         if (error != 0) {
474                 fprintf(stderr, "\n\n\t\t*** connect:  %s ***\n\n\n",
475                         strerror(errno));
476                 exit(1);
477         }
478
479         gsk = sk;
480
481         return 0;
482 } /* connect_r() */
483
484 int close_r(int sk) {
485         int error = 0;
486
487         DEBUG_PRINT(DEBUG_MIN, "\tclose(sk=%d)\n",sk);
488
489         error = close(sk);
490         if (error != 0) {
491                 fprintf(stderr, "\n\n\t\t*** close: %s ***\n\n",
492                         strerror(errno));
493                 exit(1);
494         }
495         fflush(stdout);
496         return 0;
497 } /* close_r() */
498
499 int receive_r(int sk)
500 {
501         int error = 0;
502         char incmsg[CMSG_SPACE(sizeof(_sctp_cmsg_data_t))];
503         struct iovec iov;
504         struct msghdr inmessage;
505
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");
510                 exit(1);
511         }
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);
518
519         /* Get the messages sent */
520         while (1) {
521                 DEBUG_PRINT(DEBUG_MIN, "\trecvmsg(sk=%d) ", sk);
522
523                 error = recvmsg(sk, &inmessage, MSG_WAITALL);
524                 if (error < 0 && error != EAGAIN) {
525                         fprintf(stderr, "\n\t\t*** recvmsg: %s ***\n\n",
526                                         strerror(errno));
527                         fflush(stdout);
528                         close(sk);
529                         free(iov.iov_base);
530                         exit(1);
531                 } else if (error == 0) {
532                         printf("\n\t\trecvmsg() returned 0 !!!!\n");
533                         fflush(stdout);
534                 }
535
536                 if(MSG_NOTIFICATION & inmessage.msg_flags)
537                         continue; /* got a notification... */
538
539                 inmessage.msg_control = incmsg;
540                 inmessage.msg_controllen = sizeof(incmsg);
541                 iov.iov_len = REALLY_BIG;
542                 break;
543         }
544
545         free(iov.iov_base);
546         return 0;
547 } /* receive_r () */
548
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)");
554                         exit(1);
555                 }
556         }
557
558         receive_r(sk);
559 } /* server() */
560
561 void * build_msg(int len) {
562         int i = len - 1;
563         int n;
564         char *msg_buf, *p;
565
566         msg_buf = malloc(len);
567         if (NULL == msg_buf) {
568                 fprintf(stderr, "\n\t\t*** malloc not enough memory!!! ***\n");
569                 exit(1);
570         }
571         p = msg_buf;
572
573         do {
574                 n = ((i > 50)?50:i);
575                 memcpy(p, msg, ((i > 50)?50:i));
576                 p += n;
577                 i -= n;
578         } while (i > 0);
579
580         msg_buf[len-1] = '\0';
581
582         return(msg_buf);
583
584 } /* build_msg() */
585
586 int send_r(int sk, int stream, int order, int send_size, int assoc_i) {
587         int error = 0;
588         struct msghdr outmsg;
589         struct iovec iov;
590         char *message = NULL;
591         int msglen = 0;
592         char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
593         struct cmsghdr *cmsg;
594         struct sctp_sndrcvinfo *sinfo;
595
596         if (send_size > 0) {
597                 message = build_msg(send_size);
598                 msglen = strlen(message) + 1;
599                 iov.iov_base = message;
600                 iov.iov_len = msglen;
601         } else {
602                         exit(1);
603         }
604
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;
612
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));
617
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;
624         if (!order)
625                 sinfo->sinfo_flags = SCTP_UNORDERED;
626
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);
634         }
635
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",
640                         strerror(errno));
641                 fflush(stdout);
642                 exit(1);
643         }
644
645         if (send_size > 0) free(message);
646         return 0;
647 } /* send_r() */
648
649 int next_order(int state, int pattern)
650 {
651         switch (pattern){
652         case ORDER_PATTERN_UNORDERED:
653                 state = 0;
654                 break;
655         case ORDER_PATTERN_ORDERED:
656                 state = 1;
657                 break;
658         case ORDER_PATTERN_ALTERNATE:
659                 state = state ? 0 : 1;
660                 break;
661         case ORDER_PATTERN_RANDOM:
662                 state = rand() % 2;
663                 break;
664         }
665
666         return state;
667 }
668
669 int next_stream(int state, int pattern)
670 {
671         switch (pattern){
672         case STREAM_PATTERN_RANDOM:
673                 state = rand() % (max_stream + 1);
674                 break;
675         case STREAM_PATTERN_SEQUENTIAL:
676                 state = state + 1;
677                 if (state > max_stream)
678                         state = 0;
679                 break;
680         }
681
682         return state;
683 }
684
685 int next_msg_size(int msg_cnt)
686 {
687         int msg_size;
688
689         if (size_arg) {
690                 msg_size = size_arg;
691         } else {
692                 msg_size = (rand() % max_msgsize) + 1;
693         }
694
695         return msg_size;
696
697 } /* next_msg_size() */
698
699 void client(int sk) {
700         int msg_size;
701         int i;
702
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);
707
708                 if (send_r(sk, stream_state, order_state, msg_size, 0) < 0) {
709                         close(sk);
710                         break;
711                 }
712
713                 /* The sender is echoing so do discard the echoed data. */
714                 if (drain && ((i + 1) % period == 0)) {
715                         receive_r(sk);
716                 }
717         }
718 } /* client() */
719
720 void start_test(int role) {
721         int sk, pid;
722         int i = 0;
723
724         DEBUG_PRINT(DEBUG_NONE, "\nStarting tests...\n");
725
726         repeat_count = repeat;
727
728         DEBUG_PRINT(DEBUG_MIN, "\tsocket(SOCK_STREAM, IPPROTO_SCTP)");
729
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));
733                 exit(1);
734         }
735         DEBUG_PRINT(DEBUG_MIN, "  ->  sk=%d\n", sk);
736
737         bind_r(sk, &s_loc);
738
739         if (role == SERVER) {
740                 listen_r(sk, 1);
741                 accept_r(sk);
742         } else {
743                 connect_r(sk, (struct sockaddr *)&s_rem, r_len);
744         }
745
746         if ((pid = fork()) == 0) {
747                 settimerhandle();
748                 printstatus(gsk);
749                 while(1);
750         } else {
751                 if (!debug_level) {
752                         printf("     ");
753                 }
754
755                 for(i = 0; i < repeat_count; i++) {
756
757                         if (role == SERVER) {
758                                 DEBUG_PRINT(DEBUG_NONE, "Server: Receiving packets.(%d/%d)\n",
759                                         i+1, repeat_count);
760                                 server(gsk);
761                         } else {
762                                 DEBUG_PRINT(DEBUG_NONE, "Client: Sending packets.(%d/%d)\n",
763                                         i+1, repeat_count);
764                                 client(sk);
765                         }
766
767                         fflush(stdout);
768                 }
769
770                 if (role == SERVER) close_r(gsk);
771                 close_r(sk);
772         }
773 } /* start_test() */
774
775 void settimerhandle(void) {
776         struct sigaction act;
777         struct itimerval interval;
778
779         act.sa_handler = sighandler;
780         act.sa_flags = 0;
781         sigemptyset(&act.sa_mask);
782         sigaction(SIGPROF, &act, NULL);
783
784         interval.it_value.tv_sec = DEFAULT_SEC;
785         interval.it_value.tv_usec = DEFAULT_USEC;
786         interval.it_interval = interval.it_value;
787
788         setitimer(ITIMER_PROF, &interval, NULL);
789 }
790
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",
799                 argv0);
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",
810                 argv0);
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");
823         fflush(stderr);
824
825 } /* usage() */
826
827 void sighandler(int signo) {
828         DEBUG_PRINT(DEBUG_MAX, "timeout sig\n");
829         printstatus(gsk);
830 }
831
832 char* get_sstat_state(int state) {
833         switch(state) {
834         case SCTP_EMPTY:
835                 return "EMPTY";
836         case SCTP_CLOSED:
837                 return "CLOSED";
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";
852         default:
853                 return "UNKNOW";
854         }
855 }
856
857 void printstatus(int sk) {
858         static int cwnd = 0;
859         static int count = 0;
860         struct sctp_status status;
861         socklen_t optlen;
862         FILE * fp;
863
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));
867                 exit(1);
868         }
869
870         if (statusfile != NULL) {
871                 if (count == 0)
872                         unlink(statusfile);
873
874                 if((fp = fopen(statusfile, "a+")) == NULL) {
875                         perror("fopen");
876                         exit(1);
877                 }
878         } else
879                 fp = stdout;
880
881         if (count == 0)
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");
884
885         if (cwnd != status.sstat_primary.spinfo_cwnd) {
886                 count++;
887
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);
895         }
896
897         cwnd = status.sstat_primary.spinfo_cwnd;
898
899         fflush(fp);
900
901         if (fp != stdout)
902                 fclose(fp);
903
904         if (status.sstat_primary.spinfo_state != 1) {
905                 close_r(sk);
906                 exit(1);
907         }
908 }