/*
* A very simple controlable traffic generator for TCP testing.
*
* Copyright 2007, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Hugo Santos, hugosantos@gmail.com
*/
#include <OS.h>
#include <assert.h>
#include <ctype.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
struct context {
int sock;
uint8 generator;
int index;
int8_t buffer[256];
};
static int process_command(context *ctx);
static int
number(context *ctx)
{
int result = 0;
while (isdigit(ctx->buffer[ctx->index])) {
result *= 10;
result += ctx->buffer[ctx->index] - '0';
ctx->index++;
}
return result;
}
static int
value(context *ctx)
{
if (ctx->buffer[ctx->index] == '[') {
ctx->index++;
int upper, lower = number(ctx);
if (ctx->buffer[ctx->index] == ',') {
ctx->index++;
upper = number(ctx);
} else {
upper = lower + 50;
lower -= 50;
}
return lower + rand() % (upper - lower + 1);
}
return number(ctx);
}
static int
repeat(context *ctx)
{
int max, saved, count = number(ctx);
max = saved = ctx->index;
for (int i = 0; i < count; i++) {
ctx->index = saved;
if (process_command(ctx) < 0)
return -1;
if (ctx->index > max)
max = ctx->index;
}
ctx->index = max;
return 0;
}
static void
send_packet(context *ctx, size_t bytes)
{
uint8_t buffer[1024];
uint8_t *ptr = buffer;
if (bytes > sizeof(buffer))
ptr = new uint8_t[bytes];
for (size_t i = 0; i < bytes; i++) {
ptr[i] = ctx->generator + '0';
ctx->generator = (ctx->generator + 1) % 10;
}
send(ctx->sock, ptr, bytes, 0);
if (ptr != buffer)
delete [] ptr;
}
static int
process_command(context *ctx)
{
while (ctx->buffer[ctx->index] != '.') {
ctx->index++;
switch (ctx->buffer[ctx->index - 1]) {
case 'r':
if (repeat(ctx) < 0)
return -1;
break;
case 'b':
send_packet(ctx, 1);
break;
case 'p':
send_packet(ctx, value(ctx));
break;
case 's':
usleep(value(ctx) * 1000);
break;
case 'W':
{
int value = number(ctx);
setsockopt(ctx->sock, SOL_SOCKET, SO_SNDBUF, &value,
sizeof(value));
break;
}
case 'k':
return -1;
}
}
return 0;
}
static int
read_command(context *ctx)
{
int index = 0;
do {
int size = recv(ctx->sock, ctx->buffer + index, 1, 0);
if (size == 0)
return -1;
else if (size < 0)
continue;
index++;
} while (ctx->buffer[index - 1] != '.');
ctx->index = 0;
return process_command(ctx);
}
static int32
handle_client(void *data)
{
context ctx = { *(int *)data, 0 };
while (read_command(&ctx) == 0);
fprintf(stderr, "Client %d leaving.\n", ctx.sock);
close(ctx.sock);
return 0;
}
int
main(int argc, char *argv[])
{
int port = 12345;
for (int i = 1; i < argc; i++) {
if (!strcmp(argv[i], "-p")) {
i++;
assert(i < argc);
port = atoi(argv[i]);
} else if (!strcmp(argv[i], "-h")) {
fprintf(stderr, "tcptester [-p port]\n");
return 1;
}
}
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
perror("socket()");
return -1;
}
sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
if (bind(sock, (sockaddr *)&sin, sizeof(sockaddr_in)) < 0) {
perror("bind()");
return -1;
}
if (listen(sock, 5) < 0) {
perror("listen()");
return -1;
}
while (1) {
sockaddr_in peer;
socklen_t peerLen = sizeof(peer);
int newSock = accept(sock, (sockaddr *)&peer, &peerLen);
if (newSock < 0) {
perror("accept()");
return -1;
}
char buf[64];
inet_ntop(AF_INET, &peer.sin_addr, buf, sizeof(buf));
thread_id newThread = spawn_thread(handle_client, "client",
B_NORMAL_PRIORITY, &newSock);
fprintf(stderr, "New client %d from %s with thread id %ld.\n",
newSock, buf, (int32)newThread);
resume_thread(newThread);
}
return 0;
}
↑ V576 Incorrect format. Consider checking the fifth actual argument of the 'fprintf' function. The memsize type argument is expected.