This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author cmcginty
Recipients cmcginty
Date 2009-07-28.03:59:56
SpamBayes Score 1.0741653e-09
Marked as misclassified No
Message-id <1248753598.39.0.190804723361.issue6589@psf.upfronthosting.co.za>
In-reply-to
Content
When subclass of smtpd.SMTPServer, it is possible the get asyncore.loop
to enter an infinite loop where the following output is shown:

.....
warning: unhandled write event
warning: unhandled read event
warning: unhandled write event
warning: unhandled read event
warning: unhandled write event
warning: unhandled read event
warning: unhandled write event
warning: unhandled read event
warning: unhandled write event
warning: unhandled read event
warning: unhandled write event
warning: unhandled read event
....

To reproduce:
1) Init SMTPServer class instance inside of Thread class and call
asyncore.loop()
2) Init second SMTPServer class instance from a second Thread class,
binding to the same address and port. The SMTPServer instance will raise
an exception that socket cannot bind to the port in use. The socket
exception must be caught at some level, and the program execution
allowed to continue.
3) First SMTPServer thread will enter infinite event loop.


Analysis:
When the exception is raised in the second SMTPServer instance, the new
instance has already registered itself with the asyncore library (ex:
'asyncore.dispatcher.__init__(self)'). There is no code in the
SMTPServere.__init__ method that catches the exception raised, caused by
the failed bind attempt. After the exception is caught, the first thread
continues to run, but asyncore is in an invalid state because it still
has the registration of the second SMTPServer instance that never completed.

Workaround and Proposed Fix:
A viable workaround seems to be catching the raised exception in
__init__ method of the SMTPServer subclass, and call self.close() before
re-raising the exception:

class MySmtpServer( smtpd.SMTPServer, object ):
   def __init__( self, **kwargs ):
      try:
         super( _SmtpSink, self).__init__(**kwargs)
      except Exception as e:
         self.close()   # cleanup asyncore after failure
         raise

For a long term fix, I would recommend performing the
asyncore.dispatcher.close() method call in the SMTPServer.__init__() method.
History
Date User Action Args
2009-07-28 03:59:58cmcgintysetrecipients: + cmcginty
2009-07-28 03:59:58cmcgintysetmessageid: <1248753598.39.0.190804723361.issue6589@psf.upfronthosting.co.za>
2009-07-28 03:59:57cmcgintylinkissue6589 messages
2009-07-28 03:59:56cmcgintycreate