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