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