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 27 /* 28 * tcpstream sets up a simple TCP client and server, and then streams a 29 * predictable pseudo-random byte sequence through it using variable block 30 * sizes. The intent is to detect corruption of data in the TCP stream. 31 */ 32 33 #include <sys/types.h> 34 #include <sys/errno.h> 35 #include <sys/socket.h> 36 37 #include <netinet/in.h> 38 39 #include <arpa/inet.h> 40 41 #include <err.h> 42 #include <errno.h> 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 51 static void 52 usage(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 60 static void 61 fill_buffer(long *buffer, int len) 62 { 63 int i; 64 65 for (i = 0; i < len; i++) 66 buffer[i] = htonl(random()); 67 } 68 69 static int 70 check_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 81 static void 82 tcpstream_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 errx(-1, "socket: %s", strerror(errno)); 93 94 if (connect(sock, (struct sockaddr *) &sin, sizeof(sin)) == -1) 95 errx(-1, "connect: %s", strerror(errno)); 96 97 for (j = 0; j < MAX_LOOPS; j++) { 98 for (i = 0; i < MAX_LONGS; i++) { 99 fill_buffer(buffer, i); 100 len = send(sock, buffer, i * sizeof(long), 0); 101 if (len == -1) { 102 printf("%d bytes written of %d expected\n", 103 len, i * sizeof(long)); 104 fflush(stdout); 105 perror("send"); 106 goto done; 107 } 108 } 109 } 110 111 done: 112 close(sock); 113 } 114 115 static void 116 tcpstream_server(struct sockaddr_in sin, long seed) 117 { 118 int i, j, listen_sock, accept_sock; 119 struct sockaddr_in other_sin; 120 long buffer[MAX_LONGS]; 121 socklen_t addrlen; 122 ssize_t len; 123 124 int input_byte_counter; 125 126 listen_sock = socket(PF_INET, SOCK_STREAM, 0); 127 if (listen_sock == -1) 128 errx(-1, "socket: %s", strerror(errno)); 129 130 if (bind(listen_sock, (struct sockaddr *)&sin, sizeof(sin)) == -1) 131 errx(-1, "bind: %s", strerror(errno)); 132 133 if (listen(listen_sock, -1) == -1) 134 errx(-1, "listen: %s", strerror(errno)); 135 136 while (1) { 137 bzero(&other_sin, sizeof(other_sin)); 138 addrlen = sizeof(other_sin); 139 140 accept_sock = accept(listen_sock, (struct sockaddr *) 141 &other_sin, &addrlen); 142 if (accept_sock == -1) { 143 perror("accept"); 144 continue; 145 } 146 printf("connection opened from %s:%d\n", 147 inet_ntoa(other_sin.sin_addr), ntohs(other_sin.sin_port)); 148 input_byte_counter = 0; 149 150 srandom(seed); 151 152 for (j = 0; j < MAX_LOOPS; j++) { 153 for (i = 0; i < MAX_LONGS; i++) { 154 len = recv(accept_sock, buffer, 155 i * sizeof(long), MSG_WAITALL); 156 if (len != i * sizeof(long)) { 157 perror("recv"); 158 goto done; 159 } 160 if (check_buffer(buffer, i) == 0) { 161 fprintf(stderr, 162 "Corruption in block beginning %d and ending %d\n", input_byte_counter, 163 input_byte_counter + len); 164 fprintf(stderr, 165 "Block size %d\n", i * sizeof(long)); 166 goto done; 167 } 168 input_byte_counter += len; 169 } 170 } 171 done: 172 printf("connection closed\n"); 173 close(accept_sock); 174 } 175 } 176 177 int 178 main(int argc, char *argv[]) 179 { 180 struct sockaddr_in sin; 181 long port, seed; 182 char *dummy; 183 184 if (argc < 2) 185 usage(); 186 if (strcmp(argv[1], "client") == 0) { 187 if (argc != 5) 188 usage(); 189 190 bzero(&sin, sizeof(sin)); 191 sin.sin_len = sizeof(sin); 192 sin.sin_family = AF_INET; 193 194 if (inet_aton(argv[2], &sin.sin_addr) != 1) 195 errx(-1, "%s: %s", argv[2], strerror(EINVAL)); 196 197 port = strtoul(argv[3], &dummy, 10); 198 if (port < 1 || port > 65535 || *dummy != '\0') 199 usage(); 200 sin.sin_port = htons(port); 201 202 seed = strtoul(argv[4], &dummy, 10); 203 if (*dummy != '\0') 204 usage(); 205 206 tcpstream_client(sin, seed); 207 208 } else if (strcmp(argv[1], "server") == 0) { 209 if (argc != 4) 210 usage(); 211 212 bzero(&sin, sizeof(sin)); 213 sin.sin_len = sizeof(sin); 214 sin.sin_family = AF_INET; 215 sin.sin_addr.s_addr = INADDR_ANY; 216 217 port = strtoul(argv[2], &dummy, 10); 218 if (port < 1 || port > 65535 || *dummy != '\0') 219 usage(); 220 sin.sin_port = htons(port); 221 222 seed = strtoul(argv[3], &dummy, 10); 223 if (*dummy != '\0') 224 usage(); 225 226 tcpstream_server(sin, seed); 227 } else 228 usage(); 229 230 return (0); 231 } 232