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