xref: /haiku/src/tests/system/network/tcptester/tcptester.cpp (revision 5e54f6d4f9dd607ae2afcea4fe72f2f1763e4b5e)
1*5e54f6d4SAugustin Cavalier /*
2*5e54f6d4SAugustin Cavalier  * A very simple controlable traffic generator for TCP testing.
3*5e54f6d4SAugustin Cavalier  *
4*5e54f6d4SAugustin Cavalier  * Copyright 2007, Haiku, Inc. All Rights Reserved.
5*5e54f6d4SAugustin Cavalier  * Distributed under the terms of the MIT License.
6*5e54f6d4SAugustin Cavalier  *
7*5e54f6d4SAugustin Cavalier  * Authors:
8*5e54f6d4SAugustin Cavalier  *      Hugo Santos, hugosantos@gmail.com
9*5e54f6d4SAugustin Cavalier  */
10*5e54f6d4SAugustin Cavalier 
11*5e54f6d4SAugustin Cavalier #include <OS.h>
12*5e54f6d4SAugustin Cavalier 
13*5e54f6d4SAugustin Cavalier #include <assert.h>
14*5e54f6d4SAugustin Cavalier #include <ctype.h>
15*5e54f6d4SAugustin Cavalier #include <stdio.h>
16*5e54f6d4SAugustin Cavalier #include <stdint.h>
17*5e54f6d4SAugustin Cavalier #include <stdlib.h>
18*5e54f6d4SAugustin Cavalier #include <string.h>
19*5e54f6d4SAugustin Cavalier #include <unistd.h>
20*5e54f6d4SAugustin Cavalier 
21*5e54f6d4SAugustin Cavalier #include <arpa/inet.h>
22*5e54f6d4SAugustin Cavalier #include <netinet/in.h>
23*5e54f6d4SAugustin Cavalier #include <sys/socket.h>
24*5e54f6d4SAugustin Cavalier 
25*5e54f6d4SAugustin Cavalier 
26*5e54f6d4SAugustin Cavalier struct context {
27*5e54f6d4SAugustin Cavalier 	int sock;
28*5e54f6d4SAugustin Cavalier 	uint8 generator;
29*5e54f6d4SAugustin Cavalier 	int index;
30*5e54f6d4SAugustin Cavalier 	int8_t buffer[256];
31*5e54f6d4SAugustin Cavalier };
32*5e54f6d4SAugustin Cavalier 
33*5e54f6d4SAugustin Cavalier static int process_command(context *ctx);
34*5e54f6d4SAugustin Cavalier 
35*5e54f6d4SAugustin Cavalier static int
number(context * ctx)36*5e54f6d4SAugustin Cavalier number(context *ctx)
37*5e54f6d4SAugustin Cavalier {
38*5e54f6d4SAugustin Cavalier 	int result = 0;
39*5e54f6d4SAugustin Cavalier 
40*5e54f6d4SAugustin Cavalier 	while (isdigit(ctx->buffer[ctx->index])) {
41*5e54f6d4SAugustin Cavalier 		result *= 10;
42*5e54f6d4SAugustin Cavalier 		result += ctx->buffer[ctx->index] - '0';
43*5e54f6d4SAugustin Cavalier 		ctx->index++;
44*5e54f6d4SAugustin Cavalier 	}
45*5e54f6d4SAugustin Cavalier 
46*5e54f6d4SAugustin Cavalier 	return result;
47*5e54f6d4SAugustin Cavalier }
48*5e54f6d4SAugustin Cavalier 
49*5e54f6d4SAugustin Cavalier 
50*5e54f6d4SAugustin Cavalier static int
value(context * ctx)51*5e54f6d4SAugustin Cavalier value(context *ctx)
52*5e54f6d4SAugustin Cavalier {
53*5e54f6d4SAugustin Cavalier 	if (ctx->buffer[ctx->index] == '[') {
54*5e54f6d4SAugustin Cavalier 		ctx->index++;
55*5e54f6d4SAugustin Cavalier 		int upper, lower = number(ctx);
56*5e54f6d4SAugustin Cavalier 		if (ctx->buffer[ctx->index] == ',') {
57*5e54f6d4SAugustin Cavalier 			ctx->index++;
58*5e54f6d4SAugustin Cavalier 			upper = number(ctx);
59*5e54f6d4SAugustin Cavalier 		} else {
60*5e54f6d4SAugustin Cavalier 			upper = lower + 50;
61*5e54f6d4SAugustin Cavalier 			lower -= 50;
62*5e54f6d4SAugustin Cavalier 		}
63*5e54f6d4SAugustin Cavalier 
64*5e54f6d4SAugustin Cavalier 		return lower + rand() % (upper - lower + 1);
65*5e54f6d4SAugustin Cavalier 	}
66*5e54f6d4SAugustin Cavalier 
67*5e54f6d4SAugustin Cavalier 	return number(ctx);
68*5e54f6d4SAugustin Cavalier }
69*5e54f6d4SAugustin Cavalier 
70*5e54f6d4SAugustin Cavalier 
71*5e54f6d4SAugustin Cavalier static int
repeat(context * ctx)72*5e54f6d4SAugustin Cavalier repeat(context *ctx)
73*5e54f6d4SAugustin Cavalier {
74*5e54f6d4SAugustin Cavalier 	int max, saved, count = number(ctx);
75*5e54f6d4SAugustin Cavalier 
76*5e54f6d4SAugustin Cavalier 	max = saved = ctx->index;
77*5e54f6d4SAugustin Cavalier 	for (int i = 0; i < count; i++) {
78*5e54f6d4SAugustin Cavalier 		ctx->index = saved;
79*5e54f6d4SAugustin Cavalier 		if (process_command(ctx) < 0)
80*5e54f6d4SAugustin Cavalier 			return -1;
81*5e54f6d4SAugustin Cavalier 		if (ctx->index > max)
82*5e54f6d4SAugustin Cavalier 			max = ctx->index;
83*5e54f6d4SAugustin Cavalier 	}
84*5e54f6d4SAugustin Cavalier 
85*5e54f6d4SAugustin Cavalier 	ctx->index = max;
86*5e54f6d4SAugustin Cavalier 	return 0;
87*5e54f6d4SAugustin Cavalier }
88*5e54f6d4SAugustin Cavalier 
89*5e54f6d4SAugustin Cavalier 
90*5e54f6d4SAugustin Cavalier static void
send_packet(context * ctx,size_t bytes)91*5e54f6d4SAugustin Cavalier send_packet(context *ctx, size_t bytes)
92*5e54f6d4SAugustin Cavalier {
93*5e54f6d4SAugustin Cavalier 	uint8_t buffer[1024];
94*5e54f6d4SAugustin Cavalier 	uint8_t *ptr = buffer;
95*5e54f6d4SAugustin Cavalier 
96*5e54f6d4SAugustin Cavalier 	if (bytes > sizeof(buffer))
97*5e54f6d4SAugustin Cavalier 		ptr = new uint8_t[bytes];
98*5e54f6d4SAugustin Cavalier 
99*5e54f6d4SAugustin Cavalier 	for (size_t i = 0; i < bytes; i++) {
100*5e54f6d4SAugustin Cavalier 		ptr[i] = ctx->generator + '0';
101*5e54f6d4SAugustin Cavalier 		ctx->generator = (ctx->generator + 1) % 10;
102*5e54f6d4SAugustin Cavalier 	}
103*5e54f6d4SAugustin Cavalier 
104*5e54f6d4SAugustin Cavalier 	send(ctx->sock, ptr, bytes, 0);
105*5e54f6d4SAugustin Cavalier 
106*5e54f6d4SAugustin Cavalier 	if (ptr != buffer)
107*5e54f6d4SAugustin Cavalier 		delete [] ptr;
108*5e54f6d4SAugustin Cavalier }
109*5e54f6d4SAugustin Cavalier 
110*5e54f6d4SAugustin Cavalier 
111*5e54f6d4SAugustin Cavalier static int
process_command(context * ctx)112*5e54f6d4SAugustin Cavalier process_command(context *ctx)
113*5e54f6d4SAugustin Cavalier {
114*5e54f6d4SAugustin Cavalier 	while (ctx->buffer[ctx->index] != '.') {
115*5e54f6d4SAugustin Cavalier 		ctx->index++;
116*5e54f6d4SAugustin Cavalier 
117*5e54f6d4SAugustin Cavalier 		switch (ctx->buffer[ctx->index - 1]) {
118*5e54f6d4SAugustin Cavalier 			case 'r':
119*5e54f6d4SAugustin Cavalier 				if (repeat(ctx) < 0)
120*5e54f6d4SAugustin Cavalier 					return -1;
121*5e54f6d4SAugustin Cavalier 				break;
122*5e54f6d4SAugustin Cavalier 
123*5e54f6d4SAugustin Cavalier 			case 'b':
124*5e54f6d4SAugustin Cavalier 				send_packet(ctx, 1);
125*5e54f6d4SAugustin Cavalier 				break;
126*5e54f6d4SAugustin Cavalier 
127*5e54f6d4SAugustin Cavalier 			case 'p':
128*5e54f6d4SAugustin Cavalier 				send_packet(ctx, value(ctx));
129*5e54f6d4SAugustin Cavalier 				break;
130*5e54f6d4SAugustin Cavalier 
131*5e54f6d4SAugustin Cavalier 			case 's':
132*5e54f6d4SAugustin Cavalier 				usleep(value(ctx) * 1000);
133*5e54f6d4SAugustin Cavalier 				break;
134*5e54f6d4SAugustin Cavalier 
135*5e54f6d4SAugustin Cavalier 			case 'W':
136*5e54f6d4SAugustin Cavalier 			{
137*5e54f6d4SAugustin Cavalier 				int value = number(ctx);
138*5e54f6d4SAugustin Cavalier 				setsockopt(ctx->sock, SOL_SOCKET, SO_SNDBUF, &value,
139*5e54f6d4SAugustin Cavalier 					sizeof(value));
140*5e54f6d4SAugustin Cavalier 				break;
141*5e54f6d4SAugustin Cavalier 			}
142*5e54f6d4SAugustin Cavalier 
143*5e54f6d4SAugustin Cavalier 			case 'k':
144*5e54f6d4SAugustin Cavalier 				return -1;
145*5e54f6d4SAugustin Cavalier 		}
146*5e54f6d4SAugustin Cavalier 	}
147*5e54f6d4SAugustin Cavalier 
148*5e54f6d4SAugustin Cavalier 	return 0;
149*5e54f6d4SAugustin Cavalier }
150*5e54f6d4SAugustin Cavalier 
151*5e54f6d4SAugustin Cavalier 
152*5e54f6d4SAugustin Cavalier static int
read_command(context * ctx)153*5e54f6d4SAugustin Cavalier read_command(context *ctx)
154*5e54f6d4SAugustin Cavalier {
155*5e54f6d4SAugustin Cavalier 	int index = 0;
156*5e54f6d4SAugustin Cavalier 
157*5e54f6d4SAugustin Cavalier 	do {
158*5e54f6d4SAugustin Cavalier 		int size = recv(ctx->sock, ctx->buffer + index, 1, 0);
159*5e54f6d4SAugustin Cavalier 		if (size == 0)
160*5e54f6d4SAugustin Cavalier 			return -1;
161*5e54f6d4SAugustin Cavalier 		else if (size < 0)
162*5e54f6d4SAugustin Cavalier 			continue;
163*5e54f6d4SAugustin Cavalier 
164*5e54f6d4SAugustin Cavalier 		index++;
165*5e54f6d4SAugustin Cavalier 	} while (ctx->buffer[index - 1] != '.');
166*5e54f6d4SAugustin Cavalier 
167*5e54f6d4SAugustin Cavalier 	ctx->index = 0;
168*5e54f6d4SAugustin Cavalier 	return process_command(ctx);
169*5e54f6d4SAugustin Cavalier }
170*5e54f6d4SAugustin Cavalier 
171*5e54f6d4SAugustin Cavalier 
172*5e54f6d4SAugustin Cavalier static int32
handle_client(void * data)173*5e54f6d4SAugustin Cavalier handle_client(void *data)
174*5e54f6d4SAugustin Cavalier {
175*5e54f6d4SAugustin Cavalier 	context ctx = { *(int *)data, 0 };
176*5e54f6d4SAugustin Cavalier 
177*5e54f6d4SAugustin Cavalier 	while (read_command(&ctx) == 0);
178*5e54f6d4SAugustin Cavalier 
179*5e54f6d4SAugustin Cavalier 	fprintf(stderr, "Client %d leaving.\n", ctx.sock);
180*5e54f6d4SAugustin Cavalier 
181*5e54f6d4SAugustin Cavalier 	close(ctx.sock);
182*5e54f6d4SAugustin Cavalier 
183*5e54f6d4SAugustin Cavalier 	return 0;
184*5e54f6d4SAugustin Cavalier }
185*5e54f6d4SAugustin Cavalier 
186*5e54f6d4SAugustin Cavalier 
187*5e54f6d4SAugustin Cavalier int
main(int argc,char * argv[])188*5e54f6d4SAugustin Cavalier main(int argc, char *argv[])
189*5e54f6d4SAugustin Cavalier {
190*5e54f6d4SAugustin Cavalier 	int port = 12345;
191*5e54f6d4SAugustin Cavalier 
192*5e54f6d4SAugustin Cavalier 	for (int i = 1; i < argc; i++) {
193*5e54f6d4SAugustin Cavalier 		if (!strcmp(argv[i], "-p")) {
194*5e54f6d4SAugustin Cavalier 			i++;
195*5e54f6d4SAugustin Cavalier 			assert(i < argc);
196*5e54f6d4SAugustin Cavalier 			port = atoi(argv[i]);
197*5e54f6d4SAugustin Cavalier 		} else if (!strcmp(argv[i], "-h")) {
198*5e54f6d4SAugustin Cavalier 			fprintf(stderr, "tcptester [-p port]\n");
199*5e54f6d4SAugustin Cavalier 			return 1;
200*5e54f6d4SAugustin Cavalier 		}
201*5e54f6d4SAugustin Cavalier 	}
202*5e54f6d4SAugustin Cavalier 
203*5e54f6d4SAugustin Cavalier 	int sock = socket(AF_INET, SOCK_STREAM, 0);
204*5e54f6d4SAugustin Cavalier 
205*5e54f6d4SAugustin Cavalier 	if (sock < 0) {
206*5e54f6d4SAugustin Cavalier 		perror("socket()");
207*5e54f6d4SAugustin Cavalier 		return -1;
208*5e54f6d4SAugustin Cavalier 	}
209*5e54f6d4SAugustin Cavalier 
210*5e54f6d4SAugustin Cavalier 	sockaddr_in sin;
211*5e54f6d4SAugustin Cavalier 	memset(&sin, 0, sizeof(sin));
212*5e54f6d4SAugustin Cavalier 	sin.sin_family = AF_INET;
213*5e54f6d4SAugustin Cavalier 	sin.sin_port = htons(port);
214*5e54f6d4SAugustin Cavalier 
215*5e54f6d4SAugustin Cavalier 	if (bind(sock, (sockaddr *)&sin, sizeof(sockaddr_in)) < 0) {
216*5e54f6d4SAugustin Cavalier 		perror("bind()");
217*5e54f6d4SAugustin Cavalier 		return -1;
218*5e54f6d4SAugustin Cavalier 	}
219*5e54f6d4SAugustin Cavalier 
220*5e54f6d4SAugustin Cavalier 	if (listen(sock, 5) < 0) {
221*5e54f6d4SAugustin Cavalier 		perror("listen()");
222*5e54f6d4SAugustin Cavalier 		return -1;
223*5e54f6d4SAugustin Cavalier 	}
224*5e54f6d4SAugustin Cavalier 
225*5e54f6d4SAugustin Cavalier 	while (1) {
226*5e54f6d4SAugustin Cavalier 		sockaddr_in peer;
227*5e54f6d4SAugustin Cavalier 		socklen_t peerLen = sizeof(peer);
228*5e54f6d4SAugustin Cavalier 
229*5e54f6d4SAugustin Cavalier 		int newSock = accept(sock, (sockaddr *)&peer, &peerLen);
230*5e54f6d4SAugustin Cavalier 		if (newSock < 0) {
231*5e54f6d4SAugustin Cavalier 			perror("accept()");
232*5e54f6d4SAugustin Cavalier 			return -1;
233*5e54f6d4SAugustin Cavalier 		}
234*5e54f6d4SAugustin Cavalier 
235*5e54f6d4SAugustin Cavalier 		char buf[64];
236*5e54f6d4SAugustin Cavalier 		inet_ntop(AF_INET, &peer.sin_addr, buf, sizeof(buf));
237*5e54f6d4SAugustin Cavalier 
238*5e54f6d4SAugustin Cavalier 		thread_id newThread = spawn_thread(handle_client, "client",
239*5e54f6d4SAugustin Cavalier 			B_NORMAL_PRIORITY, &newSock);
240*5e54f6d4SAugustin Cavalier 
241*5e54f6d4SAugustin Cavalier 		fprintf(stderr, "New client %d from %s with thread id %ld.\n",
242*5e54f6d4SAugustin Cavalier 			newSock, buf, (int32)newThread);
243*5e54f6d4SAugustin Cavalier 
244*5e54f6d4SAugustin Cavalier 		resume_thread(newThread);
245*5e54f6d4SAugustin Cavalier 	}
246*5e54f6d4SAugustin Cavalier 
247*5e54f6d4SAugustin Cavalier 	return 0;
248*5e54f6d4SAugustin Cavalier }
249*5e54f6d4SAugustin Cavalier 
250