tcpstream.c revision 135132
1/*- 2 * Copyright (c) 2004 Robert N. M. Watson 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD: head/tools/regression/netinet/tcpstream/tcpstream.c 135132 2004-09-13 03:17:22Z rwatson $ 27 */ 28 29/* 30 * tcpstream sets up a simple TCP client and server, and then streams a 31 * predictable pseudo-random byte sequence through it using variable block 32 * sizes. The intent is to to detect corruption of data in the TCP stream. 33 */ 34 35#include <sys/types.h> 36#include <sys/errno.h> 37#include <sys/socket.h> 38 39#include <netinet/in.h> 40 41#include <arpa/inet.h> 42 43#include <stdio.h> 44#include <stdlib.h> 45#include <string.h> 46#include <unistd.h> 47 48#define MAX_LOOPS 10240 49#define MAX_LONGS 1024 50 51static void 52usage(void) 53{ 54 55 fprintf(stderr, "tcpstream client [ip] [port] [seed]\n"); 56 fprintf(stderr, "tcpstream server [port] [seed]\n"); 57 exit(-1); 58} 59 60static void 61fill_buffer(long *buffer, int len) 62{ 63 int i; 64 65 for (i = 0; i < len; i++) 66 buffer[i] = htonl(random()); 67} 68 69static int 70check_buffer(long *buffer, int len) 71{ 72 int i; 73 74 for (i = 0; i < len; i++) { 75 if (buffer[i] != htonl(random())) 76 return (0); 77 } 78 return (1); 79} 80 81static void 82tcpstream_client(struct sockaddr_in sin, long seed) 83{ 84 long buffer[MAX_LONGS]; 85 ssize_t len; 86 int i, j, sock; 87 88 srandom(seed); 89 90 sock = socket(PF_INET, SOCK_STREAM, 0); 91 if (sock == -1) { 92 perror("socket"); 93 exit(-1); 94 } 95 96 if (connect(sock, (struct sockaddr *) &sin, sizeof(sin)) == -1) { 97 perror("connect"); 98 exit(-1); 99 } 100 101 for (j = 0; j < MAX_LOOPS; j++) { 102 for (i = 0; i < MAX_LONGS; i++) { 103 fill_buffer(buffer, i); 104 len = send(sock, buffer, i * sizeof(long), 0); 105 if (len == -1) { 106 printf("%d bytes written of %d expected\n", 107 len, i * sizeof(long)); 108 fflush(stdout); 109 perror("send"); 110 goto done; 111 } 112 } 113 } 114 115done: 116 close(sock); 117} 118 119static void 120tcpstream_server(struct sockaddr_in sin, long seed) 121{ 122 int i, j, listen_sock, accept_sock; 123 struct sockaddr_in other_sin; 124 long buffer[MAX_LONGS]; 125 socklen_t addrlen; 126 ssize_t len; 127 128 int input_byte_counter; 129 130 listen_sock = socket(PF_INET, SOCK_STREAM, 0); 131 if (listen_sock == -1) { 132 perror("socket"); 133 exit(-1); 134 } 135 136 if (bind(listen_sock, (struct sockaddr *)&sin, sizeof(sin)) == -1) { 137 perror("bind"); 138 exit(-1); 139 } 140 141 if (listen(listen_sock, -1) == -1) { 142 perror("listen"); 143 exit(-1); 144 } 145 146 while (1) { 147 bzero(&other_sin, sizeof(other_sin)); 148 addrlen = sizeof(other_sin); 149 150 accept_sock = accept(listen_sock, (struct sockaddr *) 151 &other_sin, &addrlen); 152 if (accept_sock == -1) { 153 perror("accept"); 154 continue; 155 } 156 printf("connection opened from %s:%d\n", 157 inet_ntoa(other_sin.sin_addr), ntohs(other_sin.sin_port)); 158 input_byte_counter = 0; 159 160 srandom(seed); 161 162 for (j = 0; j < MAX_LOOPS; j++) { 163 for (i = 0; i < MAX_LONGS; i++) { 164 len = recv(accept_sock, buffer, 165 i * sizeof(long), MSG_WAITALL); 166 if (len != i * sizeof(long)) { 167 perror("recv"); 168 goto done; 169 } 170 if (check_buffer(buffer, i) == 0) { 171 fprintf(stderr, 172 "Corruption in block beginning %d and ending %d\n", input_byte_counter, 173 input_byte_counter + len); 174 fprintf(stderr, 175 "Block size %d\n", i * sizeof(long)); 176 goto done; 177 } 178 input_byte_counter += len; 179 } 180 } 181done: 182 printf("connection closed\n"); 183 close(accept_sock); 184 } 185} 186 187int 188main(int argc, char *argv[]) 189{ 190 struct sockaddr_in sin; 191 long port, seed; 192 char *dummy; 193 194 if (argc < 2) 195 usage(); 196 if (strcmp(argv[1], "client") == 0) { 197 if (argc != 5) 198 usage(); 199 200 bzero(&sin, sizeof(sin)); 201 sin.sin_len = sizeof(sin); 202 sin.sin_family = AF_INET; 203 204 if (inet_aton(argv[2], &sin.sin_addr) != 1) { 205 errno = EINVAL; 206 perror(argv[2]); 207 exit(-1); 208 } 209 210 port = strtoul(argv[3], &dummy, 10); 211 if (port < 1 || port > 65535 || *dummy != '\0') 212 usage(); 213 sin.sin_port = htons(port); 214 215 seed = strtoul(argv[4], &dummy, 10); 216 if (*dummy != '\0') 217 usage(); 218 219 tcpstream_client(sin, seed); 220 221 } else if (strcmp(argv[1], "server") == 0) { 222 if (argc != 4) 223 usage(); 224 225 bzero(&sin, sizeof(sin)); 226 sin.sin_len = sizeof(sin); 227 sin.sin_family = AF_INET; 228 sin.sin_addr.s_addr = INADDR_ANY; 229 230 port = strtoul(argv[2], &dummy, 10); 231 if (port < 1 || port > 65535 || *dummy != '\0') 232 usage(); 233 sin.sin_port = htons(port); 234 235 seed = strtoul(argv[3], &dummy, 10); 236 if (*dummy != '\0') 237 usage(); 238 239 tcpstream_server(sin, seed); 240 } else 241 usage(); 242 243 return (0); 244} 245