[PATCH 3/3] lksctp-tools: Add sctp_status for congestion control test

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Add sctp_status for congestion control test. Based on sctp_test.
It used by SCTP conformance test suite.

Signed-off-by: Wei Yongjun <yjwei@xxxxxxxxxxxxxx>
---
src/apps/Makefile.am   |    7 +-
src/apps/sctp_status.c |  919 ++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 923 insertions(+), 3 deletions(-)
create mode 100644 src/apps/sctp_status.c

diff --git a/src/apps/Makefile.am b/src/apps/Makefile.am
index 515ef96..835c88c 100644
--- a/src/apps/Makefile.am
+++ b/src/apps/Makefile.am
@@ -12,11 +12,11 @@ LDADD = $(top_builddir)/src/lib/libsctp.la \
	$(top_builddir)/src/testlib/libsctputil.la

# programs to be installed with the distriubution
-bin_PROGRAMS = sctp_darn sctp_test
+bin_PROGRAMS = sctp_darn sctp_test sctp_status

# Test programs and libraries to build
noinst_PROGRAMS = bindx_test nagle_snd nagle_rcv myftp sctp_xconnect \
-	peel_server peel_client sctp_test
+	peel_server peel_client sctp_test sctp_status

$(top_builddir)/src/lib/libsctp.la:
	make -C $(top_builddir)/src/lib libsctp.la
@@ -28,6 +28,7 @@ $(top_builddir)/src/testlib/libsctputil.la:
bindx_test_SOURCES = bindx_test.c
sctp_darn_SOURCES = sctp_darn.c sctp_darn.h
sctp_test_SOURCES = sctp_test.c
+sctp_status_SOURCES = sctp_status.c
nagle_rcv_SOURCES = nagle_rcv.c nagle_snd_SOURCES = nagle_snd.c myftp_SOURCES = myftp.c
@@ -36,4 +37,4 @@ peel_server_SOURCES = peel_server.c
peel_client_SOURCES = peel_client.c

# Tutorials
-pkgdoc_DATA = sctp_darn.c sctp_darn.h sctp_test.c
+pkgdoc_DATA = sctp_darn.c sctp_darn.h sctp_test.c sctp_status.c
diff --git a/src/apps/sctp_status.c b/src/apps/sctp_status.c
new file mode 100644
index 0000000..16e5c83
--- /dev/null
+++ b/src/apps/sctp_status.c
@@ -0,0 +1,911 @@
+/* SCTP kernel reference Implementation
+ * (C) Copyright Fujitsu Ltd. 2008, 2009
+ *
+ * The SCTP reference implementation is free software;
+ * you can redistribute it and/or modify it under the terms of
+ * the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * The SCTP reference implementation is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
+ *                 ************************
+ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU CC; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Please send any bug reports or fixes you make to the
+ * email address(es):
+ *    lksctp developers <lksctp-developers@xxxxxxxxxxxxxxxxxxxxx>
+ *
+ * Or submit a bug report through the following website:
+ *    http://www.sf.net/projects/lksctp
+ *
+ * Any bugs reported to us we will try to fix... any fixes shared will
+ * be incorporated into the next SCTP release.
+ *
+ * Written or modified by:
+ *    Wei Yongjun <yjwei@xxxxxxxxxxxxxx>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <netinet/sctp.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <errno.h>
+#include <netdb.h>
+#include <string.h>
+
+#define STATUSFILE	"/tmp/sctpstatus"
+#define DEFAULT_SEC	0
+#define DEFAULT_USEC	5000
+
+#define REALLY_BIG 65536
+
+#define SERVER 		0
+#define CLIENT 		1
+#define NOT_DEFINED	666
+
+#define DEBUG_NONE	0
+#define DEBUG_MIN	1
+#define DEBUG_MAX	2
+
+#define ORDER_PATTERN_UNORDERED   0
+#define ORDER_PATTERN_ORDERED     1
+#define ORDER_PATTERN_ALTERNATE   2
+#define ORDER_PATTERN_RANDOM      3
+
+#define STREAM_PATTERN_SEQUENTIAL 0
+#define STREAM_PATTERN_RANDOM     1
+
+#define MAX_BIND_RETRYS 10
+#define BIG_REPEAT	1000000
+#define REPEAT 		10
+
+#define DEFAULT_MAX_WINDOW 32768
+#define DEFAULT_MIN_WINDOW 1500
+
+#define MSG_CNT		10
+
+#define DEBUG_PRINT(level, print_this...)	\
+{						\
+	if (debug_level >= level) { 		\
+		fprintf(stdout, print_this); 	\
+		fflush(stdout); 		\
+	}					\
+} /* DEBUG_PRINT */
+
+char *local_host = NULL;
+int local_port = 0;
+char *remote_host = NULL;
+int remote_port = 0;
+/* struct sockaddr_in s_rem, s_loc; */
+struct sockaddr_storage s_rem, s_loc;
+int r_len, l_len;
+int size_arg = 0;
+int debug_level = DEBUG_NONE;
+int order_pattern = ORDER_PATTERN_UNORDERED;
+int order_state = 0;
+int stream_pattern = STREAM_PATTERN_SEQUENTIAL;
+int stream_state = 0;
+int repeat = REPEAT;
+int repeat_count = 0;
+int max_msgsize = DEFAULT_MAX_WINDOW;
+int msg_cnt = MSG_CNT;
+int drain = 0;
+int max_stream = 0;
+int gsk = -1;
+int period = 1;
+char *statusfile = STATUSFILE;
+
+void printstatus(int sk);
+void sighandler(int signo);
+void settimerhandle(void);
+void usage(char *argv0);
+void start_test(int role);
+
+unsigned char msg[] = "012345678901234567890123456789012345678901234567890";
+
+/* Convenience structure to determine space needed for cmsg. */
+typedef union {
+	struct sctp_initmsg init;
+	struct sctp_sndrcvinfo sndrcvinfo;
+} _sctp_cmsg_data_t;
+
+int main(int argc, char *argv[]) {
+	int c, role = NOT_DEFINED;
+	char *interface = NULL;
+	struct sockaddr_in *t_addr;
+	struct sockaddr_in6 *t_addr6;
+
+	/* Parse the arguments.  */
+	while ((c = getopt(argc, argv, ":H:L:P:h:p:c:d:lm:sx:X:o:M:r:Di:I:f:")) >= 0 ) {
+		switch (c) {
+		case 'H':
+			local_host = optarg;
+			break;
+		case 'P':
+			local_port = atoi(optarg);
+			break;
+		case 'h':
+			remote_host = optarg;
+			break;
+		case 'p':
+			remote_port = atoi(optarg);
+			break;
+		case 'l':
+			if (role != NOT_DEFINED) {
+				printf("%s: only -s or -l\n", argv[0]);
+				usage(argv[0]);
+				exit(1);
+			}
+			role = SERVER;
+			break;
+		case 's':
+			if (role != NOT_DEFINED) {
+				printf("%s: only -s or -l\n", argv[0]);
+				usage(argv[0]);
+				exit(1);
+			}
+			role = CLIENT;
+			break;
+		case 'D':
+			drain = 1;
+			break;
+		case 'd':
+			debug_level = atoi(optarg);
+			if (debug_level < DEBUG_NONE
+			    || debug_level > DEBUG_MAX) {
+				usage(argv[0]);
+				exit(1);
+			}
+			break;
+		case 'I':
+			period = atoi(optarg);
+			if (period < 0) {
+				usage(argv[0]);
+				exit(1);
+			}
+			break;
+		case 'x':
+			repeat = atoi(optarg);
+			if (!repeat) {
+				repeat = BIG_REPEAT;
+			}
+			break;
+		case 'X':
+			msg_cnt = atoi(optarg);
+			if ((msg_cnt <= 0) || (msg_cnt > MSG_CNT)) {
+				usage(argv[0]);
+				exit(1);
+			}
+			break;
+		case 'c':
+			size_arg = atoi(optarg);
+			if (size_arg < 0) {
+				usage(argv[0]);
+				exit(1);
+			}
+
+			break;
+		case 'o':
+			order_pattern = atoi(optarg);
+			if (order_pattern <  ORDER_PATTERN_UNORDERED
+			    || order_pattern  > ORDER_PATTERN_RANDOM ) {
+				usage(argv[0]);
+				exit(1);
+			}
+			break;
+		case 'M':
+			max_stream = atoi(optarg);
+			if (max_stream <  0
+			    || max_stream >= (1<<16)) {
+				usage(argv[0]);
+				exit(1);
+			}
+			break;
+		case 'm':
+			max_msgsize = atoi(optarg);
+			break;
+		case 'i':
+			interface = optarg;
+			break;
+		case 'f':
+			statusfile = optarg;
+			break;
+		case '?':
+		default:
+			usage(argv[0]);
+			exit(0);
+		}
+	} /* while() */
+
+	if (NOT_DEFINED == role) {
+		usage(argv[0]);
+		exit(1);
+	}
+
+	if (SERVER == role && NULL == local_host && remote_host != NULL) {
+		fprintf(stderr, "%s: Server needs local address, "
+			 "not remote address\n", argv[0]);
+		usage(argv[0]);
+		exit(1);
+	}
+	if (CLIENT == role && NULL == remote_host) {
+		fprintf(stderr, "%s: Client needs at least remote address "
+			 "& port\n", argv[0]);
+		usage(argv[0]);
+		exit(1);
+	}
+
+	if (optind < argc) {
+		fprintf(stderr, "%s: non-option arguments are illegal: ", argv[0]);
+		while (optind < argc)
+			fprintf(stderr, "%s ", argv[optind++]);
+		fprintf (stderr, "\n");
+		usage(argv[0]);
+		exit(1);
+	}
+
+	if (remote_host != NULL && remote_port != 0) {
+		struct addrinfo *res;
+		int error;
+		char *host_s, *serv_s;
+
+		if ((host_s = malloc(NI_MAXHOST)) == NULL) {
+			fprintf(stderr, "\n*** host_s malloc failed!!! ***\n");
+			exit(1);
+		}
+		if ((serv_s = malloc(NI_MAXSERV)) == NULL) {
+			fprintf(stderr, "\n*** serv_s malloc failed!!! ***\n");
+			exit(1);
+		}
+
+		error = getaddrinfo(remote_host, 0, NULL, &res);
+		if (error) {
+			printf("%s.\n", gai_strerror(error));
+			usage(argv[0]);
+			exit(1);
+		}
+
+		switch (res->ai_family) {
+			case AF_INET:
+				t_addr = (struct sockaddr_in *)&s_rem;
+
+				t_addr->sin_family = AF_INET;
+				t_addr->sin_port = htons(remote_port);
+				inet_pton(AF_INET, remote_host, &t_addr->sin_addr);
+
+				r_len = sizeof (struct sockaddr_in);
+#ifdef __FreeBSD__
+				t_addr->sin_len = r_len;
+#endif
+				break;
+			case AF_INET6:
+				t_addr6 = (struct sockaddr_in6 *)&s_rem;
+
+				if (interface)
+					t_addr6->sin6_scope_id = if_nametoindex(interface);
+				t_addr6->sin6_family = AF_INET6;
+				t_addr6->sin6_port = htons(remote_port);
+				inet_pton(AF_INET6, remote_host, &t_addr6->sin6_addr);
+
+				r_len = sizeof (struct sockaddr_in6);
+
+#ifdef __FreeBSD__
+				t_addr6->sin6_len = r_len;
+#endif
+				break;
+		}
+
+		getnameinfo((struct sockaddr *)&s_rem, r_len, host_s,
+			    NI_MAXHOST, serv_s, NI_MAXSERV, NI_NUMERICHOST);
+
+		DEBUG_PRINT(DEBUG_MAX, "remote:addr=%s, port=%s, family=%d\n",
+			    host_s, serv_s, res->ai_family);
+        }
+
+	if (local_host != NULL) {
+		struct addrinfo *res;
+		int error;
+		char *host_s, *serv_s;
+		struct sockaddr_in *t_addr;
+		struct sockaddr_in6 *t_addr6;
+
+		if ((host_s = malloc(NI_MAXHOST)) == NULL) {
+			fprintf(stderr, "\n*** host_s malloc failed!!! ***\n");
+			exit(1);
+		}
+		if ((serv_s = malloc(NI_MAXSERV)) == NULL) {
+			fprintf(stderr, "\n*** serv_s malloc failed!!! ***\n");
+			exit(1);
+		}
+
+		if (strcmp(local_host, "0") == 0)
+			local_host = "0.0.0.0";
+
+		error = getaddrinfo(local_host, 0, NULL, &res);
+		if (error) {
+			printf("%s.\n", gai_strerror(error));
+			usage(argv[0]);
+			exit(1);
+		}
+
+		switch (res->ai_family) {
+			case AF_INET:
+				t_addr = (struct sockaddr_in *)&s_loc;
+				t_addr->sin_family = AF_INET;
+				t_addr->sin_port = htons(local_port);
+				inet_pton(AF_INET, local_host, &t_addr->sin_addr);
+
+				l_len = sizeof (struct sockaddr_in);
+#ifdef __FreeBSD__
+				t_addr->sin_len = l_len;
+#endif
+				break;
+			case AF_INET6:
+				t_addr6 = (struct sockaddr_in6 *)&s_loc;
+
+				if (interface)
+					t_addr6->sin6_scope_id = if_nametoindex(interface);
+				t_addr6->sin6_family = AF_INET6;
+				t_addr6->sin6_port = htons(local_port);
+
+				inet_pton(AF_INET6, local_host, &t_addr6->sin6_addr);
+
+				l_len = sizeof (struct sockaddr_in6);
+
+#ifdef __FreeBSD__
+				t_addr6->sin6_len = l_len;
+#endif
+				break;
+		}
+
+		error = getnameinfo((struct sockaddr *)&s_loc, l_len, host_s,
+			    NI_MAXHOST, serv_s, NI_MAXSERV, NI_NUMERICHOST);
+
+		if (error)
+			printf("%s..\n", gai_strerror(error));
+
+		DEBUG_PRINT(DEBUG_MAX, "local:addr=%s, port=%s, family=%d\n",
+			    host_s, serv_s, res->ai_family);
+        }
+
+	/* Let the testing begin. */
+	start_test(role);
+
+	return 0;
+}
+
+int bind_r(int sk, struct sockaddr_storage *saddr) {
+	int error = 0, i = 0;
+	char *host_s, *serv_s;
+
+	if ((host_s = malloc(NI_MAXHOST)) == NULL) {
+		fprintf(stderr, "\n\t\t*** host_s malloc failed!!! ***\n");
+		exit(1);
+	}
+	if ((serv_s = malloc(NI_MAXSERV)) == NULL) {
+		fprintf(stderr, "\n\t\t*** serv_s malloc failed!!! ***\n");
+		exit(1);
+	}
+
+	do {
+		if (i > 0) sleep(1); /* sleep a while before new try... */
+
+		error = getnameinfo((struct sockaddr *)saddr, l_len, host_s,
+				    NI_MAXHOST, serv_s, NI_MAXSERV,
+				    NI_NUMERICHOST);
+
+		if (error)
+			printf("%s\n", gai_strerror(error));
+
+		DEBUG_PRINT(DEBUG_MIN,
+			"\tbind(sk=%d, [a:%s,p:%s])  --  attempt %d/%d\n",
+			sk, host_s, serv_s, i+1, MAX_BIND_RETRYS);
+
+		error = bind(sk, (struct sockaddr *)saddr, l_len);
+
+		if (error != 0) {
+			if( errno != EADDRINUSE ) {
+				fprintf(stderr, "\n\n\t\t***bind: can "
+					"not bind to %s:%s: %s ****\n",
+					host_s, serv_s, strerror(errno));
+				exit(1);
+			}
+		}
+		i++;
+		if (i >= MAX_BIND_RETRYS) {
+			fprintf(stderr, "Maximum bind() attempts. "
+				"Die now...\n\n");
+			exit(1);
+		}
+	} while (error < 0 && i < MAX_BIND_RETRYS);
+
+	return 0;
+} /* bind_r() */
+
+int listen_r(int sk, int listen_count) {
+	int error = 0;
+
+	DEBUG_PRINT(DEBUG_MIN, "\tlisten(sk=%d,backlog=%d)\n",
+		sk, listen_count);
+
+	/* Mark sk as being able to accept new associations */
+	error = listen(sk, 1);
+	if (error != 0) {
+		fprintf(stderr, "\n\n\t\t*** listen:  %s ***\n\n\n", strerror(errno));
+		exit(1);
+	}
+
+	return 0;
+} /* listen_r() */
+
+int accept_r(int sk){
+	socklen_t len = 0;
+
+	DEBUG_PRINT(DEBUG_MIN, "\taccept(sk=%d)\n", sk);
+
+	gsk = accept(sk, NULL, &len);
+	if (gsk < 0) {
+		fprintf(stderr, "\n\n\t\t*** accept:  %s ***\n\n\n", strerror(errno));
+		exit(1);
+	}
+
+	return 0;
+} /* accept_r() */
+
+int connect_r(int sk, const struct sockaddr *serv_addr, socklen_t addrlen) {
+	int error = 0;
+
+	DEBUG_PRINT(DEBUG_MIN, "\tconnect(sk=%d)\n", sk);
+
+	/* Mark sk as being able to accept new associations */
+	error = connect(sk, serv_addr, addrlen);
+	if (error != 0) {
+		fprintf(stderr, "\n\n\t\t*** connect:  %s ***\n\n\n",
+			strerror(errno));
+		exit(1);
+	}
+
+	gsk = sk;
+
+	return 0;
+} /* connect_r() */
+
+int close_r(int sk) {
+	int error = 0;
+
+	DEBUG_PRINT(DEBUG_MIN, "\tclose(sk=%d)\n",sk);
+
+	error = close(sk);
+	if (error != 0) {
+		fprintf(stderr, "\n\n\t\t*** close: %s ***\n\n",
+			strerror(errno));
+		exit(1);
+	}
+	fflush(stdout);
+	gsk = -1;
+	return 0;
+} /* close_r() */
+
+int receive_r(int sk)
+{
+	int error = 0;
+	char incmsg[CMSG_SPACE(sizeof(_sctp_cmsg_data_t))];
+	struct iovec iov;
+	struct msghdr inmessage;
+
+	/* Initialize inmessage with enough space for DATA... */
+	memset(&inmessage, 0, sizeof(inmessage));
+	if ((iov.iov_base = malloc(REALLY_BIG)) == NULL) {
+		fprintf(stderr, "\n\t\t*** malloc not enough memory!!! ***\n");
+		exit(1);
+	}
+	iov.iov_len = REALLY_BIG;
+	inmessage.msg_iov = &iov;
+	inmessage.msg_iovlen = 1;
+	/* or a control message.  */
+	inmessage.msg_control = incmsg;
+	inmessage.msg_controllen = sizeof(incmsg);
+
+	/* Get the messages sent */
+	while (1) {
+		DEBUG_PRINT(DEBUG_MIN, "\trecvmsg(sk=%d) ", sk);
+
+		error = recvmsg(sk, &inmessage, MSG_WAITALL);
+		if (error < 0 && error != EAGAIN) {
+			fprintf(stderr, "\n\t\t*** recvmsg: %s ***\n\n",
+					strerror(errno));
+			fflush(stdout);
+			close(sk);
+			free(iov.iov_base);
+			exit(1);
+		} else if (error == 0) {
+			printf("\n\t\trecvmsg() returned 0 !!!!\n");
+			fflush(stdout);
+		}
+
+		if(MSG_NOTIFICATION & inmessage.msg_flags)
+			continue; /* got a notification... */
+
+		inmessage.msg_control = incmsg;
+		inmessage.msg_controllen = sizeof(incmsg);
+		iov.iov_len = REALLY_BIG;
+		break;
+	}
+
+	free(iov.iov_base);
+	return 0;
+} /* receive_r () */
+
+void server(int sk) {
+	if (max_msgsize > DEFAULT_MAX_WINDOW) {
+		if (setsockopt(sk, IPPROTO_SCTP, SO_RCVBUF, &max_msgsize,
+			       sizeof(max_msgsize)) < 0) {
+			perror("setsockopt(SO_RCVBUF)");
+			exit(1);
+		}
+	}
+
+	receive_r(sk);
+} /* server() */
+
+void * build_msg(int len) {
+	int i = len - 1;
+	int n;
+	char *msg_buf, *p;
+
+	msg_buf = malloc(len);
+	if (NULL == msg_buf) {
+		fprintf(stderr, "\n\t\t*** malloc not enough memory!!! ***\n");
+		exit(1);
+	}
+	p = msg_buf;
+
+	do {
+		n = ((i > 50)?50:i);
+		memcpy(p, msg, ((i > 50)?50:i));
+		p += n;
+		i -= n;
+	} while (i > 0);
+
+	msg_buf[len-1] = '\0';
+
+	return(msg_buf);
+
+} /* build_msg() */
+
+int send_r(int sk, int stream, int order, int send_size, int assoc_i) {
+	int error = 0;
+	struct msghdr outmsg;
+	struct iovec iov;
+	char *message = NULL;
+	int msglen = 0;
+	char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
+	struct cmsghdr *cmsg;
+	struct sctp_sndrcvinfo *sinfo;
+
+	if (send_size > 0) {
+		message = build_msg(send_size);
+		msglen = strlen(message) + 1;
+		iov.iov_base = message;
+		iov.iov_len = msglen;
+	} else {
+			exit(1);
+	}
+
+	outmsg.msg_name = &s_rem;
+	outmsg.msg_namelen = sizeof(struct sockaddr_storage);
+	outmsg.msg_iov = &iov;
+	outmsg.msg_iovlen = 1;
+	outmsg.msg_control = outcmsg;
+	outmsg.msg_controllen = sizeof(outcmsg);
+	outmsg.msg_flags = 0;
+
+	cmsg = CMSG_FIRSTHDR(&outmsg);
+	cmsg->cmsg_level = IPPROTO_SCTP;
+	cmsg->cmsg_type = SCTP_SNDRCV;
+	cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
+
+	outmsg.msg_controllen = cmsg->cmsg_len;
+	sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
+	memset(sinfo, 0, sizeof(struct sctp_sndrcvinfo));
+	sinfo->sinfo_ppid = rand();
+	sinfo->sinfo_stream = stream;
+	sinfo->sinfo_flags = 0;
+	if (!order)
+		sinfo->sinfo_flags = SCTP_UNORDERED;
+
+	DEBUG_PRINT(DEBUG_MIN, "\tsendmsg(sk=%d, assoc=%d) %4d bytes.\n",
+		    sk, assoc_i, send_size);
+	DEBUG_PRINT(DEBUG_MAX, "\t  SNDRCV");
+	if (DEBUG_MAX == debug_level) {
+		printf("(stream=%u ", 	sinfo->sinfo_stream);
+		printf("flags=0x%x ",	sinfo->sinfo_flags);
+		printf("ppid=%u)\n",	sinfo->sinfo_ppid);
+	}
+
+	/* Send to our neighbor.  */
+	error = sendmsg(sk, &outmsg, MSG_WAITALL);
+	if (error != msglen) {
+		fprintf(stderr, "\n\t\t*** sendmsg: %s ***\n\n",
+			strerror(errno));
+		fflush(stdout);
+		exit(1);
+	}
+
+	if (send_size > 0) free(message);
+	return 0;
+} /* send_r() */
+
+int next_order(int state, int pattern)
+{
+	switch (pattern){
+	case ORDER_PATTERN_UNORDERED:
+		state = 0;
+		break;
+	case ORDER_PATTERN_ORDERED:
+		state = 1;
+		break;
+	case ORDER_PATTERN_ALTERNATE:
+		state = state ? 0 : 1;
+		break;
+	case ORDER_PATTERN_RANDOM:
+		state = rand() % 2;
+		break;
+	}
+
+	return state;
+}
+
+int next_stream(int state, int pattern)
+{
+	switch (pattern){
+	case STREAM_PATTERN_RANDOM:
+		state = rand() % (max_stream + 1);
+		break;
+	case STREAM_PATTERN_SEQUENTIAL:
+		state = state + 1;
+		if (state > max_stream)
+			state = 0;
+		break;
+	}
+
+	return state;
+}
+
+int next_msg_size(int msg_cnt)
+{
+	int msg_size;
+
+	if (size_arg) {
+		msg_size = size_arg;
+	} else {
+		msg_size = (rand() % max_msgsize) + 1;
+	}
+
+	return msg_size;
+
+} /* next_msg_size() */
+
+void client(int sk) {
+	int msg_size;
+	int i;
+
+	for (i = 0; i < msg_cnt; i++) {
+		msg_size = next_msg_size(i);
+		order_state = next_order(order_state, order_pattern);
+		stream_state = next_stream(stream_state, stream_pattern);
+
+		if (send_r(sk, stream_state, order_state, msg_size, 0) < 0) {
+			close(sk);
+			break;
+		}
+
+		/* The sender is echoing so do discard the echoed data. */
+		if (drain && ((i + 1) % period == 0)) {
+			receive_r(sk);
+		}
+	}
+} /* client() */
+
+void start_test(int role) {
+	int sk, pid;
+	int i = 0;
+
+	DEBUG_PRINT(DEBUG_NONE, "\nStarting tests...\n");
+
+	repeat_count = repeat;
+
+	DEBUG_PRINT(DEBUG_MIN, "\tsocket(SOCK_STREAM, IPPROTO_SCTP)");
+
+	if ((sk = socket(s_loc.ss_family, SOCK_STREAM, IPPROTO_SCTP)) < 0 ) {
+		fprintf(stderr, "\n\n\t\t*** socket: failed to create"
+			" socket:  %s ***\n", strerror(errno));
+		exit(1);
+	}
+	DEBUG_PRINT(DEBUG_MIN, "  ->  sk=%d\n", sk);
+
+	bind_r(sk, &s_loc);
+
+	if (role == SERVER) {
+		listen_r(sk, 100);
+		accept_r(sk);
+	} else {
+		connect_r(sk, (struct sockaddr *)&s_rem, r_len);
+	}
+
+	if ((pid = fork()) == 0) {
+		settimerhandle();
+		printstatus(gsk);
+		while(gsk);
+	} else {
+		if (!debug_level) {
+			printf("     ");
+		}
+
+		for(i = 0; i < repeat_count; i++) {
+
+			if (role == SERVER) {
+				DEBUG_PRINT(DEBUG_NONE, "Server: Receiving packets.(%d/%d)\n",
+					i+1, repeat_count);
+				server(gsk);
+			} else {
+				DEBUG_PRINT(DEBUG_NONE, "Client: Sending packets.(%d/%d)\n",
+					i+1, repeat_count);
+				client(sk);
+			}
+
+			fflush(stdout);
+		}
+
+		if (role == SERVER) close_r(gsk);
+		close_r(sk);
+	}
+} /* start_test() */
+
+void settimerhandle(void) {
+	struct sigaction act;
+	struct itimerval interval;
+
+	act.sa_handler = sighandler;
+	act.sa_flags = 0;
+	sigemptyset(&act.sa_mask);
+	sigaction(SIGPROF, &act, NULL);
+
+	interval.it_value.tv_sec = DEFAULT_SEC;
+	interval.it_value.tv_usec = DEFAULT_USEC;
+	interval.it_interval = interval.it_value;
+
+	setitimer(ITIMER_PROF, &interval, NULL);
+}
+
+void usage(char *argv0) {
+	fprintf(stderr, "\nusage:\n");
+	fprintf(stderr, "  server:\n");
+	fprintf(stderr, "  %8s -H local-addr -P local-port -l [-d level] [-x]\n"
+			"\t      [-L num-ports] [-S num-ports]\n"
+			"\t      [-a assoc-pattern]\n"
+			"\t      [-i interface]\n",
+		argv0);
+	fprintf(stderr, "\n");
+	fprintf(stderr, "  client:\n");
+	fprintf(stderr, "  %8s -H local-addr -P local-port -h remote-addr\n"
+		"\t      -p remote-port -s [-c case ] [-d level]\n"
+		"\t      [-x repeat] [-o order-pattern] ream-pattern]\n"
+		"\t      [-M max-stream]\n"
+		"\t      [-m max-msgsize]\n"
+		"\t      [-L num-ports] [-S num-ports]\n"
+		"\t      [-i interface]\n",
+		argv0);
+	fprintf(stderr, "\n");
+	fprintf(stderr, "\t-c value = Packets of specifed size.\n");
+	fprintf(stderr, "\t-m msgsize(1500-65515, default value 32768)\n");
+	fprintf(stderr, "\t-x number of repeats\n");
+	fprintf(stderr, "\t-o order-pattern\n");
+	fprintf(stderr, "\t   0 = all unordered(default) \n");
+	fprintf(stderr, "\t   1 = all ordered \n");
+	fprintf(stderr, "\t   2 = alternating \n");
+	fprintf(stderr, "\t   3 = random\n");
+	fprintf(stderr, "\t-M max-stream (default value 0)\n");
+	fprintf(stderr, "\t-D drain. If in client mode do a read following send.\n");
+	fprintf(stderr, "\n");
+	fflush(stderr);
+
+} /* usage() */
+
+void sighandler(int signo) {
+	DEBUG_PRINT(DEBUG_MAX, "timeout sig\n");
+	if (gsk >= 0) printstatus(gsk);
+}
+
+char* get_sstat_state(int state) {
+	switch(state) {
+	case SCTP_EMPTY:
+		return "EMPTY";
+	case SCTP_CLOSED:
+		return "CLOSED";
+	case SCTP_COOKIE_WAIT:
+		return "COOKIE_WAIT";
+	case SCTP_COOKIE_ECHOED:
+		return "COOKIE_ECHOED";
+	case SCTP_ESTABLISHED:
+		return "ESTABLISHED";
+	case SCTP_SHUTDOWN_PENDING:
+		return "SHUTDOWN_PENDING";
+	case SCTP_SHUTDOWN_SENT:
+		return "SHUTDOWN_SENT";
+	case SCTP_SHUTDOWN_RECEIVED:
+		return "SHUTDOWN_RECEIVED";
+	case SCTP_SHUTDOWN_ACK_SENT:
+		return "SHUTDOWN_ACK_SENT";
+	default:
+		return "UNKNOW";
+	}
+}
+
+void printstatus(int sk) {
+	static int cwnd = 0;
+	static int count = 0;
+	struct sctp_status status;
+	socklen_t optlen;
+	FILE * fp;
+
+	optlen = sizeof(struct sctp_status);
+	if(getsockopt(sk, IPPROTO_SCTP, SCTP_STATUS, &status, &optlen) < 0) {
+		fprintf(stderr, "Error getting status: %s.\n", strerror(errno));
+		exit(1);
+	}
+
+	if (count == 0) {
+		unlink(statusfile);
+	}
+
+	if((fp = fopen(statusfile, "a+")) == NULL) {
+		perror("fopen");
+		exit(1);
+	}
+
+	if (count == 0) {
+		DEBUG_PRINT(DEBUG_MIN, "NO. ASSOC-ID STATE             RWND     UNACKDATA PENDDATA INSTRMS OUTSTRMS "
+				"FRAG-POINT SPINFO-STATE SPINFO-CWDN SPINFO-SRTT SPINFO-RTO SPINFO-MTU\n");
+
+		fprintf(fp, "NO. ASSOC-ID STATE             RWND     UNACKDATA PENDDATA INSTRMS OUTSTRMS "
+				"FRAG-POINT SPINFO-STATE SPINFO-CWDN SPINFO-SRTT SPINFO-RTO SPINFO-MTU\n");
+	}
+
+	if (cwnd != status.sstat_primary.spinfo_cwnd) {
+		count++;
+
+		DEBUG_PRINT(DEBUG_MIN, "%-3d %-8d %-17s %-8d %-9d %-8d %-7d %-8d %-10d %-12s %-11d %-11d %-10d %d\n", count,
+				status.sstat_assoc_id, get_sstat_state(status.sstat_state),
+				status.sstat_rwnd, status.sstat_unackdata, status.sstat_penddata,
+				status.sstat_instrms, status.sstat_outstrms, status.sstat_fragmentation_point,
+				(status.sstat_primary.spinfo_state == 1) ? "ACTIVE" : "INACTIVE",
+				status.sstat_primary.spinfo_cwnd, status.sstat_primary.spinfo_srtt,
+				status.sstat_primary.spinfo_rto, status.sstat_primary.spinfo_mtu);
+
+		fprintf(fp, "%-3d %-8d %-17s %-8d %-9d %-8d %-7d %-8d %-10d %-12s %-11d %-11d %-10d %d\n", count,
+				status.sstat_assoc_id, get_sstat_state(status.sstat_state),
+				status.sstat_rwnd, status.sstat_unackdata, status.sstat_penddata,
+				status.sstat_instrms, status.sstat_outstrms, status.sstat_fragmentation_point,
+				(status.sstat_primary.spinfo_state == 1) ? "ACTIVE" : "INACTIVE",
+				status.sstat_primary.spinfo_cwnd, status.sstat_primary.spinfo_srtt,
+				status.sstat_primary.spinfo_rto, status.sstat_primary.spinfo_mtu);
+	}
+
+	cwnd = status.sstat_primary.spinfo_cwnd;
+
+	fclose(fp);
+}
--
1.5.3.8



--
To unsubscribe from this list: send the line "unsubscribe linux-sctp" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Networking Development]     [Linux OMAP]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux