--- deliantra/server/ext/tcp.ext 2012/11/05 23:24:02 1.24 +++ deliantra/server/ext/tcp.ext 2012/11/06 01:25:48 1.25 @@ -9,23 +9,38 @@ CONF BIND_ADDRESSES = [[undef, 13327]]; -our $MAX_DETECT = 32; # how many bytes to read to identify the protocol +our $MAX_DETECT; # how many bytes to read to identify the protocol our @LISTENERS; +our @DETECTORS; +our %DETECTORS; -sub flash_policy_server { - my ($fh) = @_; +sub _update_detectors { + $MAX_DETECT = List::Util::max map $_->[1], values %DETECTORS; - # socket policy file, just write answer and hope the kernel accepts it in one go - syswrite $fh, < - - - - -EOF + use Data::Dump; + ddx [$MAX_DETECT, \%DETECTORS]; } +sub register($$$$) { + my ($name, $max_detect, $detect, $serve) = @_; + + $DETECTORS{$name} = [$max_detect, $detect, $serve]; + _update_detectors; + + Guard::guard { + delete $DETECTORS{$name}; + _update_detectors; + } +} + +our $deliantra_detector = ext::tcp::register deliantra => 10, sub { + /^..version /s +}, sub { + my $ns = cf::client::create fileno $_[1], $_[0]; + $ns->inbuf_append ($_[2]); +}; + for (@$BIND_ADDRESSES) { my ($host, $port) = @$_; cf::info "listening on ", (format_hostport $host, $port), "\n"; @@ -39,7 +54,7 @@ my $id = format_hostport $host, $port; - cf::info "$id: new connection\n" + cf::info "$id: accepted connection.\n" if $lhost ne $host; # do not log connections from the host, e.g. for watchdogs my $buf; @@ -47,31 +62,24 @@ my $len = sysread $fh, $buf, 512, length $buf; if ($len) { - if ($buf =~ /^..version /s) { # deliantra protocol - undef $w; - - my $ns = cf::client::create fileno $fh, $host; - $ns->inbuf_append ($buf); - - } elsif ($buf =~ /^GET / && defined &ext::http::server) { # http or websocket - undef $w; - - &ext::http::server ($id, $fh, $buf); - - } elsif ($buf =~ /^\x00/) { - undef $w; - - flash_policy_server $fh; - - } elsif (length $buf >= $MAX_DETECT) { # unable to detect protocol - undef $w; - - cf::info "$id: protocol detection error\n"; + for ($buf) { + while (my ($name, $v) = each %DETECTORS) { + if (my $cb = $v->[1]()) { + undef $w; + cf::debug "$id: detected protocol $name.\n"; + $v->[2]($id, $fh, $buf); + return; + } + } + + if (length >= $MAX_DETECT) { # unable to detect protocol + undef $w; + cf::debug "$id: data received, but cannot detect protocol, closing.\n"; + } } } else { undef $w; - - cf::info "$id: read error during protocol detection\n"; + cf::info "$id: read error during protocol detection ($!)\n"; } }; };