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