generalize command line parsing of connection_tester and add feature to serve corrupt pieces every now and then

This commit is contained in:
Arvid Norberg 2013-04-13 21:16:04 +00:00
parent 9e5edf3413
commit b5cf2e8439
1 changed files with 121 additions and 58 deletions

View File

@ -66,6 +66,10 @@ void generate_block(boost::uint32_t* buffer, int piece, int start, int length)
int local_if_counter = 0;
bool local_bind = false;
// if this is true, one block in 1000 will be sent corrupt.
// this only applies to dual and upload tests
bool test_corruption = false;
// number of seeds we've spawned. The test is terminated
// when this reaches zero, for dual tests
static boost::detail::atomic_count num_seeds(0);
@ -103,6 +107,7 @@ struct peer_conn
, num_pieces(num_pieces)
, start_time(time_now_hires())
{
corruption_counter = rand() % 1000;
if (seed) ++num_seeds;
pieces.reserve(num_pieces);
if (local_bind)
@ -134,6 +139,7 @@ struct peer_conn
boost::uint32_t write_buffer[17*1024/4];
boost::uint32_t buffer[17*1024/4];
int read_pos;
int corruption_counter;
enum state_t
{
@ -518,6 +524,16 @@ struct peer_conn
void write_piece(int piece, int start, int length)
{
generate_block(write_buffer, piece, start, length);
if (test_corruption)
{
--corruption_counter;
if (corruption_counter == 0)
{
corruption_counter = 1000;
memset(write_buffer, 0, 10);
}
}
char* ptr = write_buf_proto;
write_uint32(9 + length, ptr);
assert(length == 0x4000);
@ -543,34 +559,36 @@ struct peer_conn
void print_usage()
{
fprintf(stderr, "usage: connection_tester command ...\n\n"
fprintf(stderr, "usage: connection_tester command [options]\n\n"
"command is one of:\n"
" gen-torrent generate a test torrent\n"
" this command takes two extra arguments:\n"
" 1. the size of the torrent in megabytes\n"
" 2. the number of files in the test torrent\n"
" 3. the file to save the .torrent file to\n\n"
" gen-data generate the data file(s) for the test torrent\n"
" this command takes two extra arguments:\n"
" 1. the torrent file that was previously generated\n"
" 2. the path to where the data should be stored\n"
" gen-test-torrents generate many test torrents (cannot be used for up/down tests)\n"
" 1. number of torrents to generate\n"
" 2. number of files in each torrent\n"
" 3. base name of torrent files (index is appended)\n"
" upload start an uploader test\n"
" download start a downloader test\n"
" dual start a download and upload test\n"
" these commands set takes 4 additional arguments:\n"
" 1. num-connections - the number of connections to make to the target\n"
" 2. destination-IP - the IP address of the target\n"
" 3. destination-port - the port the target listens on\n"
" 4. torrent-file - the torrent file previously generated by gen-torrent\n\n"
" gen-torrent generate a test torrent\n"
" options for this command:\n"
" -s <size> the size of the torrent in megabytes\n"
" -n <num-files> the number of files in the test torrent\n"
" -t <file> the file to save the .torrent file to\n\n"
" gen-data generate the data file(s) for the test torrent\n"
" options for this command:\n"
" -t <file> the torrent file that was previously generated\n"
" -P <path> the path to where the data should be stored\n\n"
" gen-test-torrents generate many test torrents (cannot be used for up/down tests)\n"
" options for this command:\n"
" -N <num-torrents> number of torrents to generate\n"
" -n <num-files> number of files in each torrent\n"
" -t <name> base name of torrent files (index is appended)\n\n"
" upload start an uploader test\n"
" download start a downloader test\n"
" dual start a download and upload test\n"
" options for these commands:\n"
" -c <num-conns> the number of connections to make to the target\n"
" -d <dst> the IP address of the target\n"
" -p <dst-port> the port the target listens on\n"
" -t <torrent-file> the torrent file previously generated by gen-torrent\n\n"
" -C send corrupt pieces sometimes (applies to upload and dual)\n\n"
"examples:\n\n"
"connection_tester gen-torrent 1024 4 test.torrent\n"
"connection_tester upload 200 127.0.0.1 6881 test.torrent\n"
"connection_tester download 200 127.0.0.1 6881 test.torrent\n"
"connection_tester dual 200 127.0.0.1 6881 test.torrent\n");
"connection_tester gen-torrent -s 1024 -n 4 -t test.torrent\n"
"connection_tester upload -c 200 -d 127.0.0.1 -p 6881 -t test.torrent\n"
"connection_tester download -c 200 -d 127.0.0.1 -p 6881 -t test.torrent\n"
"connection_tester dual -c 200 -d 127.0.0.1 -p 6881 -t test.torrent\n");
exit(1);
}
@ -662,55 +680,101 @@ int main(int argc, char* argv[])
{
if (argc <= 1) print_usage();
if (strcmp(argv[1], "gen-torrent") == 0)
{
if (argc != 5) print_usage();
char const* command = argv[1];
int size = 1000;
int num_files = 10;
int num_torrents = 1;
char const* torrent_file = "benchmark.torrent";
char const* data_path = ".";
int num_connections = 50;
char const* destination_ip = "127.0.0.1";
int destination_port = 6881;
int size = atoi(argv[2]);
int num_files = atoi(argv[3]);
argv += 2;
argc -= 2;
while (argc > 0)
{
char const* optname = argv[0];
++argv;
--argc;
if (optname[0] != '-' || strlen(optname) != 2)
{
fprintf(stderr, "unknown option: %s\n", optname);
continue;
}
// options with no arguments
switch (optname[1])
{
case 'C': test_corruption = true; continue;
}
if (argc == 0)
{
fprintf(stderr, "missing argument for option: %s\n", optname);
break;
}
char const* optarg = argv[0];
++argv;
--argc;
switch (optname[1])
{
case 's': size = atoi(optarg); break;
case 'n': num_files = atoi(optarg); break;
case 'N': num_torrents = atoi(optarg); break;
case 't': torrent_file = optarg; break;
case 'P': data_path = optarg; break;
case 'c': num_connections = atoi(optarg); break;
case 'p': destination_port = atoi(optarg); break;
case 'd': destination_ip = optarg; break;
default: fprintf(stderr, "unknown option: %s\n", optname);
}
}
if (strcmp(command, "gen-torrent") == 0)
{
std::vector<char> tmp;
generate_torrent(tmp, size ? size : 1024, num_files ? num_files : 1);
FILE* output = stdout;
if (strcmp("-", argv[4]) != 0)
output = fopen(argv[4], "wb+");
if (strcmp("-", torrent_file) != 0)
output = fopen(torrent_file, "wb+");
fprintf(stderr, "writing file to: %s\n", torrent_file);
fwrite(&tmp[0], 1, tmp.size(), output);
if (output != stdout)
fclose(output);
return 0;
}
else if (strcmp(argv[1], "gen-data") == 0)
else if (strcmp(command, "gen-data") == 0)
{
if (argc != 4) print_usage();
error_code ec;
torrent_info ti(argv[2], ec);
torrent_info ti(torrent_file, ec);
if (ec)
{
fprintf(stderr, "ERROR LOADING .TORRENT: %s\n", ec.message().c_str());
return 1;
}
generate_data(argv[3], ti.num_pieces(), ti.piece_length());
generate_data(data_path, ti.num_pieces(), ti.piece_length());
return 0;
}
else if (strcmp(argv[1], "gen-test-torrents") == 0)
else if (strcmp(command, "gen-test-torrents") == 0)
{
if (argc != 5) print_usage();
int num_torrents = atoi(argv[2]);
int num_files = atoi(argv[3]);
char const* name = argv[4];
std::vector<char> buf;
for (int i = 0; i < num_torrents; ++i)
{
char torrent_name[100];
snprintf(torrent_name, sizeof(torrent_name), "%s-%d.torrent", name, i);
snprintf(torrent_name, sizeof(torrent_name), "%s-%d.torrent", torrent_file, i);
file_storage fs;
for (int j = 0; j < num_files; ++j)
{
char file_name[100];
snprintf(file_name, sizeof(file_name), "%s-%d/file-%d", name, i, j);
snprintf(file_name, sizeof(file_name), "%s-%d/file-%d", torrent_file, i, j);
fs.add_file(file_name, size_type(j + i + 1) * 251);
}
// 1 MiB piece size
@ -741,33 +805,32 @@ int main(int argc, char* argv[])
}
return 0;
}
else if (strcmp(argv[1], "upload") == 0)
else if (strcmp(command, "upload") == 0)
{
if (argc != 6) print_usage();
test_mode = upload_test;
}
else if (strcmp(argv[1], "download") == 0)
else if (strcmp(command, "download") == 0)
{
if (argc != 6) print_usage();
test_mode = download_test;
}
else if (strcmp(argv[1], "dual") == 0)
else if (strcmp(command, "dual") == 0)
{
if (argc != 6) print_usage();
test_mode = dual_test;
}
else print_usage();
else
{
fprintf(stderr, "unknown command: %s\n\n", command);
print_usage();
}
int num_connections = atoi(argv[2]);
error_code ec;
address_v4 addr = address_v4::from_string(argv[3], ec);
address_v4 addr = address_v4::from_string(destination_ip, ec);
if (ec)
{
fprintf(stderr, "ERROR RESOLVING %s: %s\n", argv[3], ec.message().c_str());
fprintf(stderr, "ERROR RESOLVING %s: %s\n", destination_ip, ec.message().c_str());
return 1;
}
int port = atoi(argv[4]);
tcp::endpoint ep(addr, port);
tcp::endpoint ep(addr, destination_port);
#if !defined __APPLE__
// apparently darwin doesn't seems to let you bind to
@ -779,7 +842,7 @@ int main(int argc, char* argv[])
}
#endif
torrent_info ti(argv[5], ec);
torrent_info ti(torrent_file, ec);
if (ec)
{
fprintf(stderr, "ERROR LOADING .TORRENT: %s\n", ec.message().c_str());