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