yet more compatibilty fixes
[spider.git] / perl / Msg.pm
index 3f52e39dfe8057d4fb202f364be81eb36567ceb3..fdcc9fa00c5eef4472bec4f64ad74ac331c7ff12 100644 (file)
@@ -52,6 +52,14 @@ BEGIN {
        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;
@@ -109,14 +117,23 @@ sub set_rproc
 sub blocking
 {
        return unless $blocking_supported;
-       
-       my $flags = fcntl ($_[0], F_GETFL, 0);
-       if ($_[1]) {
-               $flags &= ~O_NONBLOCK;
+
+       # 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]"
+             );
        } else {
-               $flags |= O_NONBLOCK;
+               my $flags = fcntl ($_[0], F_GETFL, 0);
+               if ($_[1]) {
+                       $flags &= ~O_NONBLOCK;
+               } else {
+                       $flags |= O_NONBLOCK;
+               }
+               fcntl ($_[0], F_SETFL, $flags);
        }
-       fcntl ($_[0], F_SETFL, $flags);
 }
 
 # save it
@@ -208,10 +225,6 @@ sub disconnect {
        $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->{$_})) {
@@ -219,10 +232,16 @@ sub disconnect {
                }
        }
 
-       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 {
@@ -344,16 +363,49 @@ sub new_server {
        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;
@@ -386,11 +438,29 @@ sub _rcv {                     # Complement to _send
        $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($!)) {
@@ -418,6 +488,7 @@ sub new_client {
                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';