#!/usr/bin/perl # file: razor-caching-proxy.pl # usage: razor-caching-proxy.pl [listening_port] # #Copyright 2002 William Stearns #Released under the GPL. use strict; use IO::Socket qw(:DEFAULT :crlf); use Socket; use IO::Handle; use IO::File; use constant DEFAULT_RAZOR_PORT => 2702; use constant DEFAULT_CACHE_FILE => '/tmp/razor-cache'; use constant CACHE_DEBUG => 1; use constant VERBOSE_CACHE_DEBUG =>0; my $CACHE_VERSION='0.0.1'; $/ = CRLF; my ($server_bytes_out, $server_bytes_in, $client_bytes_in, $client_bytes_out) = (0,0,0,0); my $quit = 0; $SIG{INT} = sub { $quit++ }; my %responses = ( "version" => "Razor Caching Server live, version $CACHE_VERSION.", "key:d97b1764b257f4f67a7d7fc9e6988aace12c5a56&action:lookup" => "Positive d97b1764b257f4f67a7d7fc9e6988aace12c5a56" ); my $real_razor_server; my $real_razor_servername; my $real_razor_server_port; my $cache_file=DEFAULT_CACHE_FILE; my $cache_query; my $cache_response; my $cache_fh; if ($cache_fh = IO::File->new($cache_file, O_RDONLY|O_CREAT)) { undef $!; while (defined(my $cache_line = <$cache_fh>)) { chomp $cache_line; #process cache line ($cache_query, $cache_response) = split(/\s+/, $cache_line, 2); if (VERBOSE_CACHE_DEBUG) { warn "Loaded $cache_query , $cache_response.\n"; } $responses{$cache_query} = $cache_response; } close $cache_file } elsif (CACHE_DEBUG) { warn "Local cache file $cache_file unavailable: $!"; } #Set up client connection to the real razor server first so if that fails we don't even set ourselves up as a proxy. if (CACHE_DEBUG) { #testing only $real_razor_servername = "localhost"; $real_razor_server_port = 7; } else { $real_razor_servername = "b.razor.vipul.net."; $real_razor_server_port = DEFAULT_RAZOR_PORT; } my $protocol = getprotobyname('tcp'); $real_razor_server = inet_aton($real_razor_servername) or die "Can't lookup the IP address of $real_razor_servername"; socket(SOCK, AF_INET, SOCK_STREAM, $protocol) or die "client socket creation error: $!"; my $dest_addr = sockaddr_in($real_razor_server_port, $real_razor_server); connect(SOCK,$dest_addr) or die "Connection to real server failed: $!"; SOCK->autoflush(1); if (CACHE_DEBUG) { warn "Connected to $real_razor_servername:$real_razor_server_port.\n"; } #Now start setting up the server port. my $port = shift || DEFAULT_RAZOR_PORT; my $server_sock = IO::Socket::INET->new( Listen => 20, LocalPort => $port, Timeout => 60*60, Reuse => 1) or die "Can't create listening socket: $!\n"; if (CACHE_DEBUG) { warn "Waiting for incoming connections on port $port...\n"; } while (!$quit) { next unless my $session = $server_sock->accept; my $peer = gethostbyaddr($session->peeraddr,AF_INET) || $session->peerhost; my $port = $session->peerport; if (CACHE_DEBUG) { warn "Connection from [$peer,$port]\n"; } print $session "Vipul's Razor Cache $CACHE_VERSION, protocol version 2." . CRLF; while (my $client_query=<$session>) { my $response; $server_bytes_in += length($client_query); chomp $client_query; if ($client_query eq '.') { #Do nothing, end of arguments } elsif (defined $responses{$client_query}) { if (CACHE_DEBUG) { warn "Cached response to $client_query.\n"; } $response = "$responses{$client_query}" . CRLF; print $session $response; $server_bytes_out += length($response); } else { if (CACHE_DEBUG) { warn "Live response to $client_query.\n"; } #$msg_out = "$client_query Unknown" . CRLF; $client_bytes_out += length($client_query); print SOCK $client_query . CRLF; $response=; chomp $response; $responses{$client_query} = $response; $response .= CRLF; print $session $response; $server_bytes_out += length($response); #Save for later reference if ($cache_fh = IO::File->new(">>$cache_file")) { $cache_fh->autoflush(1); print $cache_fh "$client_query $response"; close $cache_file; if (VERBOSE_CACHE_DEBUG) { chomp $response; warn "stored >$client_query<, >$response< in cache file.\n"; } } } } if (CACHE_DEBUG) { warn "Connection from [$peer,$port] finished.\n"; } close $session; } print STDERR "client_bytes_sent = $client_bytes_out, client_bytes_received = $client_bytes_in, server_bytes_sent = $server_bytes_out, server_bytes_received = $server_bytes_in.\n"; close $server_sock; close SOCK