On Fri, 2003-08-22 at 17:38, Rocco Caputo wrote: 
> On Fri, Aug 22, 2003 at 03:09:59PM -0400, Dan McCormick wrote:

[...]

> fileno() returning undef is a great way to check for a closed file.
> Your problem is you're ignoring it.  Try this instead:
> 
>   unless (defined fileno $handle) {
>     $kernel->select($handle);
>     return;
>   }
> 
> That'll stop watching closed sockets.

The trick is that by this point, $handle is invalid.  If ASSERT_USAGE is
on, POE dies when you try that select.  Otherwise, it ignores it, but
seems to keep watching the invalid filehandle.  (That is, rd_ok and
wr_ok keep getting called, but fileno($socket) returns undef.)

> My guess is that Net::OSCAR hasn't cleaned up after the closed socket
> yet.  I would need to read the source/documentation on it to determine
> how to force that.

I think you're onto something.  Here's what seems to be going on:

Net::OSCAR creates a connection upon signon.  This socket gets assigned
a fileno -- say, 3.  When we set POE to select on this socket,
everything is peachy.

After signon, Net::OSCAR drops that connection, thus freeing up fileno
3.  POE, however, does not seem to be aware of this.  Net::OSCAR then
immediately establishes a new connection, which also uses fileno 3.

The two problems at this point seem to be:

1) POE keeps watching a socket that no longer exists.  To stop watching
the socket, POE needs a valid socket in the $kernel->select($socket)
call, but we don't have a valid socket to give it.

2) If we try to watch the new socket, POE complains that it "can't watch
the same handle in the same mode 2+ times" because (I think) it's
confusing the old fileno 3 with the new fileno 3.

To support this, I added the line

$main::poe_kernel->select( $connection->{socket} );

in Net::OSCAR immediately before it disconnects the login socket
(Net::OSCAR::Callbacks line 521) and, afterwards, everything worked
perfectly.

Furthermore, tracing through POE's guts, when we call
$kernel->select($socket) in rd_ok or wr_ok with an invalid socket, it
ends up at _data_handle_remove, in which the second line that calls
fileno($handle) returns undef.  Meanwhile, a look at %kr_filenos
indicates that fileno 3 is still there.

So somehow we need (a) Net::OSCAR to alert POE that it's closing the
socket or (b) POE to stop watching an invalid filehandle.

Happily, there's a Net::OSCAR callback that we can set up to alert us 
before it closes a connection.  The only hitch is that using a
$session->postback seems to give us the socket too late --
$connection->{socket} is already undef.

But if I make it a straight subroutine call, everything works fine. 
(Which raises the question: has there been talk of a synchronous
"$session->callback()"?)

In any case, the PoCo::Net::OSCAR module is now fully functional and
perhaps even well-coded.  I'll post it on the Wiki shortly.

Thanks for the guidance, Rocco.

Dan

Reply via email to