1 /*
2 * Copyright (C) 2005-2013 Michael Tuexen
3 * Copyright (C) 2011-2013 Irene Ruengeler
4 * Copyright (C) 2014-2019 Felix Weinrank
5 *
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the project nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33 #include <sys/types.h>
34 #ifdef _WIN32
35 #include <winsock2.h>
36 #include <ws2tcpip.h>
37 #include <stdlib.h>
38 #include <crtdbg.h>
39 #include <sys/timeb.h>
40 #else
41 #include <sys/socket.h>
42 #include <netinet/in.h>
43 #include <arpa/inet.h>
44 #include <sys/time.h>
45 #include <unistd.h>
46 #include <pthread.h>
47 #endif
48 #include <stdarg.h>
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <signal.h>
53 #include <errno.h>
54 #include <inttypes.h>
55 #ifdef LINUX
56 #include <getopt.h>
57 #endif
58 #include <usrsctp.h>
59 #include "programs_helper.h"
60
61 #define TSCTP_CLIENT 1
62 #define TSCTP_SERVER 2
63
64 #define DEFAULT_LENGTH 1024
65 #define DEFAULT_NUMBER_OF_MESSAGES 1024
66 #define DEFAULT_PORT 5001
67 #define BUFFERSIZE (1<<16)
68
69 static int par_verbose = 0;
70 static int par_very_verbose = 0;
71 static unsigned int done = 0;
72
73 struct tsctp_meta {
74 uint8_t par_role;
75 uint8_t par_stats_human;
76 uint8_t par_ordered;
77 uint64_t par_messages;
78 uint64_t par_message_length;
79 uint64_t par_runtime;
80
81 uint64_t stat_messages;
82 uint64_t stat_message_length;
83 uint64_t stat_notifications;
84 uint64_t stat_recv_calls;
85 struct timeval stat_start;
86
87 uint64_t stat_fragment_sum;
88
89 char *buffer;
90 };
91
92 #ifndef timersub
93 #define timersub(tvp, uvp, vvp) \
94 do { \
95 (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \
96 (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \
97 if ((vvp)->tv_usec < 0) { \
98 (vvp)->tv_sec--; \
99 (vvp)->tv_usec += 1000000; \
100 } \
101 } while (0)
102 #endif
103
104 #ifdef _WIN32
105 static void
gettimeofday(struct timeval * tv,void * ignore)106 gettimeofday(struct timeval *tv, void *ignore)
107 {
108 struct timeb tb;
109
110 ftime(&tb);
111 tv->tv_sec = (long)tb.time;
112 tv->tv_usec = tb.millitm * 1000;
113 }
114 #endif
115
116
117 char Usage[] =
118 "Usage: tsctp [options] [address]\n"
119 "Options:\n"
120 " -a set adaptation layer indication\n"
121 " -E local UDP encapsulation port (default 9899)\n"
122 " -f fragmentation point\n"
123 " -H human readable statistics"
124 " -l message length\n"
125 " -L bind to local IP (default INADDR_ANY)\n"
126 " -n number of messages sent (0 means infinite)/received\n"
127 " -D turns Nagle off\n"
128 " -R socket recv buffer\n"
129 " -S socket send buffer\n"
130 " -T time to send messages\n"
131 " -u use unordered user messages\n"
132 " -U remote UDP encapsulation port\n"
133 " -v verbose\n"
134 " -V very verbose\n"
135 ;
136
137 static void handle_upcall(struct socket *upcall_socket, void *upcall_data, int upcall_flags);
138
bytes2human(uint64_t bytes)139 static const char *bytes2human(uint64_t bytes)
140 {
141 char *suffix[] = {"", "K", "M", "G", "T"};
142 char suffix_length = sizeof(suffix) / sizeof(suffix[0]);
143 int i = 0;
144 double human_size = bytes;
145 static char output[200];
146
147 if (bytes > 1024) {
148 for (i = 0; (bytes / 1024) > 0 && i < suffix_length - 1; i++) {
149 human_size = bytes / 1024.0;
150 bytes /= 1024;
151 }
152 }
153
154 if (snprintf(output, sizeof(output), "%.02lf %s", human_size, suffix[i]) < 0) {
155 output[0] = '\0';
156 }
157 return output;
158 }
159
160
161 static void
handle_accept(struct socket * upcall_socket,void * upcall_data,int upcall_flags)162 handle_accept(struct socket *upcall_socket, void *upcall_data, int upcall_flags)
163 {
164 struct socket *conn_sock;
165 struct sockaddr_in remote_addr;
166 socklen_t addr_len = sizeof(struct sockaddr_in);
167 struct tsctp_meta *meta_listening, *meta_accepted;
168 char addrbuf[INET_ADDRSTRLEN];
169
170 meta_listening = (struct tsctp_meta *) upcall_data;
171
172 memset(&remote_addr, 0, sizeof(struct sockaddr_in));
173 if (((conn_sock = usrsctp_accept(upcall_socket, (struct sockaddr *) &remote_addr, &addr_len)) == NULL) && (errno != EINPROGRESS)) {
174 perror("usrsctp_accept");
175 exit(EXIT_FAILURE);
176 }
177
178 if (par_verbose) {
179 printf("Connection accepted from %s:%d\n", inet_ntop(AF_INET, &(remote_addr.sin_addr), addrbuf, INET_ADDRSTRLEN), ntohs(remote_addr.sin_port));
180 }
181
182 meta_accepted = malloc(sizeof(struct tsctp_meta));
183 if (!meta_accepted) {
184 printf("malloc() failed!\n");
185 exit(EXIT_FAILURE);
186 }
187
188 memset(meta_accepted, 0, sizeof(struct tsctp_meta));
189
190 meta_accepted->par_role = meta_listening->par_role;
191 meta_accepted->par_stats_human = meta_listening->par_stats_human;
192 meta_accepted->buffer = malloc(BUFFERSIZE);
193
194 if (!meta_accepted->buffer) {
195 printf("malloc() failed!\n");
196 exit(EXIT_FAILURE);
197 }
198
199 usrsctp_set_upcall(conn_sock, handle_upcall, meta_accepted);
200 }
201
202 static void
handle_upcall(struct socket * upcall_socket,void * upcall_data,int upcall_flags)203 handle_upcall(struct socket *upcall_socket, void *upcall_data, int upcall_flags)
204 {
205 int events = usrsctp_get_events(upcall_socket);
206 struct tsctp_meta* tsctp_meta = (struct tsctp_meta*) upcall_data;
207
208 struct sctp_recvv_rn rn;
209 ssize_t n;
210 struct sockaddr_storage addr;
211 int recv_flags = 0;
212 socklen_t len = (socklen_t)sizeof(struct sockaddr_storage);
213 unsigned int infotype = 0;
214 socklen_t infolen = sizeof(struct sctp_recvv_rn);
215 struct sctp_rcvinfo *rcvinfo = (struct sctp_rcvinfo *) &rn;
216 memset(&rn, 0, sizeof(struct sctp_recvv_rn));
217 struct timeval note_time;
218 union sctp_notification *snp;
219 struct sctp_paddr_change *spc;
220 struct timeval time_now;
221 struct timeval time_diff;
222 float seconds;
223 struct sctp_sndinfo snd_info;
224
225 if (events & SCTP_EVENT_READ) {
226 while ((n = usrsctp_recvv(upcall_socket, tsctp_meta->buffer, BUFFERSIZE, (struct sockaddr *) &addr, &len, (void *)&rn, &infolen, &infotype, &recv_flags)) > 0) {
227
228 if (!tsctp_meta->stat_recv_calls) {
229 gettimeofday(&tsctp_meta->stat_start, NULL);
230 }
231 tsctp_meta->stat_recv_calls++;
232
233 if (recv_flags & MSG_NOTIFICATION) {
234 tsctp_meta->stat_notifications++;
235 gettimeofday(¬e_time, NULL);
236 if (par_verbose) {
237 printf("notification arrived at %f\n", note_time.tv_sec + (double)note_time.tv_usec / 1000000.0);
238
239 snp = (union sctp_notification *)tsctp_meta->buffer;
240 if (snp->sn_header.sn_type == SCTP_PEER_ADDR_CHANGE) {
241 spc = &snp->sn_paddr_change;
242 printf("SCTP_PEER_ADDR_CHANGE: state=%d, error=%d\n",spc->spc_state, spc->spc_error);
243 }
244 }
245 } else {
246 if (par_very_verbose) {
247 if (infotype == SCTP_RECVV_RCVINFO) {
248 printf("Message received - %zd bytes - %s - sid %u - tsn %u %s\n",
249 n,
250 (rcvinfo->rcv_flags & SCTP_UNORDERED) ? "unordered" : "ordered",
251 rcvinfo->rcv_sid,
252 rcvinfo->rcv_tsn,
253 (recv_flags & MSG_EOR) ? "- EOR" : ""
254 );
255
256 } else {
257 printf("Message received - %zd bytes %s\n", n, (recv_flags & MSG_EOR) ? "- EOR" : "");
258 }
259 }
260 tsctp_meta->stat_fragment_sum += n;
261 if (recv_flags & MSG_EOR) {
262 tsctp_meta->stat_messages++;
263 if (tsctp_meta->stat_message_length == 0) {
264 tsctp_meta->stat_message_length = tsctp_meta->stat_fragment_sum;
265 }
266 }
267 }
268 }
269
270 if (n < 0 && errno != EAGAIN && errno != EWOULDBLOCK) {
271 perror("usrsctp_recvv");
272 exit(EXIT_FAILURE);
273 }
274
275 if (n == 0) {
276 done = 1;
277
278 gettimeofday(&time_now, NULL);
279 timersub(&time_now, &tsctp_meta->stat_start, &time_diff);
280 seconds = time_diff.tv_sec + (double)time_diff.tv_usec / 1000000.0;
281
282 if (tsctp_meta->par_stats_human) {
283 printf("Connection closed - statistics\n");
284
285 printf("\tmessage size : %" PRIu64 "\n", tsctp_meta->stat_message_length);
286 printf("\tmessages : %" PRIu64 "\n", tsctp_meta->stat_messages);
287 printf("\trecv() calls : %" PRIu64 "\n", tsctp_meta->stat_recv_calls);
288 printf("\tnotifications : %" PRIu64 "\n", tsctp_meta->stat_notifications);
289 printf("\ttransferred : %sByte\n", bytes2human(tsctp_meta->stat_message_length * tsctp_meta->stat_messages));
290 printf("\truntime : %.2f s\n", seconds);
291 printf("\tgoodput : %sBit/s\n", bytes2human((double) tsctp_meta->stat_message_length * (double) tsctp_meta->stat_messages / seconds * 8));
292
293 } else {
294 printf("%" PRIu64 ", %" PRIu64 ", %" PRIu64 ", %" PRIu64 ", %f, %f, %" PRIu64 "\n",
295 tsctp_meta->stat_message_length,
296 tsctp_meta->stat_messages,
297 tsctp_meta->stat_recv_calls,
298 tsctp_meta->stat_message_length * tsctp_meta->stat_messages,
299 seconds,
300 (double) tsctp_meta->stat_message_length * (double) tsctp_meta->stat_messages / seconds,
301 tsctp_meta->stat_notifications);
302 }
303 fflush(stdout);
304 usrsctp_close(upcall_socket);
305
306 free(tsctp_meta->buffer);
307 free(tsctp_meta);
308 return;
309 }
310 }
311
312 if ((events & SCTP_EVENT_WRITE) && tsctp_meta->par_role == TSCTP_CLIENT && !done) {
313
314 memset(&snd_info, 0, sizeof(struct sctp_sndinfo));
315 if (tsctp_meta->par_ordered == 0) {
316 snd_info.snd_flags |= SCTP_UNORDERED;
317 }
318
319 while ((n = usrsctp_sendv(upcall_socket, tsctp_meta->buffer, tsctp_meta->par_message_length, NULL, 0, &snd_info, (socklen_t)sizeof(struct sctp_sndinfo), SCTP_SENDV_SNDINFO, 0)) > 0) {
320 if (tsctp_meta->stat_messages == 0) {
321 gettimeofday(&tsctp_meta->stat_start, NULL);
322 }
323 tsctp_meta->stat_messages++;
324
325 if (par_very_verbose) {
326 printf("Message #%" PRIu64 " sent\n", tsctp_meta->stat_messages);
327 }
328
329 if (tsctp_meta->par_messages && tsctp_meta->par_messages == tsctp_meta->stat_messages) {
330 break;
331 }
332 }
333
334 if (errno != EAGAIN && errno != EWOULDBLOCK) {
335 done = 1;
336 usrsctp_close(upcall_socket);
337 printf("client socket %p closed\n", (void *)upcall_socket);
338 free(tsctp_meta->buffer);
339 free(tsctp_meta);
340 return;
341 }
342
343 gettimeofday(&time_now, NULL);
344 timersub(&time_now, &tsctp_meta->stat_start, &time_diff);
345 seconds = time_diff.tv_sec + (double)time_diff.tv_usec / 1000000.0;
346
347 if ((tsctp_meta->par_messages && tsctp_meta->par_messages == tsctp_meta->stat_messages) ||
348 (tsctp_meta->par_runtime && tsctp_meta->par_runtime <= seconds)) {
349
350 if (par_verbose) {
351 printf("Runtime or max messages reached - finishing...\n");
352 }
353
354 done = 1;
355 usrsctp_close(upcall_socket);
356 free(tsctp_meta->buffer);
357 free(tsctp_meta);
358 return;
359 }
360 }
361
362 return;
363 }
364
main(int argc,char ** argv)365 int main(int argc, char **argv)
366 {
367 #ifndef _WIN32
368 int c;
369 #endif
370 struct socket *psock = NULL;
371 struct sockaddr_in local_addr;
372 struct sockaddr_in remote_addr;
373 int optval;
374 uint16_t local_port;
375 uint16_t remote_port;
376 uint16_t local_udp_port;
377 uint16_t remote_udp_port;
378 int rcvbufsize = 0;
379 int sndbufsize = 0;
380 socklen_t intlen;
381 int nodelay = 0;
382 struct sctp_assoc_value av;
383 struct sctp_udpencaps encaps;
384 struct tsctp_meta *meta;
385
386 uint16_t par_port = DEFAULT_PORT;
387 uint8_t par_stats_human = 0;
388 int par_ordered = 1;
389 int par_message_length = DEFAULT_LENGTH;
390 int par_messages = DEFAULT_NUMBER_OF_MESSAGES;
391 int par_runtime = 0;
392
393 #ifdef _WIN32
394 unsigned long src_addr;
395 #else
396 in_addr_t src_addr;
397 #endif
398 int fragpoint = 0;
399 struct sctp_setadaptation ind = {0};
400 #ifdef _WIN32
401 char *opt;
402 int optind;
403 #endif
404
405 remote_udp_port = 0;
406 local_udp_port = 9899;
407 src_addr = htonl(INADDR_ANY);
408
409 memset((void *) &remote_addr, 0, sizeof(struct sockaddr_in));
410 memset((void *) &local_addr, 0, sizeof(struct sockaddr_in));
411
412 #ifndef _WIN32
413 while ((c = getopt(argc, argv, "a:DE:f:Hl:L:n:p:R:S:T:uU:vV")) != -1)
414 switch(c) {
415 case 'a':
416 ind.ssb_adaptation_ind = atoi(optarg);
417 break;
418 case 'D':
419 nodelay = 1;
420 break;
421 case 'E':
422 local_udp_port = atoi(optarg);
423 break;
424 case 'f':
425 fragpoint = atoi(optarg);
426 break;
427 case 'H':
428 par_stats_human = 1;
429 break;
430 case 'l':
431 par_message_length = atoi(optarg);
432 break;
433 case 'L':
434 if (inet_pton(AF_INET, optarg, &src_addr) != 1) {
435 printf("Can't parse %s\n", optarg);
436 exit(EXIT_FAILURE);
437 }
438 break;
439 case 'n':
440 par_messages = atoi(optarg);
441 break;
442 case 'p':
443 par_port = atoi(optarg);
444 break;
445 case 'R':
446 rcvbufsize = atoi(optarg);
447 break;
448 case 'S':
449 sndbufsize = atoi(optarg);
450 break;
451 case 'T':
452 par_runtime = atoi(optarg);
453 par_messages = 0;
454 break;
455 case 'u':
456 par_ordered = 0;
457 break;
458 case 'U':
459 remote_udp_port = atoi(optarg);
460 break;
461 case 'v':
462 par_verbose = 1;
463 break;
464 case 'V':
465 par_verbose = 1;
466 par_very_verbose = 1;
467 break;
468 default:
469 fprintf(stderr, "%s", Usage);
470 exit(1);
471 }
472 #else
473 for (optind = 1; optind < argc; optind++) {
474 if (argv[optind][0] == '-') {
475 switch (argv[optind][1]) {
476 case 'a':
477 if (++optind >= argc) {
478 printf("%s", Usage);
479 exit(1);
480 }
481 opt = argv[optind];
482 ind.ssb_adaptation_ind = atoi(opt);
483 break;
484 case 'D':
485 nodelay = 1;
486 break;
487 case 'E':
488 if (++optind >= argc) {
489 printf("%s", Usage);
490 exit(1);
491 }
492 opt = argv[optind];
493 local_udp_port = atoi(opt);
494 break;
495 case 'f':
496 if (++optind >= argc) {
497 printf("%s", Usage);
498 exit(1);
499 }
500 opt = argv[optind];
501 fragpoint = atoi(opt);
502 break;
503 case 'H':
504 par_stats_human = 1;
505 break;
506 case 'l':
507 if (++optind >= argc) {
508 printf("%s", Usage);
509 exit(1);
510 }
511 opt = argv[optind];
512 par_message_length = atoi(opt);
513 break;
514 case 'L':
515 if (++optind >= argc) {
516 printf("%s", Usage);
517 exit(1);
518 }
519 opt = argv[optind];
520 inet_pton(AF_INET, opt, &src_addr);
521 break;
522 case 'n':
523 if (++optind >= argc) {
524 printf("%s", Usage);
525 exit(1);
526 }
527 opt = argv[optind];
528 par_messages = atoi(opt);
529 break;
530 case 'p':
531 if (++optind >= argc) {
532 printf("%s", Usage);
533 exit(1);
534 }
535 opt = argv[optind];
536 par_port = atoi(opt);
537 break;
538 case 'R':
539 if (++optind >= argc) {
540 printf("%s", Usage);
541 exit(1);
542 }
543 opt = argv[optind];
544 rcvbufsize = atoi(opt);
545 break;
546 case 'S':
547 if (++optind >= argc) {
548 printf("%s", Usage);
549 exit(1);
550 }
551 opt = argv[optind];
552 sndbufsize = atoi(opt);
553 break;
554 case 'T':
555 if (++optind >= argc) {
556 printf("%s", Usage);
557 exit(1);
558 }
559 opt = argv[optind];
560 par_runtime = atoi(opt);
561 par_messages = 0;
562 break;
563 case 'u':
564 par_ordered = 0;
565 break;
566 case 'U':
567 if (++optind >= argc) {
568 printf("%s", Usage);
569 exit(1);
570 }
571 opt = argv[optind];
572 remote_udp_port = atoi(opt);
573 break;
574 case 'v':
575 par_verbose = 1;
576 break;
577 case 'V':
578 par_verbose = 1;
579 par_very_verbose = 1;
580 break;
581 default:
582 printf("%s", Usage);
583 exit(1);
584 }
585 } else {
586 break;
587 }
588 }
589 #endif
590
591 meta = malloc(sizeof(struct tsctp_meta));
592 if (!meta) {
593 printf("malloc() failed!\n");
594 exit(EXIT_FAILURE);
595 }
596
597 memset(meta, 0, sizeof(struct tsctp_meta));
598
599 meta->buffer = malloc(BUFFERSIZE);
600 if (!meta->buffer) {
601 printf("malloc() failed!\n");
602 exit(EXIT_FAILURE);
603 }
604
605 meta->par_stats_human = par_stats_human;
606 meta->par_message_length = par_message_length;
607 meta->par_messages = par_messages;
608 meta->par_ordered = par_ordered;
609 meta->par_runtime = par_runtime;
610
611 if (optind == argc) {
612 meta->par_role = TSCTP_SERVER;
613 local_port = par_port;
614 remote_port = 0;
615 } else {
616 meta->par_role = TSCTP_CLIENT;
617 local_port = 0;
618 remote_port = par_port;
619 }
620 local_addr.sin_family = AF_INET;
621 #ifdef HAVE_SIN_LEN
622 local_addr.sin_len = sizeof(struct sockaddr_in);
623 #endif
624 local_addr.sin_port = htons(local_port);
625 local_addr.sin_addr.s_addr = src_addr;
626
627 usrsctp_init(local_udp_port, NULL, debug_printf_stack);
628 #ifdef SCTP_DEBUG
629 usrsctp_sysctl_set_sctp_debug_on(SCTP_DEBUG_ALL);
630 #endif
631 usrsctp_sysctl_set_sctp_blackhole(2);
632 usrsctp_sysctl_set_sctp_no_csum_on_loopback(0);
633 usrsctp_sysctl_set_sctp_enable_sack_immediately(1);
634
635 if (!(psock = usrsctp_socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP, NULL, NULL, 0, NULL))) {
636 perror("user_socket");
637 exit(EXIT_FAILURE);
638 }
639
640 optval = 1;
641 if (usrsctp_setsockopt(psock, IPPROTO_SCTP, SCTP_RECVRCVINFO, &optval, sizeof(optval)) < 0) {
642 perror("usrsctp_setsockopt SCTP_RECVRCVINFO");
643 }
644
645 usrsctp_set_non_blocking(psock, 1);
646
647 if (usrsctp_bind(psock, (struct sockaddr *) &local_addr, sizeof(struct sockaddr_in)) == -1) {
648 perror("usrsctp_bind");
649 exit(1);
650 }
651
652 if (usrsctp_setsockopt(psock, IPPROTO_SCTP, SCTP_ADAPTATION_LAYER, (const void*)&ind, (socklen_t)sizeof(struct sctp_setadaptation)) < 0) {
653 perror("setsockopt");
654 }
655
656 if (meta->par_role == TSCTP_SERVER) {
657 if (rcvbufsize) {
658 if (usrsctp_setsockopt(psock, SOL_SOCKET, SO_RCVBUF, &rcvbufsize, sizeof(int)) < 0) {
659 perror("setsockopt: rcvbuf");
660 }
661 }
662 if (par_verbose) {
663 intlen = sizeof(int);
664 if (usrsctp_getsockopt(psock, SOL_SOCKET, SO_RCVBUF, &rcvbufsize, (socklen_t *)&intlen) < 0) {
665 perror("getsockopt: rcvbuf");
666 } else {
667 fprintf(stdout, "Receive buffer size: %d.\n", rcvbufsize);
668 }
669 }
670
671 if (usrsctp_listen(psock, 1) < 0) {
672 perror("usrsctp_listen");
673 exit(EXIT_FAILURE);
674 }
675
676 usrsctp_set_upcall(psock, handle_accept, meta);
677
678 while (1) {
679 #ifdef _WIN32
680 Sleep(1000);
681 #else
682 sleep(1);
683 #endif
684 }
685
686 } else {
687 memset(&encaps, 0, sizeof(struct sctp_udpencaps));
688 encaps.sue_address.ss_family = AF_INET;
689 encaps.sue_port = htons(remote_udp_port);
690 if (usrsctp_setsockopt(psock, IPPROTO_SCTP, SCTP_REMOTE_UDP_ENCAPS_PORT, (const void*)&encaps, (socklen_t)sizeof(struct sctp_udpencaps)) < 0) {
691 perror("setsockopt");
692 }
693
694 remote_addr.sin_family = AF_INET;
695 #ifdef HAVE_SIN_LEN
696 remote_addr.sin_len = sizeof(struct sockaddr_in);
697 #endif
698 if (!inet_pton(AF_INET, argv[optind], &remote_addr.sin_addr.s_addr)){
699 printf("error: invalid destination address\n");
700 exit(EXIT_FAILURE);
701 }
702 remote_addr.sin_port = htons(remote_port);
703
704 memset(meta->buffer, 'X', BUFFERSIZE);
705
706 usrsctp_set_upcall(psock, handle_upcall, meta);
707
708 usrsctp_setsockopt(psock, IPPROTO_SCTP, SCTP_NODELAY, &nodelay, sizeof(nodelay));
709
710 if (fragpoint) {
711 av.assoc_id = 0;
712 av.assoc_value = fragpoint;
713 if (usrsctp_setsockopt(psock, IPPROTO_SCTP, SCTP_MAXSEG, &av, sizeof(struct sctp_assoc_value)) < 0) {
714 perror("setsockopt: SCTP_MAXSEG");
715 }
716 }
717
718 if (sndbufsize) {
719 if (usrsctp_setsockopt(psock, SOL_SOCKET, SO_SNDBUF, &sndbufsize, sizeof(int)) < 0) {
720 perror("setsockopt: sndbuf");
721 }
722 }
723
724 if (par_verbose) {
725 intlen = sizeof(int);
726 if (usrsctp_getsockopt(psock, SOL_SOCKET, SO_SNDBUF, &sndbufsize, (socklen_t *)&intlen) < 0) {
727 perror("setsockopt: SO_SNDBUF");
728 } else {
729 fprintf(stdout,"Send buffer size: %d.\n", sndbufsize);
730 }
731 }
732
733 if (usrsctp_connect(psock, (struct sockaddr *) &remote_addr, sizeof(struct sockaddr_in)) == -1 ) {
734 if (errno != EINPROGRESS) {
735 perror("usrsctp_connect");
736 exit(EXIT_FAILURE);
737 }
738 }
739
740 while (!done) {
741 #ifdef _WIN32
742 Sleep(1000);
743 #else
744 sleep(1);
745 #endif
746 }
747
748 if (par_verbose) {
749 printf("Finished... \n");
750 }
751 }
752
753 while (usrsctp_finish() != 0) {
754 #ifdef _WIN32
755 Sleep(1000);
756 #else
757 sleep(1);
758 #endif
759 }
760
761 return 0;
762 }
763