I've been using smtpd.py to implement a kind of cowboy SMTP server (only overriding process_message), and inevitably after a certain time the server stops accepting incoming connections: the socket on which it was formerly listening gets closed.
I ran it using strace and discovered that it would get ENOTCONN on some just-accepted socket in a call to getpeername(), and then close the *listening* socket. This seems to be caused by the line channel = SMTPChannel(self, conn, addr) in smtpd.py and handle_error() in the definition of asyncore.dispatcher, which finishes by calling self.handle_close() [1]. The result of this is that when the call to getpeername() in the constructor for SMTPChannel raises ENOTCONN (or any other exception), it unwinds via asyncore.dispatcher.handle_read_event(), to asyncore.read(), where the SMTPServer instance gets its handle_error method called on it, eventually closing its listening socket. But the error was in the socket we just accepted---not the listening socket. [1] I'm actually using python2.4, since that's what's installed on the server; there, the handle_error() method simply finishes by calling self.close(). In fact, AFAICT, there's another problem in 3.1: neither asyncore.dispatcher nor smtpd.SMTPServer (nor any of its subclasses in smtpd.py) defines a method handle_close(); asyncore.dispatcher passes attribute lookups to its socket object via __getattr__, but sockets don't have a handle_close method either---so it seems as if, if handle_close() is ever called, it'll just generate a new error. -- http://mail.python.org/mailman/listinfo/python-list