Skip Menu |

This queue is for tickets about the POE-Component-Client-FTP CPAN distribution.

Report information
The Basics
Id: 34609
Status: new
Priority: 0/
Queue: POE-Component-Client-FTP

People
Owner: Nobody in particular
Requestors: jpalmer [...] linz.govt.nz
Cc:
AdminCc:

Bug Information
Severity: Critical
Broken in: 0.18
Fixed in: (no value)



Subject: Event not emitted after list error
Hi, I've setup a POCO FTP client i.e my $ftp = POE::Component::Client::FTP->spawn( Alias => 'ftp_alias', RemoteAddr => $host, RemotePort => $port, Username => $user, Password => $password, Events => [qw( connected connect_error authenticated login_error quit quit_error type type_error cd cd_error ls_data ls_done ls_error get_data get_done get_error )], ); Everything seems to work ok to most ftp sites until I get a dir list error. My parent session is expecting either a ls_data ls_done ls_error to be called, but after the list error the ls_error is not emitted. Here's the last few lines of my debug log: 5 -> ls_data (from C:/Perl/site/lib/POE/Component/Client/FTP.pm at 986) 5 -> ls_data (from C:/Perl/site/lib/POE/Component/Client/FTP.pm at 986) 5 -> ls_data (from C:/Perl/site/lib/POE/Component/Client/FTP.pm at 986) 5 -> ls_data (from C:/Perl/site/lib/POE/Component/Client/FTP.pm at 986) 5 -> ls_data (from C:/Perl/site/lib/POE/Component/Client/FTP.pm at 986) 5 -> ls_data (from C:/Perl/site/lib/POE/Component/Client/FTP.pm at 986) 5 -> ls_data (from C:/Perl/site/lib/POE/Component/Client/FTP.pm at 986) -> default_complex::cmd_input at C:/Perl/site/lib/POE/Component/Client/FTP.pm line 968. <<< 227 Entering Passive Mode (69,44,86,87,213,212) -> default_complex::data_error at C:/Perl/site/lib/POE/Component/Client/FTP.pm line 968. error: complex_list: read at C:/Perl/site/lib/POE/Component/Client/FTP.pm line 913. Thanks, Jeremy
From: jpalmer [...] linz.govt.nz
Ok here is a patch that ensures that the order of command events is handled correctly. What was currently happening with certain FTP servers was the success transfer command event was being processed before the actual data connection had finished. In the current version of FTP 0.18 this caused the 'ready' state to be declared too early. This attached patch now ensures that the success transfer command event is queued if the data connection is not complete. The queued command event is then dispatched once the data connection has closed. This resolves the issue I was seeing in this bug. Cheers, Jeremy
--- FTP.pm.org Wed Mar 19 01:21:07 2008 +++ FTP.pm Fri Apr 18 13:13:49 2008 @@ -294,8 +294,7 @@ delete $heap->{cmd_rw_wheel}; delete $heap->{cmd_sock_wheel}; - delete $heap->{data_rw_wheel}; - delete $heap->{data_sock_wheel}; + clean_up_complex_cmd(); $poe_kernel->alias_remove( $heap->{alias} ); return; @@ -309,8 +308,7 @@ my $coderef; - $input =~ s/^(\d\d\d)(.?)//o; - my ($code, $more) = ($1, $2); + my ($code, $major, $more) = parse_cmd_string($input); $input =~ s/^ // if defined $more && $more eq "-"; @@ -320,8 +318,6 @@ $heap->{ftp_message} =~ s/\s+$//; - my $major = substr($code, 0, 1); - if ($major == 1) { # 1yz Positive Preliminary reply @@ -470,8 +466,7 @@ elsif ($heap->{data_suicidal}) { warn "killing suicidal socket" . $heap->{data_rw_wheel}->get_driver_out_octets() if DEBUG; - delete $heap->{data_sock_wheel}; - delete $heap->{data_rw_wheel}; + clean_up_complex_cmd(); $heap->{data_suicidal} = 0; send_event("put_closed", @@ -489,8 +484,7 @@ send_event( "put_error", $error, $heap->{complex_stack}->{command}->[1] ); - delete $heap->{data_sock_wheel}; - delete $heap->{data_rw_wheel}; + clean_up_complex_cmd(); goto_state("ready"); return; } @@ -808,8 +802,6 @@ command($heap->{complex_stack}->{command}); } else { - send_event( $heap->{complex_stack}->{command}->[0] . "_done", - $heap->{complex_stack}->{command}->[1] ); goto_state("ready"); } return; @@ -826,9 +818,7 @@ $status, $line, $heap->{complex_stack}->{command}->[1] ); - delete $heap->{data_sock_wheel}; - delete $heap->{data_rw_wheel}; - + clean_up_complex_cmd(); goto_state("ready"); return; } @@ -891,8 +881,7 @@ send_event( $heap->{complex_stack}->{command}->[0] . "_error", $error, $heap->{complex_stack}->{command}->[1] ); - delete $heap->{data_sock_wheel}; - delete $heap->{data_rw_wheel}; + clean_up_complex_cmd(); goto_state("ready"); return; } @@ -911,9 +900,11 @@ sub handler_complex_list_error { my ($kernel, $heap, $input) = @_[KERNEL, HEAP, ARG0]; warn "error: complex_list: $input" if DEBUG; + send_event( $heap->{complex_stack}->{command}->[0] . "_done", + $heap->{complex_stack}->{command}->[1] ); - delete $heap->{data_sock_wheel}; - delete $heap->{data_rw_wheel}; + clean_up_complex_cmd(); + dequeue_complex_cmd(); return; } @@ -958,8 +949,15 @@ # if active session knows how to handle this event, dispatch it to them # if not, enqueue the event sub dispatch { - my ($kernel, $heap, $state) = @_[KERNEL, HEAP, STATE]; + my ($kernel, $heap, $state, $input) = @_[KERNEL, HEAP, STATE, ARG0]; + if ($state eq 'cmd_input' && defined $heap->{data_rw_wheel} ) { + my ($code, $major, $msg) = parse_cmd_string($input); + if ( $major == 2 ) { + enqueue_complex_cmd(@_); + return; + } + } my $coderef = ( $state_map->{ $heap->{state} }->{$state} || $state_map->{global}->{$state} || \&enqueue_event ); @@ -1058,6 +1056,38 @@ command("PORT " . join ",", @addr, @port); } return; +} + +sub parse_cmd_string { + my $string = shift; + $string =~ s/^(\d\d\d)(.?)//o; + my ($code, $more) = ($1, $2); + my $major = substr($code, 0, 1); + return ($code, $major, $more); +} + +sub clean_up_complex_cmd { + my $heap = $poe_kernel->get_active_session()->get_heap(); + delete $heap->{data_sock_wheel}; + delete $heap->{data_rw_wheel}; + $heap->{complex_stack} = {}; +} + +sub enqueue_complex_cmd { + my $heap = $poe_kernel->get_active_session()->get_heap(); + warn "enqueue_complex_cmd $_[STATE]" if DEBUG; + $heap->{pending_complex_cmd} = \@_; +} + +sub dequeue_complex_cmd { + my $heap = $poe_kernel->get_active_session()->get_heap(); + return unless $heap->{pending_complex_cmd}; + + my $state = $heap->{pending_complex_cmd}->[STATE]; + warn "dequeue_complex_cmd $state" if DEBUG; + my @event = @{ $heap->{pending_complex_cmd} }; + $heap->{pending_complex_cmd} = undef; + dispatch( @event ); } 1;
From: jpalmer [...] linz.govt.nz
Here's a new version of the patch the corrects a small uninitialized value in concatenation error. Cheers, Jeremy
--- FTP.pm.org Wed Mar 19 01:21:07 2008 +++ FTP.pm Fri Apr 18 14:16:45 2008 @@ -294,8 +294,7 @@ delete $heap->{cmd_rw_wheel}; delete $heap->{cmd_sock_wheel}; - delete $heap->{data_rw_wheel}; - delete $heap->{data_sock_wheel}; + clean_up_complex_cmd(); $poe_kernel->alias_remove( $heap->{alias} ); return; @@ -309,8 +308,7 @@ my $coderef; - $input =~ s/^(\d\d\d)(.?)//o; - my ($code, $more) = ($1, $2); + my ($code, $more) = parse_cmd_string($input); $input =~ s/^ // if defined $more && $more eq "-"; @@ -470,8 +468,7 @@ elsif ($heap->{data_suicidal}) { warn "killing suicidal socket" . $heap->{data_rw_wheel}->get_driver_out_octets() if DEBUG; - delete $heap->{data_sock_wheel}; - delete $heap->{data_rw_wheel}; + clean_up_complex_cmd(); $heap->{data_suicidal} = 0; send_event("put_closed", @@ -489,8 +486,7 @@ send_event( "put_error", $error, $heap->{complex_stack}->{command}->[1] ); - delete $heap->{data_sock_wheel}; - delete $heap->{data_rw_wheel}; + clean_up_complex_cmd(); goto_state("ready"); return; } @@ -808,8 +804,6 @@ command($heap->{complex_stack}->{command}); } else { - send_event( $heap->{complex_stack}->{command}->[0] . "_done", - $heap->{complex_stack}->{command}->[1] ); goto_state("ready"); } return; @@ -826,9 +820,7 @@ $status, $line, $heap->{complex_stack}->{command}->[1] ); - delete $heap->{data_sock_wheel}; - delete $heap->{data_rw_wheel}; - + clean_up_complex_cmd(); goto_state("ready"); return; } @@ -891,8 +883,7 @@ send_event( $heap->{complex_stack}->{command}->[0] . "_error", $error, $heap->{complex_stack}->{command}->[1] ); - delete $heap->{data_sock_wheel}; - delete $heap->{data_rw_wheel}; + clean_up_complex_cmd(); goto_state("ready"); return; } @@ -911,9 +902,11 @@ sub handler_complex_list_error { my ($kernel, $heap, $input) = @_[KERNEL, HEAP, ARG0]; warn "error: complex_list: $input" if DEBUG; + send_event( $heap->{complex_stack}->{command}->[0] . "_done", + $heap->{complex_stack}->{command}->[1] ); - delete $heap->{data_sock_wheel}; - delete $heap->{data_rw_wheel}; + clean_up_complex_cmd(); + dequeue_complex_cmd(); return; } @@ -958,8 +951,15 @@ # if active session knows how to handle this event, dispatch it to them # if not, enqueue the event sub dispatch { - my ($kernel, $heap, $state) = @_[KERNEL, HEAP, STATE]; + my ($kernel, $heap, $state, $input) = @_[KERNEL, HEAP, STATE, ARG0]; + if ($state eq 'cmd_input' && defined $heap->{data_rw_wheel} ) { + my ($code, $msg) = parse_cmd_string($input); + if ( substr($code, 0, 1) == 2 ) { + enqueue_complex_cmd(@_); + return; + } + } my $coderef = ( $state_map->{ $heap->{state} }->{$state} || $state_map->{global}->{$state} || \&enqueue_event ); @@ -1058,6 +1058,37 @@ command("PORT " . join ",", @addr, @port); } return; +} + +sub parse_cmd_string { + my $string = shift; + $string =~ s/^(\d\d\d)(.?)//o; + my ($code, $more) = ($1, $2); + return ($code, $more); +} + +sub clean_up_complex_cmd { + my $heap = $poe_kernel->get_active_session()->get_heap(); + delete $heap->{data_sock_wheel}; + delete $heap->{data_rw_wheel}; + $heap->{complex_stack} = {}; +} + +sub enqueue_complex_cmd { + my $heap = $poe_kernel->get_active_session()->get_heap(); + warn "enqueue_complex_cmd $_[STATE]" if DEBUG; + $heap->{pending_complex_cmd} = \@_; +} + +sub dequeue_complex_cmd { + my $heap = $poe_kernel->get_active_session()->get_heap(); + return unless $heap->{pending_complex_cmd}; + + my $state = $heap->{pending_complex_cmd}->[STATE]; + warn "dequeue_complex_cmd $state" if DEBUG; + my @event = @{ $heap->{pending_complex_cmd} }; + $heap->{pending_complex_cmd} = undef; + dispatch( @event ); } 1;