1135132Srwatson/*-
2135132Srwatson * Copyright (c) 2004 Robert N. M. Watson
3135132Srwatson * All rights reserved.
4135132Srwatson *
5135132Srwatson * Redistribution and use in source and binary forms, with or without
6135132Srwatson * modification, are permitted provided that the following conditions
7135132Srwatson * are met:
8135132Srwatson * 1. Redistributions of source code must retain the above copyright
9135132Srwatson *    notice, this list of conditions and the following disclaimer.
10135132Srwatson * 2. Redistributions in binary form must reproduce the above copyright
11135132Srwatson *    notice, this list of conditions and the following disclaimer in the
12135132Srwatson *    documentation and/or other materials provided with the distribution.
13135132Srwatson *
14135132Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15135132Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16135132Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17135132Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18135132Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19135132Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20135132Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21135132Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22135132Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23135132Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24135132Srwatson * SUCH DAMAGE.
25135132Srwatson *
26135132Srwatson * $FreeBSD: releng/11.0/tools/regression/netinet/tcpstream/tcpstream.c 136843 2004-10-23 22:11:35Z rwatson $
27135132Srwatson */
28135132Srwatson
29135132Srwatson/*
30135132Srwatson * tcpstream sets up a simple TCP client and server, and then streams a
31135132Srwatson * predictable pseudo-random byte sequence through it using variable block
32135132Srwatson * sizes.  The intent is to to detect corruption of data in the TCP stream.
33135132Srwatson */
34135132Srwatson
35135132Srwatson#include <sys/types.h>
36135132Srwatson#include <sys/errno.h>
37135132Srwatson#include <sys/socket.h>
38135132Srwatson
39135132Srwatson#include <netinet/in.h>
40135132Srwatson
41135132Srwatson#include <arpa/inet.h>
42135132Srwatson
43136843Srwatson#include <err.h>
44136843Srwatson#include <errno.h>
45135132Srwatson#include <stdio.h>
46135132Srwatson#include <stdlib.h>
47135132Srwatson#include <string.h>
48135132Srwatson#include <unistd.h>
49135132Srwatson
50135132Srwatson#define	MAX_LOOPS	10240
51135132Srwatson#define	MAX_LONGS	1024
52135132Srwatson
53135132Srwatsonstatic void
54135132Srwatsonusage(void)
55135132Srwatson{
56135132Srwatson
57135132Srwatson	fprintf(stderr, "tcpstream client [ip] [port] [seed]\n");
58135132Srwatson	fprintf(stderr, "tcpstream server [port] [seed]\n");
59135132Srwatson	exit(-1);
60135132Srwatson}
61135132Srwatson
62135132Srwatsonstatic void
63135132Srwatsonfill_buffer(long *buffer, int len)
64135132Srwatson{
65135132Srwatson	int i;
66135132Srwatson
67135132Srwatson	for (i = 0; i < len; i++)
68135132Srwatson		buffer[i] = htonl(random());
69135132Srwatson}
70135132Srwatson
71135132Srwatsonstatic int
72135132Srwatsoncheck_buffer(long *buffer, int len)
73135132Srwatson{
74135132Srwatson	int i;
75135132Srwatson
76135132Srwatson	for (i = 0; i < len; i++) {
77135132Srwatson		if (buffer[i] != htonl(random()))
78135132Srwatson			return (0);
79135132Srwatson	}
80135132Srwatson	return (1);
81135132Srwatson}
82135132Srwatson
83135132Srwatsonstatic void
84135132Srwatsontcpstream_client(struct sockaddr_in sin, long seed)
85135132Srwatson{
86135132Srwatson	long buffer[MAX_LONGS];
87135132Srwatson	ssize_t len;
88135132Srwatson	int i, j, sock;
89135132Srwatson
90135132Srwatson	srandom(seed);
91135132Srwatson
92135132Srwatson	sock = socket(PF_INET, SOCK_STREAM, 0);
93136843Srwatson	if (sock == -1)
94136843Srwatson		errx(-1, "socket: %s", strerror(errno));
95135132Srwatson
96136843Srwatson	if (connect(sock, (struct sockaddr *) &sin, sizeof(sin)) == -1)
97136843Srwatson		errx(-1, "connect: %s", strerror(errno));
98135132Srwatson
99135132Srwatson	for (j = 0; j < MAX_LOOPS; j++) {
100135132Srwatson		for (i = 0; i < MAX_LONGS; i++) {
101135132Srwatson			fill_buffer(buffer, i);
102135132Srwatson			len = send(sock, buffer, i * sizeof(long), 0);
103135132Srwatson			if (len == -1) {
104135132Srwatson				printf("%d bytes written of %d expected\n",
105135132Srwatson				    len, i * sizeof(long));
106135132Srwatson				fflush(stdout);
107135132Srwatson				perror("send");
108135132Srwatson				goto done;
109135132Srwatson			}
110135132Srwatson		}
111135132Srwatson	}
112135132Srwatson
113135132Srwatsondone:
114135132Srwatson	close(sock);
115135132Srwatson}
116135132Srwatson
117135132Srwatsonstatic void
118135132Srwatsontcpstream_server(struct sockaddr_in sin, long seed)
119135132Srwatson{
120135132Srwatson	int i, j, listen_sock, accept_sock;
121135132Srwatson	struct sockaddr_in other_sin;
122135132Srwatson	long buffer[MAX_LONGS];
123135132Srwatson	socklen_t addrlen;
124135132Srwatson	ssize_t len;
125135132Srwatson
126135132Srwatson	int input_byte_counter;
127135132Srwatson
128135132Srwatson	listen_sock = socket(PF_INET, SOCK_STREAM, 0);
129136843Srwatson	if (listen_sock == -1)
130136843Srwatson		errx(-1, "socket: %s", strerror(errno));
131135132Srwatson
132136843Srwatson	if (bind(listen_sock, (struct sockaddr *)&sin, sizeof(sin)) == -1)
133136843Srwatson		errx(-1, "bind: %s", strerror(errno));
134135132Srwatson
135136843Srwatson	if (listen(listen_sock, -1) == -1)
136136843Srwatson		errx(-1, "listen: %s", strerror(errno));
137135132Srwatson
138135132Srwatson	while (1) {
139135132Srwatson		bzero(&other_sin, sizeof(other_sin));
140135132Srwatson		addrlen = sizeof(other_sin);
141135132Srwatson
142135132Srwatson		accept_sock = accept(listen_sock, (struct sockaddr *)
143135132Srwatson		    &other_sin, &addrlen);
144135132Srwatson		if (accept_sock == -1) {
145135132Srwatson			perror("accept");
146135132Srwatson			continue;
147135132Srwatson		}
148135132Srwatson		printf("connection opened from %s:%d\n",
149135132Srwatson		    inet_ntoa(other_sin.sin_addr), ntohs(other_sin.sin_port));
150135132Srwatson		input_byte_counter = 0;
151135132Srwatson
152135132Srwatson		srandom(seed);
153135132Srwatson
154135132Srwatson		for (j = 0; j < MAX_LOOPS; j++) {
155135132Srwatson			for (i = 0; i < MAX_LONGS; i++) {
156135132Srwatson				len = recv(accept_sock, buffer,
157135132Srwatson				    i * sizeof(long), MSG_WAITALL);
158135132Srwatson				if (len != i * sizeof(long)) {
159135132Srwatson					perror("recv");
160135132Srwatson					goto done;
161135132Srwatson				}
162135132Srwatson				if (check_buffer(buffer, i) == 0) {
163135132Srwatson					fprintf(stderr,
164135132Srwatson    "Corruption in block beginning %d and ending %d\n", input_byte_counter,
165135132Srwatson    input_byte_counter + len);
166135132Srwatson					fprintf(stderr,
167135132Srwatson    "Block size %d\n", i * sizeof(long));
168135132Srwatson					goto done;
169135132Srwatson				}
170135132Srwatson				input_byte_counter += len;
171135132Srwatson			}
172135132Srwatson		}
173135132Srwatsondone:
174135132Srwatson		printf("connection closed\n");
175135132Srwatson		close(accept_sock);
176135132Srwatson	}
177135132Srwatson}
178135132Srwatson
179135132Srwatsonint
180135132Srwatsonmain(int argc, char *argv[])
181135132Srwatson{
182135132Srwatson	struct sockaddr_in sin;
183135132Srwatson	long port, seed;
184135132Srwatson	char *dummy;
185135132Srwatson
186135132Srwatson	if (argc < 2)
187135132Srwatson		usage();
188135132Srwatson	if (strcmp(argv[1], "client") == 0) {
189135132Srwatson		if (argc != 5)
190135132Srwatson			usage();
191135132Srwatson
192135132Srwatson		bzero(&sin, sizeof(sin));
193135132Srwatson		sin.sin_len = sizeof(sin);
194135132Srwatson		sin.sin_family = AF_INET;
195135132Srwatson
196136843Srwatson		if (inet_aton(argv[2], &sin.sin_addr) != 1)
197136843Srwatson			errx(-1, "%s: %s", argv[2], strerror(EINVAL));
198135132Srwatson
199135132Srwatson		port = strtoul(argv[3], &dummy, 10);
200135132Srwatson		if (port < 1 || port > 65535 || *dummy != '\0')
201135132Srwatson			usage();
202135132Srwatson		sin.sin_port = htons(port);
203135132Srwatson
204135132Srwatson		seed = strtoul(argv[4], &dummy, 10);
205135132Srwatson		if (*dummy != '\0')
206135132Srwatson			usage();
207135132Srwatson
208135132Srwatson		tcpstream_client(sin, seed);
209135132Srwatson
210135132Srwatson	} else if (strcmp(argv[1], "server") == 0) {
211135132Srwatson		if (argc != 4)
212135132Srwatson			usage();
213135132Srwatson
214135132Srwatson		bzero(&sin, sizeof(sin));
215135132Srwatson		sin.sin_len = sizeof(sin);
216135132Srwatson		sin.sin_family = AF_INET;
217135132Srwatson		sin.sin_addr.s_addr = INADDR_ANY;
218135132Srwatson
219135132Srwatson		port = strtoul(argv[2], &dummy, 10);
220135132Srwatson		if (port < 1 || port > 65535 || *dummy != '\0')
221135132Srwatson			usage();
222135132Srwatson		sin.sin_port = htons(port);
223135132Srwatson
224135132Srwatson		seed = strtoul(argv[3], &dummy, 10);
225135132Srwatson		if (*dummy != '\0')
226135132Srwatson			usage();
227135132Srwatson
228135132Srwatson		tcpstream_server(sin, seed);
229135132Srwatson	} else
230135132Srwatson		usage();
231135132Srwatson
232135132Srwatson	return (0);
233135132Srwatson}
234