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