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$ 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 <err.h> 44 #include <errno.h> 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <string.h> 48 #include <unistd.h> 49 50 #define MAX_LOOPS 10240 51 #define MAX_LONGS 1024 52 53 static void 54 usage(void) 55 { 56 57 fprintf(stderr, "tcpstream client [ip] [port] [seed]\n"); 58 fprintf(stderr, "tcpstream server [port] [seed]\n"); 59 exit(-1); 60 } 61 62 static void 63 fill_buffer(long *buffer, int len) 64 { 65 int i; 66 67 for (i = 0; i < len; i++) 68 buffer[i] = htonl(random()); 69 } 70 71 static int 72 check_buffer(long *buffer, int len) 73 { 74 int i; 75 76 for (i = 0; i < len; i++) { 77 if (buffer[i] != htonl(random())) 78 return (0); 79 } 80 return (1); 81 } 82 83 static void 84 tcpstream_client(struct sockaddr_in sin, long seed) 85 { 86 long buffer[MAX_LONGS]; 87 ssize_t len; 88 int i, j, sock; 89 90 srandom(seed); 91 92 sock = socket(PF_INET, SOCK_STREAM, 0); 93 if (sock == -1) 94 errx(-1, "socket: %s", strerror(errno)); 95 96 if (connect(sock, (struct sockaddr *) &sin, sizeof(sin)) == -1) 97 errx(-1, "connect: %s", strerror(errno)); 98 99 for (j = 0; j < MAX_LOOPS; j++) { 100 for (i = 0; i < MAX_LONGS; i++) { 101 fill_buffer(buffer, i); 102 len = send(sock, buffer, i * sizeof(long), 0); 103 if (len == -1) { 104 printf("%d bytes written of %d expected\n", 105 len, i * sizeof(long)); 106 fflush(stdout); 107 perror("send"); 108 goto done; 109 } 110 } 111 } 112 113 done: 114 close(sock); 115 } 116 117 static void 118 tcpstream_server(struct sockaddr_in sin, long seed) 119 { 120 int i, j, listen_sock, accept_sock; 121 struct sockaddr_in other_sin; 122 long buffer[MAX_LONGS]; 123 socklen_t addrlen; 124 ssize_t len; 125 126 int input_byte_counter; 127 128 listen_sock = socket(PF_INET, SOCK_STREAM, 0); 129 if (listen_sock == -1) 130 errx(-1, "socket: %s", strerror(errno)); 131 132 if (bind(listen_sock, (struct sockaddr *)&sin, sizeof(sin)) == -1) 133 errx(-1, "bind: %s", strerror(errno)); 134 135 if (listen(listen_sock, -1) == -1) 136 errx(-1, "listen: %s", strerror(errno)); 137 138 while (1) { 139 bzero(&other_sin, sizeof(other_sin)); 140 addrlen = sizeof(other_sin); 141 142 accept_sock = accept(listen_sock, (struct sockaddr *) 143 &other_sin, &addrlen); 144 if (accept_sock == -1) { 145 perror("accept"); 146 continue; 147 } 148 printf("connection opened from %s:%d\n", 149 inet_ntoa(other_sin.sin_addr), ntohs(other_sin.sin_port)); 150 input_byte_counter = 0; 151 152 srandom(seed); 153 154 for (j = 0; j < MAX_LOOPS; j++) { 155 for (i = 0; i < MAX_LONGS; i++) { 156 len = recv(accept_sock, buffer, 157 i * sizeof(long), MSG_WAITALL); 158 if (len != i * sizeof(long)) { 159 perror("recv"); 160 goto done; 161 } 162 if (check_buffer(buffer, i) == 0) { 163 fprintf(stderr, 164 "Corruption in block beginning %d and ending %d\n", input_byte_counter, 165 input_byte_counter + len); 166 fprintf(stderr, 167 "Block size %d\n", i * sizeof(long)); 168 goto done; 169 } 170 input_byte_counter += len; 171 } 172 } 173 done: 174 printf("connection closed\n"); 175 close(accept_sock); 176 } 177 } 178 179 int 180 main(int argc, char *argv[]) 181 { 182 struct sockaddr_in sin; 183 long port, seed; 184 char *dummy; 185 186 if (argc < 2) 187 usage(); 188 if (strcmp(argv[1], "client") == 0) { 189 if (argc != 5) 190 usage(); 191 192 bzero(&sin, sizeof(sin)); 193 sin.sin_len = sizeof(sin); 194 sin.sin_family = AF_INET; 195 196 if (inet_aton(argv[2], &sin.sin_addr) != 1) 197 errx(-1, "%s: %s", argv[2], strerror(EINVAL)); 198 199 port = strtoul(argv[3], &dummy, 10); 200 if (port < 1 || port > 65535 || *dummy != '\0') 201 usage(); 202 sin.sin_port = htons(port); 203 204 seed = strtoul(argv[4], &dummy, 10); 205 if (*dummy != '\0') 206 usage(); 207 208 tcpstream_client(sin, seed); 209 210 } else if (strcmp(argv[1], "server") == 0) { 211 if (argc != 4) 212 usage(); 213 214 bzero(&sin, sizeof(sin)); 215 sin.sin_len = sizeof(sin); 216 sin.sin_family = AF_INET; 217 sin.sin_addr.s_addr = INADDR_ANY; 218 219 port = strtoul(argv[2], &dummy, 10); 220 if (port < 1 || port > 65535 || *dummy != '\0') 221 usage(); 222 sin.sin_port = htons(port); 223 224 seed = strtoul(argv[3], &dummy, 10); 225 if (*dummy != '\0') 226 usage(); 227 228 tcpstream_server(sin, seed); 229 } else 230 usage(); 231 232 return (0); 233 } 234