try to get around differences for TCP_NODELAY for perl 5_005 and below
[spider.git] / perl / Msg.pm
index 615feb1987e4a102def727f208d093107f63d85b..57880ed112f825f9d445a4bdf7397375f4ac0835 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,6 +117,17 @@ sub set_rproc
 sub blocking
 {
        return unless $blocking_supported;
+
+       # Make the handle stop blocking, the Windows way.
+       if ($^O eq 'MSWin32') { 
+        my $set_it = $_[1];
+               
+        # 126 is FIONBIO (some docs say 0x7F << 16)
+        ioctl( $_[0],
+               0x80000000 | (4 << 16) | (ord('f') << 8) | 126,
+               $set_it
+             ) or confess "Can't set the handle non-blocking: $!";
+       }
        
        my $flags = fcntl ($_[0], F_GETFL, 0);
        if ($_[1]) {
@@ -208,10 +227,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 +234,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 +365,46 @@ 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;
 }
 
+eval "use Socket qw(IPPROTO_TCP TCP_NODELAY)";
+if ($@) {
+       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;
@@ -436,6 +487,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';