#!/usr/bin/perl -w # sanada2.pl - Don Yang (uguu.org) # # 11/26/03 use strict; use Socket; local (*SERVER, *CLIENT, *FILE); my ($Name, $Port, $Type, $Size, $HEADER, $EOL); my ($rin, $rout, $i, $j); 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)"); Text("listening 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 $!; $i = 0; $j = $Size - 1; if( $rin =~ /\s+user-agent:\s*([^\r\n]+)/i ) { Text("agent=$1"); } if( $rin =~ /\s+referer:\s*([^\r\n]+)/i ) { Text("referer=$1"); } if( $rin =~ /\s+range:\s*bytes=(\d+)-(\d+)/i ) { $i = $1; $j = $2; } elsif( $rin =~ /\s+range:\s*bytes=(\d+)-/i ) { $i = $1; } elsif( $rin =~ /\s+range:\s*bytes=-(\d+)/i ) { $i = $Size - $1; } # Header if( $i >= $Size || $j >= $Size || $j < $i ) { $rout = "HTTP/1.1 416 Requested Range Not Satisfiable$EOL" . "Content-Range: bytes */$Size$EOL"; $Type = 0; } else { if( $i > 0 || $j < $Size - 1 ) { $rout = "HTTP/1.1 206 Partial Content$EOL" . "Content-Range: bytes $i-$j/$Size$EOL"; } else { $rout = "HTTP/1.1 200 OK$EOL"; } $rout .= "Content-Length: " . ($j - $i + 1) . $EOL; $Type = 1; } $rout .= $HEADER; send(CLIENT, $rout, 0) || die $!; if( $Type && ($rin =~ /^GET /) ) { $Type = 0; open(FILE, "< $Name"); $j++; for(seek(FILE, $i, 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); $Type = "~" . $Type if( $i < $j ); Text("sent $Type bytes"); } shutdown(CLIENT, 2); close(CLIENT); exit(0); } } } die "$!\n";