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

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

 



Vlad Yasevich wrote:
Hi Wei

Looking forward to the tests!

I have a few concerns...

Wei Yongjun wrote:
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"

It is a really "bad" (tm) thing to write to a well
known file in /tmp.  It leads to all kinds of exploits.

You either need to make this default a little more
robust, or write to stdout.  Then any debug info can be written
to stderr to distinguish it from the stats.

I personally like the the idea of stdout as it lets the user
deal with output.

Another alternative is to always require '-f' option and make
the user specify the file.

Fixed to use stdout if '-f' is not special.
+#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; */

Commented out code.

Deleted.
+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;

+
+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);
+    }
+

Hmm.. You allow 100 backloged associations, but you only ever accept 1.
Is that on purpose?

I want trace only one association. So only accept 1.

+    if ((pid = fork()) == 0) {
+        settimerhandle();
+        printstatus(gsk);
+        while(gsk);

Are you trying to spin and periodically check the status of the socket?
The problem with checking the status is that the child will never learn
that the socket is closed simply by checking the value of the descriptor.
It will only learn this when it attempts to query SCTP_STATUS and will get
a failure.  This is because the child will have its own descriptor for the
socket and it will stay a valid descriptor even when the parent closes the
socket.

So I think you can skip the whole descriptor checking.

Remove the check. Add check for association state, if it is not active, exit the program.

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

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 |  908 ++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 912 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..ff30a9e
--- /dev/null
+++ b/src/apps/sctp_status.c
@@ -0,0 +1,908 @@
+/* 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 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_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 = NULL;
+
+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);
+	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, 1);
+		accept_r(sk);
+	} else {
+		connect_r(sk, (struct sockaddr *)&s_rem, r_len);
+	}
+
+	if ((pid = fork()) == 0) {
+		settimerhandle();
+		printstatus(gsk);
+		while(1);
+	} 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"
+			"\t      [-f status-file]\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"
+		"\t      [-f status-file]\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");
+	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 (statusfile != NULL) {
+		if (count == 0)
+			unlink(statusfile);
+
+		if((fp = fopen(statusfile, "a+")) == NULL) {
+			perror("fopen");
+			exit(1);
+		}
+	} else
+		fp = stdout;
+
+	if (count == 0)
+		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++;
+
+		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;
+
+	fflush(fp);
+
+	if (fp != stdout)
+		fclose(fp);
+
+	if (status.sstat_primary.spinfo_state != 1) {
+		close_r(sk);
+		exit(1);
+	}
+}
--
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