You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
817 lines
21 KiB
817 lines
21 KiB
/*
|
|
* Copyright (C) 2005-2013 Michael Tuexen
|
|
* Copyright (C) 2011-2013 Irene Ruengeler
|
|
*
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. Neither the name of the project nor the names of its contributors
|
|
* may be used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <sys/types.h>
|
|
#ifdef _WIN32
|
|
#include <winsock2.h>
|
|
#include <ws2tcpip.h>
|
|
#include <stdlib.h>
|
|
#include <crtdbg.h>
|
|
#include <sys/timeb.h>
|
|
#else
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
#include <sys/time.h>
|
|
#include <unistd.h>
|
|
#include <pthread.h>
|
|
#endif
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <signal.h>
|
|
#include <errno.h>
|
|
#ifdef LINUX
|
|
#include <getopt.h>
|
|
#endif
|
|
#include <usrsctp.h>
|
|
#include "programs_helper.h"
|
|
|
|
/* global for the send callback, but used in kernel version as well */
|
|
static unsigned long number_of_messages;
|
|
static char *buffer;
|
|
static int length;
|
|
static struct sockaddr_in remote_addr;
|
|
static int unordered;
|
|
uint32_t optval = 1;
|
|
struct socket *psock = NULL;
|
|
|
|
static struct timeval start_time;
|
|
unsigned int runtime = 0;
|
|
static unsigned long cb_messages = 0;
|
|
static unsigned long long cb_first_length = 0;
|
|
static unsigned long long cb_sum = 0;
|
|
static unsigned int use_cb = 0;
|
|
|
|
#ifdef _WIN32
|
|
static void
|
|
gettimeofday(struct timeval *tv, void *ignore)
|
|
{
|
|
struct timeb tb;
|
|
|
|
ftime(&tb);
|
|
tv->tv_sec = (long)tb.time;
|
|
tv->tv_usec = tb.millitm * 1000;
|
|
}
|
|
#endif
|
|
|
|
|
|
char Usage[] =
|
|
"Usage: tsctp [options] [address]\n"
|
|
"Options:\n"
|
|
" -a set adaptation layer indication\n"
|
|
" -c use callback API\n"
|
|
" -E local UDP encapsulation port (default 9899)\n"
|
|
" -f fragmentation point\n"
|
|
" -l message length\n"
|
|
" -L bind to local IP (default INADDR_ANY)\n"
|
|
" -n number of messages sent (0 means infinite)/received\n"
|
|
" -D turns Nagle off\n"
|
|
" -R socket recv buffer\n"
|
|
" -S socket send buffer\n"
|
|
" -T time to send messages\n"
|
|
" -u use unordered user messages\n"
|
|
" -U remote UDP encapsulation port\n"
|
|
" -v verbose\n"
|
|
" -V very verbose\n"
|
|
;
|
|
|
|
#define DEFAULT_LENGTH 1024
|
|
#define DEFAULT_NUMBER_OF_MESSAGES 1024
|
|
#define DEFAULT_PORT 5001
|
|
#define BUFFERSIZE (1<<16)
|
|
|
|
static int verbose, very_verbose;
|
|
static unsigned int done;
|
|
|
|
void stop_sender(int sig)
|
|
{
|
|
done = 1;
|
|
}
|
|
|
|
#ifdef _WIN32
|
|
static DWORD WINAPI
|
|
#else
|
|
static void *
|
|
#endif
|
|
handle_connection(void *arg)
|
|
{
|
|
ssize_t n;
|
|
char *buf;
|
|
|
|
#if !defined(_WIN32)
|
|
pthread_t tid;
|
|
#endif
|
|
struct socket *conn_sock;
|
|
struct timeval time_start, time_now, time_diff;
|
|
double seconds;
|
|
unsigned long recv_calls = 0;
|
|
unsigned long notifications = 0;
|
|
int flags;
|
|
struct sockaddr_in addr;
|
|
socklen_t len;
|
|
union sctp_notification *snp;
|
|
struct sctp_paddr_change *spc;
|
|
struct timeval note_time;
|
|
unsigned int infotype;
|
|
struct sctp_recvv_rn rn;
|
|
socklen_t infolen = sizeof(struct sctp_recvv_rn);
|
|
unsigned long messages = 0;
|
|
unsigned long long first_length = 0;
|
|
unsigned long long sum = 0;
|
|
|
|
conn_sock = *(struct socket **)arg;
|
|
|
|
#if !defined(_WIN32)
|
|
tid = pthread_self();
|
|
pthread_detach(tid);
|
|
#endif
|
|
|
|
buf = malloc(BUFFERSIZE);
|
|
flags = 0;
|
|
len = (socklen_t)sizeof(struct sockaddr_in);
|
|
infotype = 0;
|
|
memset(&rn, 0, sizeof(struct sctp_recvv_rn));
|
|
n = usrsctp_recvv(conn_sock, buf, BUFFERSIZE, (struct sockaddr *) &addr, &len, (void *)&rn,
|
|
&infolen, &infotype, &flags);
|
|
|
|
gettimeofday(&time_start, NULL);
|
|
while (n > 0) {
|
|
recv_calls++;
|
|
if (flags & MSG_NOTIFICATION) {
|
|
notifications++;
|
|
gettimeofday(¬e_time, NULL);
|
|
printf("notification arrived at %f\n", note_time.tv_sec+(double)note_time.tv_usec/1000000.0);
|
|
snp = (union sctp_notification *)buf;
|
|
if (snp->sn_header.sn_type == SCTP_PEER_ADDR_CHANGE) {
|
|
spc = &snp->sn_paddr_change;
|
|
printf("SCTP_PEER_ADDR_CHANGE: state=%d, error=%d\n",spc->spc_state, spc->spc_error);
|
|
}
|
|
} else {
|
|
if (very_verbose) {
|
|
printf("Message received\n");
|
|
}
|
|
sum += n;
|
|
if (flags & MSG_EOR) {
|
|
messages++;
|
|
if (first_length == 0) {
|
|
first_length = sum;
|
|
}
|
|
}
|
|
}
|
|
flags = 0;
|
|
len = (socklen_t)sizeof(struct sockaddr_in);
|
|
infolen = sizeof(struct sctp_recvv_rn);
|
|
infotype = 0;
|
|
memset(&rn, 0, sizeof(struct sctp_recvv_rn));
|
|
n = usrsctp_recvv(conn_sock, (void *) buf, BUFFERSIZE, (struct sockaddr *) &addr, &len, (void *)&rn,
|
|
&infolen, &infotype, &flags);
|
|
}
|
|
if (n < 0) {
|
|
perror("sctp_recvv");
|
|
}
|
|
gettimeofday(&time_now, NULL);
|
|
timersub(&time_now, &time_start, &time_diff);
|
|
seconds = time_diff.tv_sec + (double)time_diff.tv_usec/1000000.0;
|
|
printf("%llu, %lu, %lu, %llu, %f, %f, %lu\n",
|
|
first_length, messages, recv_calls, sum, seconds, (double)first_length * (double)messages / seconds, notifications);
|
|
fflush(stdout);
|
|
usrsctp_close(conn_sock);
|
|
free(buf);
|
|
#ifdef _WIN32
|
|
return 0;
|
|
#else
|
|
return (NULL);
|
|
#endif
|
|
}
|
|
|
|
static int
|
|
send_cb(struct socket *sock, uint32_t sb_free) {
|
|
struct sctp_sndinfo sndinfo;
|
|
|
|
if ((cb_messages == 0) && verbose) {
|
|
printf("Start sending ");
|
|
if (number_of_messages > 0) {
|
|
printf("%ld messages ", (long)number_of_messages);
|
|
}
|
|
if (runtime > 0) {
|
|
printf("for %u seconds ...", runtime);
|
|
}
|
|
printf("\n");
|
|
fflush(stdout);
|
|
}
|
|
|
|
sndinfo.snd_sid = 0;
|
|
sndinfo.snd_flags = 0;
|
|
if (unordered != 0) {
|
|
sndinfo.snd_flags |= SCTP_UNORDERED;
|
|
}
|
|
sndinfo.snd_ppid = 0;
|
|
sndinfo.snd_context = 0;
|
|
sndinfo.snd_assoc_id = 0;
|
|
|
|
while (!done && ((number_of_messages == 0) || (cb_messages < (number_of_messages - 1)))) {
|
|
if (very_verbose) {
|
|
printf("Sending message number %lu.\n", cb_messages + 1);
|
|
}
|
|
|
|
if (usrsctp_sendv(psock, buffer, length,
|
|
(struct sockaddr *) &remote_addr, 1,
|
|
(void *)&sndinfo, (socklen_t)sizeof(struct sctp_sndinfo), SCTP_SENDV_SNDINFO,
|
|
0) < 0) {
|
|
if (errno != EWOULDBLOCK && errno != EAGAIN) {
|
|
perror("usrsctp_sendv (cb)");
|
|
exit(1);
|
|
} else {
|
|
if (very_verbose){
|
|
printf("EWOULDBLOCK or EAGAIN for message number %lu - will retry\n", cb_messages + 1);
|
|
}
|
|
/* send until EWOULDBLOCK then exit callback. */
|
|
return (1);
|
|
}
|
|
}
|
|
cb_messages++;
|
|
}
|
|
if ((done == 1) || (cb_messages == (number_of_messages - 1))) {
|
|
if (very_verbose) {
|
|
printf("Sending final message number %lu.\n", cb_messages + 1);
|
|
}
|
|
|
|
sndinfo.snd_flags |= SCTP_EOF;
|
|
if (usrsctp_sendv(psock, buffer, length, (struct sockaddr *) &remote_addr, 1,
|
|
(void *)&sndinfo, (socklen_t)sizeof(struct sctp_sndinfo), SCTP_SENDV_SNDINFO,
|
|
0) < 0) {
|
|
if (errno != EWOULDBLOCK && errno != EAGAIN) {
|
|
perror("usrsctp_sendv (cb)");
|
|
exit(1);
|
|
} else {
|
|
if (very_verbose){
|
|
printf("EWOULDBLOCK or EAGAIN for final message number %lu - will retry\n", cb_messages + 1);
|
|
}
|
|
/* send until EWOULDBLOCK then exit callback. */
|
|
return (1);
|
|
}
|
|
}
|
|
cb_messages++;
|
|
done = 2;
|
|
}
|
|
|
|
return (1);
|
|
}
|
|
|
|
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)
|
|
{
|
|
struct timeval now, diff_time;
|
|
double seconds;
|
|
|
|
if (data == NULL) {
|
|
gettimeofday(&now, NULL);
|
|
timersub(&now, &start_time, &diff_time);
|
|
seconds = diff_time.tv_sec + (double)diff_time.tv_usec / 1000000.0;
|
|
printf("%llu, %lu, %llu, %f, %f\n",
|
|
cb_first_length, cb_messages, cb_sum, seconds, (double)cb_first_length * (double)cb_messages / seconds);
|
|
usrsctp_close(sock);
|
|
cb_first_length = 0;
|
|
cb_sum = 0;
|
|
cb_messages = 0;
|
|
return (1);
|
|
}
|
|
if (cb_first_length == 0) {
|
|
cb_first_length = (unsigned int)datalen;
|
|
gettimeofday(&start_time, NULL);
|
|
}
|
|
cb_sum += datalen;
|
|
cb_messages++;
|
|
|
|
free(data);
|
|
return (1);
|
|
}
|
|
|
|
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)
|
|
{
|
|
free(data);
|
|
return (1);
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
#ifndef _WIN32
|
|
int c, rc;
|
|
#endif
|
|
socklen_t addr_len;
|
|
struct sockaddr_in local_addr;
|
|
struct timeval time_start, time_now, time_diff;
|
|
int client;
|
|
uint16_t local_port, remote_port, port, local_udp_port, remote_udp_port;
|
|
int rcvbufsize=0, sndbufsize=0, myrcvbufsize, mysndbufsize;
|
|
socklen_t intlen;
|
|
double seconds;
|
|
double throughput;
|
|
int nodelay = 0;
|
|
struct sctp_assoc_value av;
|
|
struct sctp_udpencaps encaps;
|
|
struct sctp_sndinfo sndinfo;
|
|
unsigned long messages = 0;
|
|
#ifdef _WIN32
|
|
unsigned long srcAddr;
|
|
HANDLE tid;
|
|
#else
|
|
in_addr_t srcAddr;
|
|
pthread_t tid;
|
|
#endif
|
|
int fragpoint = 0;
|
|
struct sctp_setadaptation ind = {0};
|
|
#ifdef _WIN32
|
|
char *opt;
|
|
int optind;
|
|
#endif
|
|
unordered = 0;
|
|
|
|
length = DEFAULT_LENGTH;
|
|
number_of_messages = DEFAULT_NUMBER_OF_MESSAGES;
|
|
port = DEFAULT_PORT;
|
|
remote_udp_port = 0;
|
|
local_udp_port = 9899;
|
|
verbose = 0;
|
|
very_verbose = 0;
|
|
srcAddr = htonl(INADDR_ANY);
|
|
|
|
memset((void *) &remote_addr, 0, sizeof(struct sockaddr_in));
|
|
memset((void *) &local_addr, 0, sizeof(struct sockaddr_in));
|
|
|
|
#ifndef _WIN32
|
|
while ((c = getopt(argc, argv, "a:cp:l:E:f:L:n:R:S:T:uU:vVD")) != -1)
|
|
switch(c) {
|
|
case 'a':
|
|
ind.ssb_adaptation_ind = atoi(optarg);
|
|
break;
|
|
case 'c':
|
|
use_cb = 1;
|
|
break;
|
|
case 'l':
|
|
length = atoi(optarg);
|
|
break;
|
|
case 'n':
|
|
number_of_messages = atoi(optarg);
|
|
break;
|
|
case 'p':
|
|
port = atoi(optarg);
|
|
break;
|
|
case 'E':
|
|
local_udp_port = atoi(optarg);
|
|
break;
|
|
case 'f':
|
|
fragpoint = atoi(optarg);
|
|
break;
|
|
case 'L':
|
|
if (inet_pton(AF_INET, optarg, &srcAddr) != 1) {
|
|
printf("Can't parse %s\n", optarg);
|
|
}
|
|
break;
|
|
case 'R':
|
|
rcvbufsize = atoi(optarg);
|
|
break;
|
|
case 'S':
|
|
sndbufsize = atoi(optarg);
|
|
break;
|
|
case 'T':
|
|
runtime = atoi(optarg);
|
|
number_of_messages = 0;
|
|
break;
|
|
case 'u':
|
|
unordered = 1;
|
|
break;
|
|
case 'U':
|
|
remote_udp_port = atoi(optarg);
|
|
break;
|
|
case 'v':
|
|
verbose = 1;
|
|
break;
|
|
case 'V':
|
|
verbose = 1;
|
|
very_verbose = 1;
|
|
break;
|
|
case 'D':
|
|
nodelay = 1;
|
|
break;
|
|
default:
|
|
fprintf(stderr, "%s", Usage);
|
|
exit(1);
|
|
}
|
|
#else
|
|
for (optind = 1; optind < argc; optind++) {
|
|
if (argv[optind][0] == '-') {
|
|
switch (argv[optind][1]) {
|
|
case 'a':
|
|
if (++optind >= argc) {
|
|
printf("%s", Usage);
|
|
exit(1);
|
|
}
|
|
opt = argv[optind];
|
|
ind.ssb_adaptation_ind = atoi(opt);
|
|
break;
|
|
case 'c':
|
|
use_cb = 1;
|
|
break;
|
|
case 'l':
|
|
if (++optind >= argc) {
|
|
printf("%s", Usage);
|
|
exit(1);
|
|
}
|
|
opt = argv[optind];
|
|
length = atoi(opt);
|
|
break;
|
|
case 'p':
|
|
if (++optind >= argc) {
|
|
printf("%s", Usage);
|
|
exit(1);
|
|
}
|
|
opt = argv[optind];
|
|
port = atoi(opt);
|
|
break;
|
|
case 'n':
|
|
if (++optind >= argc) {
|
|
printf("%s", Usage);
|
|
exit(1);
|
|
}
|
|
opt = argv[optind];
|
|
number_of_messages = atoi(opt);
|
|
break;
|
|
case 'f':
|
|
if (++optind >= argc) {
|
|
printf("%s", Usage);
|
|
exit(1);
|
|
}
|
|
opt = argv[optind];
|
|
fragpoint = atoi(opt);
|
|
break;
|
|
case 'L':
|
|
if (++optind >= argc) {
|
|
printf("%s", Usage);
|
|
exit(1);
|
|
}
|
|
opt = argv[optind];
|
|
inet_pton(AF_INET, opt, &srcAddr);
|
|
break;
|
|
case 'U':
|
|
if (++optind >= argc) {
|
|
printf("%s", Usage);
|
|
exit(1);
|
|
}
|
|
opt = argv[optind];
|
|
remote_udp_port = atoi(opt);
|
|
break;
|
|
case 'E':
|
|
if (++optind >= argc) {
|
|
printf("%s", Usage);
|
|
exit(1);
|
|
}
|
|
opt = argv[optind];
|
|
local_udp_port = atoi(opt);
|
|
break;
|
|
case 'R':
|
|
if (++optind >= argc) {
|
|
printf("%s", Usage);
|
|
exit(1);
|
|
}
|
|
opt = argv[optind];
|
|
rcvbufsize = atoi(opt);
|
|
break;
|
|
case 'S':
|
|
if (++optind >= argc) {
|
|
printf("%s", Usage);
|
|
exit(1);
|
|
}
|
|
opt = argv[optind];
|
|
sndbufsize = atoi(opt);
|
|
break;
|
|
case 'T':
|
|
if (++optind >= argc) {
|
|
printf("%s", Usage);
|
|
exit(1);
|
|
}
|
|
opt = argv[optind];
|
|
runtime = atoi(opt);
|
|
number_of_messages = 0;
|
|
break;
|
|
case 'u':
|
|
unordered = 1;
|
|
break;
|
|
case 'v':
|
|
verbose = 1;
|
|
break;
|
|
case 'V':
|
|
verbose = 1;
|
|
very_verbose = 1;
|
|
break;
|
|
case 'D':
|
|
nodelay = 1;
|
|
break;
|
|
default:
|
|
printf("%s", Usage);
|
|
exit(1);
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
if (optind == argc) {
|
|
client = 0;
|
|
local_port = port;
|
|
remote_port = 0;
|
|
} else {
|
|
client = 1;
|
|
local_port = 0;
|
|
remote_port = port;
|
|
}
|
|
local_addr.sin_family = AF_INET;
|
|
#ifdef HAVE_SIN_LEN
|
|
local_addr.sin_len = sizeof(struct sockaddr_in);
|
|
#endif
|
|
local_addr.sin_port = htons(local_port);
|
|
local_addr.sin_addr.s_addr = srcAddr;
|
|
|
|
usrsctp_init(local_udp_port, NULL, debug_printf_stack);
|
|
#ifdef SCTP_DEBUG
|
|
usrsctp_sysctl_set_sctp_debug_on(SCTP_DEBUG_ALL);
|
|
#endif
|
|
usrsctp_sysctl_set_sctp_blackhole(2);
|
|
usrsctp_sysctl_set_sctp_no_csum_on_loopback(0);
|
|
usrsctp_sysctl_set_sctp_enable_sack_immediately(1);
|
|
|
|
if (client) {
|
|
if (use_cb) {
|
|
if (!(psock = usrsctp_socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP, client_receive_cb, send_cb, length, NULL))) {
|
|
perror("user_socket");
|
|
exit(1);
|
|
}
|
|
} else {
|
|
if (!(psock = usrsctp_socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP, NULL, NULL, 0, NULL))) {
|
|
perror("user_socket");
|
|
exit(1);
|
|
}
|
|
}
|
|
} else {
|
|
if (use_cb) {
|
|
if (!(psock = usrsctp_socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP, server_receive_cb, NULL, 0, NULL))) {
|
|
perror("user_socket");
|
|
exit(1);
|
|
}
|
|
} else {
|
|
if (!(psock = usrsctp_socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP, NULL, NULL, 0, NULL))) {
|
|
perror("user_socket");
|
|
exit(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (usrsctp_bind(psock, (struct sockaddr *)&local_addr, sizeof(struct sockaddr_in)) == -1) {
|
|
perror("usrsctp_bind");
|
|
exit(1);
|
|
}
|
|
|
|
if (usrsctp_setsockopt(psock, IPPROTO_SCTP, SCTP_ADAPTATION_LAYER, (const void*)&ind, (socklen_t)sizeof(struct sctp_setadaptation)) < 0) {
|
|
perror("setsockopt");
|
|
}
|
|
|
|
if (!client) {
|
|
if (rcvbufsize) {
|
|
if (usrsctp_setsockopt(psock, SOL_SOCKET, SO_RCVBUF, &rcvbufsize, sizeof(int)) < 0) {
|
|
perror("setsockopt: rcvbuf");
|
|
}
|
|
}
|
|
if (verbose) {
|
|
intlen = sizeof(int);
|
|
if (usrsctp_getsockopt(psock, SOL_SOCKET, SO_RCVBUF, &myrcvbufsize, (socklen_t *)&intlen) < 0) {
|
|
perror("getsockopt: rcvbuf");
|
|
} else {
|
|
fprintf(stdout,"Receive buffer size: %d.\n", myrcvbufsize);
|
|
}
|
|
}
|
|
|
|
if (usrsctp_listen(psock, 1) < 0) {
|
|
perror("usrsctp_listen");
|
|
exit(1);
|
|
}
|
|
|
|
while (1) {
|
|
memset(&remote_addr, 0, sizeof(struct sockaddr_in));
|
|
addr_len = sizeof(struct sockaddr_in);
|
|
if (use_cb) {
|
|
struct socket *conn_sock;
|
|
|
|
if ((conn_sock = usrsctp_accept(psock, (struct sockaddr *) &remote_addr, &addr_len)) == NULL) {
|
|
perror("usrsctp_accept");
|
|
continue;
|
|
}
|
|
} else {
|
|
struct socket **conn_sock;
|
|
|
|
conn_sock = (struct socket **) malloc(sizeof(struct socket *));
|
|
if ((*conn_sock = usrsctp_accept(psock, (struct sockaddr *) &remote_addr, &addr_len)) == NULL) {
|
|
perror("usrsctp_accept");
|
|
continue;
|
|
}
|
|
#ifdef _WIN32
|
|
if ((tid = CreateThread(NULL, 0, &handle_connection, (void *)conn_sock, 0, NULL)) == NULL) {
|
|
fprintf(stderr, "CreateThread() failed with error: %d\n", GetLastError());
|
|
#else
|
|
if ((rc = pthread_create(&tid, NULL, &handle_connection, (void *)conn_sock)) != 0) {
|
|
fprintf(stderr, "pthread_create: %s\n", strerror(rc));
|
|
#endif
|
|
usrsctp_close(*conn_sock);
|
|
continue;
|
|
}
|
|
}
|
|
if (verbose) {
|
|
/* const char *inet_ntop(int af, const void *src, char *dst, socklen_t size)
|
|
inet_ntoa(remote_addr.sin_addr) */
|
|
char addrbuf[INET_ADDRSTRLEN];
|
|
printf("Connection accepted from %s:%d\n", inet_ntop(AF_INET, &(remote_addr.sin_addr), addrbuf, INET_ADDRSTRLEN), ntohs(remote_addr.sin_port));
|
|
}
|
|
}
|
|
/* usrsctp_close(psock); unreachable */
|
|
} else {
|
|
memset(&encaps, 0, sizeof(struct sctp_udpencaps));
|
|
encaps.sue_address.ss_family = AF_INET;
|
|
encaps.sue_port = htons(remote_udp_port);
|
|
if (usrsctp_setsockopt(psock, IPPROTO_SCTP, SCTP_REMOTE_UDP_ENCAPS_PORT, (const void*)&encaps, (socklen_t)sizeof(struct sctp_udpencaps)) < 0) {
|
|
perror("setsockopt");
|
|
}
|
|
|
|
remote_addr.sin_family = AF_INET;
|
|
#ifdef HAVE_SIN_LEN
|
|
remote_addr.sin_len = sizeof(struct sockaddr_in);
|
|
#endif
|
|
if (!inet_pton(AF_INET, argv[optind], &remote_addr.sin_addr.s_addr)){
|
|
printf("error: invalid destination address\n");
|
|
exit(1);
|
|
}
|
|
remote_addr.sin_port = htons(remote_port);
|
|
|
|
/* TODO fragpoint stuff */
|
|
if (nodelay == 1) {
|
|
optval = 1;
|
|
} else {
|
|
optval = 0;
|
|
}
|
|
usrsctp_setsockopt(psock, IPPROTO_SCTP, SCTP_NODELAY, &optval, sizeof(int));
|
|
|
|
if (fragpoint) {
|
|
av.assoc_id = 0;
|
|
av.assoc_value = fragpoint;
|
|
if (usrsctp_setsockopt(psock, IPPROTO_SCTP, SCTP_MAXSEG, &av, sizeof(struct sctp_assoc_value)) < 0) {
|
|
perror("setsockopt: SCTP_MAXSEG");
|
|
}
|
|
}
|
|
|
|
if (sndbufsize) {
|
|
if (usrsctp_setsockopt(psock, SOL_SOCKET, SO_SNDBUF, &sndbufsize, sizeof(int)) < 0) {
|
|
perror("setsockopt: sndbuf");
|
|
}
|
|
}
|
|
if (verbose) {
|
|
intlen = sizeof(int);
|
|
if (usrsctp_getsockopt(psock, SOL_SOCKET, SO_SNDBUF, &mysndbufsize, (socklen_t *)&intlen) < 0) {
|
|
perror("setsockopt: SO_SNDBUF");
|
|
} else {
|
|
fprintf(stdout,"Send buffer size: %d.\n", mysndbufsize);
|
|
}
|
|
}
|
|
|
|
buffer = malloc(length);
|
|
memset(buffer, 'b', length);
|
|
|
|
if (usrsctp_connect(psock, (struct sockaddr *) &remote_addr, sizeof(struct sockaddr_in)) == -1 ) {
|
|
perror("usrsctp_connect");
|
|
exit(1);
|
|
}
|
|
|
|
gettimeofday(&time_start, NULL);
|
|
|
|
done = 0;
|
|
|
|
if (runtime > 0) {
|
|
#ifndef _WIN32
|
|
signal(SIGALRM, stop_sender);
|
|
alarm(runtime);
|
|
#else
|
|
fprintf(stderr, "You cannot set the runtime in Windows yet\n");
|
|
exit(-1);
|
|
#endif
|
|
}
|
|
|
|
if (use_cb) {
|
|
while (done < 2 && (cb_messages < (number_of_messages - 1))) {
|
|
#ifdef _WIN32
|
|
Sleep(1000);
|
|
#else
|
|
sleep(1);
|
|
#endif
|
|
}
|
|
} else {
|
|
sndinfo.snd_sid = 0;
|
|
sndinfo.snd_flags = 0;
|
|
if (unordered != 0) {
|
|
sndinfo.snd_flags |= SCTP_UNORDERED;
|
|
}
|
|
sndinfo.snd_ppid = 0;
|
|
sndinfo.snd_context = 0;
|
|
sndinfo.snd_assoc_id = 0;
|
|
if (verbose) {
|
|
printf("Start sending ");
|
|
if (number_of_messages > 0) {
|
|
printf("%ld messages ", (long)number_of_messages);
|
|
}
|
|
if (runtime > 0) {
|
|
printf("for %u seconds ...", runtime);
|
|
}
|
|
printf("\n");
|
|
fflush(stdout);
|
|
}
|
|
while (!done && ((number_of_messages == 0) || (messages < (number_of_messages - 1)))) {
|
|
if (very_verbose) {
|
|
printf("Sending message number %lu.\n", messages + 1);
|
|
}
|
|
|
|
if (usrsctp_sendv(psock, buffer, length, (struct sockaddr *) &remote_addr, 1,
|
|
(void *)&sndinfo, (socklen_t)sizeof(struct sctp_sndinfo), SCTP_SENDV_SNDINFO,
|
|
0) < 0) {
|
|
perror("usrsctp_sendv");
|
|
exit(1);
|
|
}
|
|
messages++;
|
|
}
|
|
if (very_verbose) {
|
|
printf("Sending message number %lu.\n", messages + 1);
|
|
}
|
|
|
|
sndinfo.snd_flags |= SCTP_EOF;
|
|
if (usrsctp_sendv(psock, buffer, length, (struct sockaddr *) &remote_addr, 1,
|
|
(void *)&sndinfo, (socklen_t)sizeof(struct sctp_sndinfo), SCTP_SENDV_SNDINFO,
|
|
0) < 0) {
|
|
perror("usrsctp_sendv");
|
|
exit(1);
|
|
}
|
|
messages++;
|
|
}
|
|
free (buffer);
|
|
|
|
if (verbose) {
|
|
printf("Closing socket.\n");
|
|
}
|
|
|
|
usrsctp_close(psock);
|
|
gettimeofday(&time_now, NULL);
|
|
timersub(&time_now, &time_start, &time_diff);
|
|
seconds = time_diff.tv_sec + (double)time_diff.tv_usec/1000000;
|
|
printf("%s of %lu messages of length %d took %f seconds.\n",
|
|
"Sending", messages, length, seconds);
|
|
throughput = (double)messages * (double)length / seconds;
|
|
printf("Throughput was %f Byte/sec.\n", throughput);
|
|
}
|
|
|
|
while (usrsctp_finish() != 0) {
|
|
#ifdef _WIN32
|
|
Sleep(1000);
|
|
#else
|
|
sleep(1);
|
|
#endif
|
|
}
|
|
return 0;
|
|
}
|