eval {
require Errno; Errno->import(qw(EAGAIN EINPROGRESS EWOULDBLOCK));
};
+ # http://support.microsoft.com/support/kb/articles/Q150/5/37.asp
+ # defines EINPROGRESS as 10035. We provide it here because some
+ # Win32 users report POSIX::EINPROGRESS is not vendor-supported.
+ if ($^O eq 'MSWin32') {
+ eval '*EINPROGRESS = sub { 10036 };';
+ eval '*EWOULDBLOCK = *EAGAIN = sub { 10035 };';
+ $blocking_supported = 1;
+ }
}
my $w = $^W;
sub blocking
{
return unless $blocking_supported;
+
+ # Make the handle stop blocking, the Windows way.
+ if ($main::iswin) {
+ # 126 is FIONBIO (some docs say 0x7F << 16)
+ ioctl( $_[0],
+ 0x80000000 | (4 << 16) | (ord('f') << 8) | 126,
+ "$_[1]"
+ );
+ }
my $flags = fcntl ($_[0], F_GETFL, 0);
if ($_[1]) {
$call ||= 'unallocated';
dbg("Connection $conn->{cnum} $call disconnected") if isdbg('connll');
- unless ($main::is_win) {
- kill 'TERM', $conn->{pid} if exists $conn->{pid};
- }
-
# get rid of any references
for (keys %$conn) {
if (ref($conn->{$_})) {
}
}
- return unless defined($sock);
- set_event_handler ($sock, read => undef, write => undef, error => undef);
- shutdown($sock, 3);
- close($sock);
+ if (defined($sock)) {
+ set_event_handler ($sock, read => undef, write => undef, error => undef);
+ shutdown($sock, 3);
+ close($sock);
+ }
+
+ unless ($main::is_win) {
+ kill 'TERM', $conn->{pid} if exists $conn->{pid};
+ }
+
}
sub send_now {
my $self = $pkg->new($login_proc);
$self->{sock} = IO::Socket::INET->new (
- LocalAddr => $my_host,
- LocalPort => $my_port,
+ LocalAddr => "$my_host:$my_port",
+# LocalPort => $my_port,
Listen => SOMAXCONN,
Proto => 'tcp',
- Reuse => 1);
+ Reuse => 1);
die "Could not create socket: $! \n" unless $self->{sock};
set_event_handler ($self->{sock}, read => sub { $self->new_client } );
return $self;
}
+my $oldw = $^W;
+$^W = 0;
+eval "use Socket qw(IPPROTO_TCP TCP_NODELAY)";
+$^W = $oldw;
+if ($@ && !$main::inwin) {
+ sub IPPROTO_TCP {6;}
+ sub TCP_NODELAY {1;};
+}
+
+sub nolinger
+{
+ my $conn = shift;
+
+ if (isdbg('sock')) {
+ my ($l, $t) = unpack "ll", getsockopt($conn->{sock}, SOL_SOCKET, SO_LINGER);
+ my $k = unpack 'l', getsockopt($conn->{sock}, SOL_SOCKET, SO_KEEPALIVE);
+ my $n = unpack "l", getsockopt($conn->{sock}, IPPROTO_TCP, TCP_NODELAY);
+ dbg("Linger is: $l $t, keepalive: $k, nagle: $n");
+ }
+
+ setsockopt($conn->{sock}, SOL_SOCKET, SO_LINGER, pack("ll", 0, 0)) or confess "setsockopt linger: $!";
+ setsockopt($conn->{sock}, SOL_SOCKET, SO_KEEPALIVE, 1) or confess "setsockopt keepalive: $!";
+ setsockopt($conn->{sock}, IPPROTO_TCP, TCP_NODELAY, 1) or confess "setsockopt: $!" unless $main::iswin;
+ $conn->{sock}->autoflush(0);
+
+ if (isdbg('sock')) {
+ my ($l, $t) = unpack "ll", getsockopt($conn->{sock}, SOL_SOCKET, SO_LINGER);
+ my $k = unpack 'l', getsockopt($conn->{sock}, SOL_SOCKET, SO_KEEPALIVE);
+ my $n = unpack "l", getsockopt($conn->{sock}, IPPROTO_TCP, TCP_NODELAY);
+ dbg("Linger is: $l $t, keepalive: $k, nagle: $n");
+ }
+}
+
sub dequeue
{
my $conn = shift;
$bytes_read = sysread ($sock, $msg, 1024, 0);
if (defined ($bytes_read)) {
if ($bytes_read > 0) {
- $conn->{msg} .= $msg;
if (isdbg('raw')) {
my $call = $conn->{call} || 'none';
dbgdump('raw', "$call read $bytes_read: ", $msg);
}
+ if ($conn->{echo}) {
+ my @ch = split //, $msg;
+ my $out;
+ for (@ch) {
+ if (/[\cH\x7f]/) {
+ $out .= "\cH \cH";
+ $conn->{msg} =~ s/.$//;
+ } else {
+ $out .= $_;
+ $conn->{msg} .= $_;
+ }
+ }
+ if (defined $out) {
+ set_event_handler ($sock, write => sub{$conn->_send(0)});
+ push @{$conn->{outqueue}}, $out;
+ }
+ } else {
+ $conn->{msg} .= $msg;
+ }
}
} else {
if (_err_will_block($!)) {
my $conn = $server_conn->new($server_conn->{rproc});
$conn->{sock} = $sock;
blocking($sock, 0);
+ $conn->nolinger;
$conn->{blocking} = 0;
my ($rproc, $eproc) = &{$server_conn->{rproc}} ($conn, $conn->{peerhost} = $sock->peerhost(), $conn->{peerport} = $sock->peerport());
$conn->{sort} = 'Incoming';