Line 231 is the @socket.close line. Nothing gets done to the socket
after this, or if it is, it's not getting to it because it crashes on
@socket.close. Nothing should even be touching the entire object after
this, because it sets a flag saying "I'm dead, please GC me."

It's a large program, and the code is available at
http://synapse.malkier.net/browser. The socket closing is in
lib/xmppd/xmpp/stream.rb. The code right there doesn't have the
exception catching written in, because I removed the thing that causes
this to happen, which is this:

        # Check for connection timeouts.
        #Timer::Timer.new('check connection timeouts', 60, true) do
        #    $connections.each do |c|
        #        c.error('connection-timeout') if ($time - c.rtime) >= 30
        #    end

I'll try putting the exception around this. One second.

No, that doesn't work. Nor does this:

        # Check for connection timeouts.
        Timer::Timer.new('check connection timeouts', 60, true) do
            $connections.each do |c|
                next if c.dead? or c.socket.closed?
                c.error('connection-timeout') if ($time - c.rtime) >= 30
            end

The socket.closed? returns false, then ONE LINE LATER when I call
socket.close, the IOError is raised and cannot seem to be rescued.

Ok, I've updated the code in svn. Relevant files are
http://synapse.malkier.net/browser/trunk/lib/xmppd.rb (which is where
the Timer is started),
http://synapse.malkier.net/browser/trunk/lib/xmppd/timer.rb (which is
the Timers themselves), and
http://synapse.malkier.net/browser/trunk/lib/xmppd/xmpp/stream.rb
(which is where the socket is closing.

This code outputs this:

/Users/rakaur/Sources/wc/ruby/synapse/trunk/lib/xmppd/xmpp/stream.rb:230:in
`ioloop': stream closed (IOError)
	from /Users/rakaur/Sources/wc/ruby/synapse/trunk/lib/xmppd.rb:197:in `loop'
	from /Users/rakaur/Sources/wc/ruby/synapse/trunk/lib/xmppd.rb:197:in `ioloop'
	from ./bin/xmppd:20

Perhaps it has to do with the timers running in a separate thread?
Putting begin/rescue in the tread doesn't catch it, either.

Thanks.