1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
|
#!/usr/bin/env perl
use strict;
use warnings;
use File::Basename;
use lib dirname (__FILE__);
use TestUtils;
use IO::Socket;
use Socket;
use POSIX qw(:sys_wait_h);
use File::Temp;
sub proxy {
my $config = shift;
exec(@_, '../src/sniproxy', '-f', '-c', $config);
}
sub simple_server($) {
my $port = shift;
my $server = IO::Socket::INET->new(LocalPort => $port,
Type => SOCK_STREAM,
Reuse => 1,
Listen => 10)
or die "listen: $!";
while (my $client = $server->accept()) {
my $pid = fork();
next if $pid; # Parent
die "fork: $!" unless defined $pid;
$server->close();
while (my $line = <$client>) {
last if $line eq "\r\n"; # End of headers
}
$client->send("HTTP/1.1 200 OK\r\n" .
"Content-Type: text/plain\r\n" .
"Context-Length: 16777216\r\n" .
"\r\n");
# Send a bunch of data (more that will be buffered by the kernel
for (my $i = 0; $i < 4096; $i++) {
$client->send('x' x 4096);
}
$client->close();
exit;
}
$server->close();
# Wait for children
1 until (-1 == waitpid(-1, WNOHANG));
exit(0);
}
sub bad_client($) {
my $port = shift;
my $socket = IO::Socket::INET->new(PeerAddr => '127.0.0.1',
PeerPort => $port,
Proto => "tcp",
Type => SOCK_STREAM)
or die "couldn't connect $!";
# This causes the socket to terminate abnormally and
# replicates the select invalid file descriptor error
kill 9, $$;
$socket->send("GET / HTTP/1.1\r\n" .
"UserAgent: bad_client/0.1\r\n" .
"Host: localhost:$port\r\n" .
"Accept: */*\r\n" .
"\r\n");
my $buffer;
$socket->recv($buffer, 4096);
$socket->recv($buffer, 4096);
$socket->recv($buffer, 4096);
$socket->close();
exit(0);
}
sub main {
my $proxy_port = $ENV{SNI_PROXY_PORT} || 8080;
my $httpd_port = $ENV{TEST_HTTPD_PORT} || 8081;
my $config = make_config($proxy_port, $httpd_port);
my $proxy_pid = start_child('sniproxy', \&proxy, $config, @ARGV);
my $httpd_pid = start_child('server', \&simple_server, $httpd_port);
# Wait for proxy to load and parse config
wait_for_port(port => $httpd_port);
wait_for_port(port => $proxy_port);
for (my $i = 0; $i < 10; $i++) {
start_child('worker', \&bad_client, $proxy_port);
}
# Wait for all our children to finish
wait_for_type('worker');
# Give the proxy a second to flush buffers and close server connections
sleep 1;
# For troubleshooting connections stuck in CLOSE_WAIT state
#kill 10, $proxy_pid;
#system("netstat -ptn | grep $proxy_pid\/sniproxy");
# For troubleshooting 100% CPU usage
#system("top -n 1 -p $proxy_pid -b");
# Orderly shutdown of the server
kill 15, $proxy_pid;
kill 15, $httpd_pid;
sleep 1;
# Delete our test configuration
unlink($config);
# Kill off any remaining children
reap_children();
}
main();
|