#!/usr/bin/perl -w # sanada3.pl - Don Yang (uguu.org) # # 11/26/03 use Socket; sub Text { print "$$: ", (scalar(localtime)), ": @_\n"; } die "$0 [port] [type]\n" unless( $#ARGV > -1 ); ($Name, $Port, $Type) = @ARGV; die "$Name is empty\n" unless( (-f $Name) && ($Size = -s $Name) > 0 ); $Port ||= 80; $Type ||= "application/octet-stream"; $EOL = "\r\n"; $HEADER = "Server: Sanada-san$EOL" . "Accept-Ranges: bytes$EOL" . "Content-Type: $Type$EOL" . "Connection: close$EOL$EOL"; $SIG{"CHLD"} = "IGNORE"; die "$!\n" unless( socket(SERVER, PF_INET, SOCK_STREAM, getprotobyname("tcp")) && bind(SERVER, sockaddr_in($Port, INADDR_ANY)) && listen(SERVER, 5) && binmode(SERVER)); $rin = ""; vec($rin, fileno(SERVER), 1) = 1; Text("serving $Name (type=$Type, size=$Size) on port $Port"); while( select($rout = $rin, undef, undef, undef) ) { if( vec($rout, fileno(SERVER), 1) ) { $j = accept(CLIENT, SERVER); ($j, $i) = sockaddr_in($j); $i = inet_ntoa($i); if( fork ) { close(CLIENT); } else { Text("request from $i:$j"); binmode(CLIENT); defined(recv(CLIENT, $rin, 1024, 0)) || die $!; Text("agent=$1") if( $rin =~ /\s+user-agent:\s*([^\r\n]+)/i ); Text("referer=$1") if( $rin =~ /\s+referer:\s*([^\r\n]+)/i ); $j = $Size - 1; ($i, $j) = ($rin =~ /\s+range:\s*bytes=(\d+)-(\d+)/i) ? ($1, $2) : ($rin =~ /\s+range:\s*bytes=(\d+)-/i) ? ($1, $j) : ($rin =~ /\s+range:\s*bytes=-(\d+)/i) ? ($Size - $1, $j) : (0, $j); $rout = ( ($i >= $Size || $j >= $Size || $j < $i) ? "HTTP/1.1 416 Requested Range Not Satisfiable$EOL" . "Content-Range: bytes */$Size$EOL" : ( ($i > 0 || $j < $Size - 1) ? "HTTP/1.1 206 Partial Content$EOL" . "Content-Range: bytes $i-$j/$Size$EOL" : "HTTP/1.1 200 OK$EOL" ) . "Content-Length: " . ($j - $i + 1) . $EOL ) . $HEADER; send(CLIENT, $rout, 0) || die $!; if( ($rout =~ /1\.1 20/) && ($rin =~ /^GET /) ) { open(FILE, "< $Name"); $j++; for(seek(FILE, $i, $Type = 0); $i < $j; $i += $Port) { if(($Port = $j - $i) > 0x4000) {$Port = 0x4000;} read(FILE, $rout, $Port); last unless defined(send(CLIENT, $rout, 0)); $Type += $Port; } close(FILE); if($i < $j) {$Type = "~$Type";} Text("sent $Type bytes"); } shutdown(CLIENT, 2); close(CLIENT); exit(0); } } } die "$!\n";