remove any leading ::ffff: on ipv4 addresses
[spider.git] / perl / Msg.pm
index bad84a2c4f2277d7b117999f5fbe7e55e6aa9a16..f3642d59b79dfabd3bbe0b7f00e7d514421981ba 100644 (file)
@@ -20,7 +20,7 @@ use Mojo::IOLoop::Stream;
 use DXDebug;
 use Timer;
 
-use vars qw($now %conns $noconns $cnum $total_in $total_out $connect_timeout);
+use vars qw($now %conns $noconns $cnum $total_in $total_out $connect_timeout $disc_waittime);
 
 $total_in = $total_out = 0;
 
@@ -28,6 +28,9 @@ $now = time;
 
 $cnum = 0;
 $connect_timeout = 5;
+$disc_waittime = 3;
+
+our %delqueue;
 
 #
 #-----------------------------------------------------------------
@@ -120,9 +123,11 @@ sub ax25
 sub peerhost
 {
        my $conn = shift;
-       $conn->{peerhost} ||= 'ax25' if $conn->ax25;
-       $conn->{peerhost} ||= $conn->{sock}->handle->peerhost if $conn->{sock};
-       $conn->{peerhost} ||= 'UNKNOWN';
+       unless ($conn->{peerhost}) {
+               $conn->{peerhost} ||= 'ax25' if $conn->ax25;
+               $conn->{peerhost} ||= $conn->{sock}->handle->peerhost if $conn->{sock};
+               $conn->{peerhost} ||= 'UNKNOWN';
+       }
        return $conn->{peerhost};
 }
 
@@ -136,8 +141,8 @@ sub _on_connect
        undef $conn->{sock};
        my $sock = $conn->{sock} = Mojo::IOLoop::Stream->new($handle);
        $sock->on(read => sub {$conn->_rcv($_[1]);} );
-       $sock->on(error => sub {$conn->disconnect;});
-       $sock->on(close => sub {$conn->disconnect;});
+       $sock->on(error => sub {delete $conn->{sock}; $conn->disconnect;});
+       $sock->on(close => sub {delete $conn->{sock}; $conn->disconnect;});
        $sock->timeout(0);
        $sock->start;
        $conn->{peerhost} = eval { $handle->peerhost; };
@@ -172,9 +177,18 @@ sub connect {
        
        my $sock;
        $conn->{sock} = $sock = Mojo::IOLoop::Client->new;
-       $sock->on(connect => sub {$conn->_on_connect($_[1])} );
-       $sock->on(error => sub {&{$conn->{eproc}}($conn, $_[1]) if exists $conn->{eproc}; $conn->disconnect});
-       $sock->on(close => sub {$conn->disconnect});
+       $sock->on(connect => sub {
+                                 $conn->_on_connect($_[1])
+                         } );
+       $sock->on(error => sub {
+                                 &{$conn->{eproc}}($conn, $_[1]) if exists $conn->{eproc};
+                                 delete $conn->{sock};
+                                 $conn->disconnect
+                         });
+       $sock->on(close => sub {
+                                 delete $conn->{sock};
+                                 $conn->disconnect}
+                        );
 
        # copy any args like on_connect, on_disconnect etc
        while (my ($k, $v) = each %args) {
@@ -235,16 +249,22 @@ sub start_program
        return $pid;
 }
 
-sub disconnect 
+sub disconnect
 {
-    my $conn = shift;
-       return if exists $conn->{disconnecting};
-
-       $conn->{disconnecting} = 1;
-    my $sock = delete $conn->{sock};
-       $conn->{state} = 'E';
-       $conn->{timeout}->del if $conn->{timeout};
+       my $conn = shift;
+       my $count = $conn->{disconnecting}++;
+       my $dbg = isdbg('connll');
+       my ($pkg, $fn, $line) = caller if $dbg;
+
+       if ($count >= 2) {
+               dbg((ref $conn) . "::disconnect on call $conn->{call} attempt $conn->{disconnecting} called from ${pkg}::${fn} line $line FORCING CLOSE ") if $dbg;
+               _close_it($conn);
+               return;
+       }
+       dbg((ref $conn) . "::disconnect on call $conn->{call} attempt $conn->{disconnecting} called from ${pkg}::${fn} line $line ") if $dbg;
+       return if $count;
 
+       # remove this conn from the active queue
        # be careful to delete the correct one
        my $call;
        if ($call = $conn->{call}) {
@@ -252,12 +272,67 @@ sub disconnect
                delete $conns{$call} if $ref && $ref == $conn;
        }
        $call ||= 'unallocated';
-       dbg((ref $conn) . " Connection $conn->{cnum} $call disconnected") if isdbg('connll');
+
+       $delqueue{$conn} = $conn; # save this connection until everything is finished
+       my $sock = $conn->{sock};
+       if ($sock) {
+
+               # remove me from the active list
+               my $call;
+               if ($call = $conn->{call}) {
+                       my $ref = $conns{$call};
+                       delete $conns{$call} if $ref && $ref == $conn;
+               }
+
+               $conn->{delay} = Mojo::IOLoop->delay (
+#                               Mojo::IOLoop->delay (
+                                                                                         sub {
+                                                                                                 my $delay = shift;
+                                                                                                 dbg("before drain $call") if $dbg;
+                                                                                                 $sock->on(drain => $delay->begin);
+                                                                                                 1;
+                                                                                         },
+                                                                                         sub {
+                                                                                                 my $delay = shift;
+                                                                                                 dbg("before _close_it $call") if $dbg;
+                                                                                                 _close_it($conn);
+                                                                                                 1;
+                                                                                         }
+                                                                                        );
+               $conn->{delay}->wait;
+
+       } else {
+               dbg((ref $conn) . " socket missing on $conn->{call}") if $dbg;
+               _close_it($conn);
+       }
+}
+
+sub _close_it
+{
+    my $conn = shift;
+    my $sock = delete $conn->{sock};
+       $conn->{state} = 'E';
+       $conn->{timeout}->del if $conn->{timeout};
+
+       my $call = $conn->{call};
+
+       if (isdbg('connll')) {
+               my ($pkg, $fn, $line) = caller;
+               dbg((ref $conn) . "::_close_it on call $conn->{call} attempt $conn->{disconnecting} called from ${pkg}::${fn} line $line ");
+       }
+
+
+       dbg((ref $conn) . " Connection $conn->{cnum} $call starting to close") if isdbg('connll');
        
        if ($conn->{on_disconnect}) {
                &{$conn->{on_disconnect}}($conn);
        }
 
+       if ($sock) {
+               dbg((ref $conn) . " Connection $conn->{cnum} $call closing gracefully") if isdbg('connll');
+               $sock->close_gracefully;
+       }
+       
        # get rid of any references
        for (keys %$conn) {
                if (ref($conn->{$_})) {
@@ -265,8 +340,7 @@ sub disconnect
                }
        }
 
-       $sock->close_gracefully if defined $sock && $sock->can('close_gracefully');
-       undef $sock;
+       delete $delqueue{$conn};        # finally remove the $conn
        
        unless ($main::is_win) {
                kill 'TERM', $conn->{pid} if exists $conn->{pid};
@@ -423,9 +497,11 @@ sub new_client {
        $sock->on(read => sub {$conn->_rcv($_[1])});
        $sock->timeout(0);
        $sock->start;
-       dbg((ref $conn) . "accept $conn->{cnum} from $conn->{peerhost} $conn->{peerport}") if isdbg('connll');
-
-       my ($rproc, $eproc) = &{$server_conn->{rproc}} ($conn, $conn->{peerhost} = $handle->peerhost, $conn->{peerport} = $handle->peerport);
+       $conn->{peerhost} = $handle->peerhost;
+       $conn->{peerhost} =~ s|^::ffff:||; # chop off leading pseudo IPV6 stuff on dual stack listeners
+       $conn->{peerport} = $handle->peerport;
+       dbg((ref $conn) . " accept $conn->{cnum} from $conn->{peerhost}:$conn->{peerport}") if isdbg('connll');
+       my ($rproc, $eproc) = &{$server_conn->{rproc}} ($conn, $conn->{peerhost}, $conn->{peerport});
        $conn->{sort} = 'Incoming';
        if ($eproc) {
                $conn->{eproc} = $eproc;
@@ -488,12 +564,22 @@ sub sleep
 sub DESTROY
 {
        my $conn = shift;
+       my $call = $conn->{call} || 'unallocated';
+
+       if (isdbg('connll')) {
+               my ($pkg, $fn, $line) = caller;
+               dbg((ref $conn) . "::DESTROY on call $call called from ${pkg}::${fn} line $line ");
+               
+       }
+
        my $call = $conn->{call} || 'unallocated';
        my $host = $conn->{peerhost} || '';
        my $port = $conn->{peerport} || '';
        my $sock = $conn->{sock};
 
-       $sock->close_gracefully if defined $sock && $sock->can('close_gracefully');
+       if ($sock) {
+               $sock->close_gracefully;
+       }
        
        $noconns--;
        dbg((ref $conn) . " Connection $conn->{cnum} $call [$host $port] being destroyed (total $noconns)") if isdbg('connll');