m2crypto - close_wait when running echod_async

"CARNES, MARK E (MARK)" <[email protected]>
Newsgroups gmane.comp.python.cryptography
Message-ID <17D8724A2A8D9542B2B8AE546B9E5BBC0217694F@AZ4315EXCH001U>
I've been looking at a server that is using the SSL.ssl_dispatcher and asyncore.dispatcher, and noticed
file descriptors that aren't being closed.  I went back and ran the echod_async example from the demo
directory and interestingly enough got the same result.

It looks like the socket is never being closed on the server side.  If I manually go do a self.socket.socket.close()
I can get it to go away, but it looks like it normally wouldn't call that method unless it goes through the __del__
method in Connection, and the reference count was never going to 0.

The end result is that the "Connection" class self references its own methods "self._write_bio", and "self._write_nbio",
which causes a circular reference and if you don't have garbage collection enabled, this object never gets collected.

I tested a variation of "Connection" where I just created a "self.mode" and corresponding "self.send", "self.write", "self.recv",
and "self.read" methods instead of using the method references.

Is there a better way to approach this problem?

Here's the code I changed

-------------------------------------------------------------------------------------------------------------------------------------------------------------

<<snip>>

class Connection:

    """An SSL connection."""

    def __init__(self, ctx, sock=None):
        self.ctx = ctx
        self.ssl = m2.ssl_new(self.ctx.ctx)
        if sock is not None:
            self.socket = sock
        else:
            self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self._fileno = self.socket.fileno()
        self.mode = 0                                   # -- ADDED

   <<snip>>

    def setblocking(self, mode):
        """Set this connection's underlying socket to _mode_."""
        self.socket.setblocking(mode)
        self.mode = mode                                # -- ADDED
#        if mode:                                         -- REMOVED
#            self.send = self.write = self._write_bio     -- REMOVED
#            self.recv = self.read = self._read_bio       -- REMOVED
#        else:                                            -- REMOVED
#            self.send = self.write = self._write_nbio    -- REMOVED
#            self.recv = self.read = self._read_nbio      -- REMOVED

    # NEW METHODS FOLLOW

    def send(self, data):
        if self.mode:
            return self._write_bio(data)
        else:
            return self._write_nbio(data)

    def write(self, data):
        if self.mode:
            return self._write_bio(data)
        else:
            return self._write_nbio(data)

    def recv(self, size=1024):
        if self.mode:
            return self._read_bio(size)
        else:
            return self._read_nbio(size)

    def read(self, size=1024):
        if self.mode:
            return self._read_bio(size)
        else:
            return self._read_nbio(size)

    # END NEW METHODS

   <<snip>>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.