Author: bdonlan
Date: 2004-06-08 21:59:54 -0400 (Tue, 08 Jun 2004)
New Revision: 233
Modified:
trunk/main/client/lib/Haver/Client/POE.pm
Log:
Fix race where a client message before S: ACCEPT could cause a disconnect due
to a S: WANT being sent at the same time
Modified: trunk/main/client/lib/Haver/Client/POE.pm
===================================================================
--- trunk/main/client/lib/Haver/Client/POE.pm 2004-06-09 01:54:40 UTC (rev
232)
+++ trunk/main/client/lib/Haver/Client/POE.pm 2004-06-09 01:59:54 UTC (rev
233)
@@ -106,6 +106,7 @@
input
send_raw
send
+ _flush_msgq
net_error
destroy
@@ -269,6 +270,10 @@
$heap->{UID} = $args{UID};
$heap->{PASS} = $args{Password};
$heap->{Host} = $args{Host};
+ undef $heap->{want};
+ $heap->{enabled} = 1; # Set to 0 when graceful shutdown
begins, to block user input
+ $heap->{accepted} = 0; # Set to 1 when login is successful
+ $heap->{dead} = 0; # Set to 1 when the socket
fails, to drop messages
$args{Port} ||= 7070;
$heap->{connect_wheel} =
POE::Wheel::SocketFactory->new(
@@ -288,6 +293,7 @@
sub disconnect {
my ($kernel, $heap) = @_[KERNEL, HEAP];
+ $heap->{enabled} = 0;
return if $heap->{closing};
$heap->{closing} = 1;
if ($heap->{want}) {
@@ -351,37 +357,57 @@
sub send_raw {
my ($kernel, $heap, @message) = @_[KERNEL,HEAP,ARG0..$#_];
- return if ($heap->{want} && $heap->{want} eq "!impossible");
+ return if ($heap->{dead});
eval { $heap->{conn}->put([EMAIL PROTECTED]); };
if ($@) {
# Ack, lost connection unexpectedly!
# Hopefully we get net_error soon
- $heap->{want} = "!impossible";
+ $heap->{dead} = 1;
return;
}
_dprint 1, "C: ", join("\t", map { defined($_) ? $_ : '~UNDEF~' }
@message), "\n";
_call('dispatch', 'raw_out', @message);
+ $heap->{flushed} = 0;
}
sub send {
my ($kernel, $heap, @message) = @_[KERNEL,HEAP,ARG0..$#_];
- if ($heap->{want}) {
- if (($heap->{want} ne uc $message[0]) &&
- ((uc $message[0] ne 'CANT') || ($message[1] ne
$heap->{want}))) {
- _dprint 1, "(blocked) C: ", join("\t", @message), "\n";
- push @{$heap->{messageq} ||= []}, [EMAIL PROTECTED];
- return;
- }
- delete $heap->{want};
+ my $block = 0;
+
+ if (!$heap->{enabled}) {
+ $block = 1;
+ } elsif ($heap->{accepted} && !$heap->{want}) {
+ $block = 0;
+ } elsif (!$heap->{want}) {
+ # Before we get a S: ACCEPT we can't send anything not in
response to a S: WANT
+ $block = 1;
+ } elsif ($message[0] eq 'CANT') {
+ $block = ($message[1] ne $heap->{want});
+ } elsif ($message[0] ne $heap->{want}) {
+ $block = 1;
}
+
+ if ($block) {
+ _dprint 1, "(blocked) C: ", join("\t", @message), "\n";
+ push @{$heap->{messageq} ||= []}, [EMAIL PROTECTED];
+ return;
+ }
+
+ delete $heap->{want};
+
$kernel->yield('send_raw', @message);
+
+ $kernel->yield('_flush_msgq');
+}
+
+sub _flush_msgq {
+ my ($kernel, $heap) = @_[KERNEL,HEAP];
if (exists $heap->{messageq}) {
for (@{$heap->{messageq}}) {
$kernel->yield('send', @$_);
}
delete $heap->{messageq};
}
- $heap->{flushed} = 0;
}
### SERVER EVENTS
@@ -428,7 +454,9 @@
sub event_ACCEPT {
my ($kernel, $heap) = @_[KERNEL,HEAP];
$heap->{logged_in} = 1;
+ $heap->{accepted} = 1;
_call('dispatch', 'login');
+ $kernel->yield('_flush_msgq');
}
sub event_REJECT {
@@ -673,7 +701,7 @@
sub cleanup {
my ($kernel, $heap) = @_[KERNEL, HEAP];
- delete $heap->{$_} for qw(conn flushed closing UID PASS want messageq);
+ delete $heap->{$_} for qw(conn flushed closing UID PASS want messageq
enabled accepted dead);
$kernel->delay('force_close');
if ($heap->{destroy_pending}) {