diff -r 35da9e3ba697 -r d7c50c15468d Doc/library/asyncore.rst --- a/Doc/library/asyncore.rst Fri May 31 22:18:26 2013 -0700 +++ b/Doc/library/asyncore.rst Sat Jun 01 13:09:19 2013 -0700 @@ -1,4 +1,3 @@ -:mod:`asyncore` --- Asynchronous socket handler =============================================== .. module:: asyncore @@ -184,14 +183,18 @@ Most of these are nearly identical to their socket partners. - .. method:: create_socket(family=socket.AF_INET, type=socket.SOCK_STREAM) + .. method:: create_socket(family=socket.AF_INET, type=socket.SOCK_STREAM, + map=None) This is identical to the creation of a normal socket, and will use the same options for creation. Refer to the :mod:`socket` documentation for - information on creating sockets. + information on creating sockets. The *map* parameter is the map of + channels; if unspecified, the global socket map will be used. For details + about *map*, see the documentation for :func:`loop`. .. versionchanged:: 3.3 - *family* and *type* arguments can be omitted. + *family* and *type* arguments can be omitted. The *map* parameter was + added. .. method:: connect(address) diff -r 35da9e3ba697 -r d7c50c15468d Lib/smtpd.py --- a/Lib/smtpd.py Fri May 31 22:18:26 2013 -0700 +++ b/Lib/smtpd.py Sat Jun 01 13:09:19 2013 -0700 @@ -121,8 +121,9 @@ }) max_command_size_limit = max(command_size_limits.values()) - def __init__(self, server, conn, addr, data_size_limit=DATA_SIZE_DEFAULT): - asynchat.async_chat.__init__(self, conn) + def __init__(self, server, conn, addr, data_size_limit=DATA_SIZE_DEFAULT, + map=None): + asynchat.async_chat.__init__(self, conn, map) self.smtp_server = server self.conn = conn self.addr = addr @@ -576,11 +577,11 @@ channel_class = SMTPChannel def __init__(self, localaddr, remoteaddr, - data_size_limit=DATA_SIZE_DEFAULT): + data_size_limit=DATA_SIZE_DEFAULT, map=None): self._localaddr = localaddr self._remoteaddr = remoteaddr self.data_size_limit = data_size_limit - asyncore.dispatcher.__init__(self) + asyncore.dispatcher.__init__(self, map=map) try: self.create_socket(socket.AF_INET, socket.SOCK_STREAM) # try to re-use a server port if possible @@ -597,7 +598,8 @@ def handle_accepted(self, conn, addr): print('Incoming connection from %s' % repr(addr), file=DEBUGSTREAM) - channel = self.channel_class(self, conn, addr, self.data_size_limit) + channel = self.channel_class(self, conn, addr, self.data_size_limit, + self._map) # API for "doing something useful with the message" def process_message(self, peer, mailfrom, rcpttos, data): diff -r 35da9e3ba697 -r d7c50c15468d Lib/test/test_logging.py --- a/Lib/test/test_logging.py Fri May 31 22:18:26 2013 -0700 +++ b/Lib/test/test_logging.py Sat Jun 01 13:09:19 2013 -0700 @@ -659,41 +659,6 @@ # -- if it proves to be of wider utility than just test_logging if threading: - class TestSMTPChannel(smtpd.SMTPChannel): - """ - This derived class has had to be created because smtpd does not - support use of custom channel maps, although they are allowed by - asyncore's design. Issue #11959 has been raised to address this, - and if resolved satisfactorily, some of this code can be removed. - """ - def __init__(self, server, conn, addr, sockmap): - asynchat.async_chat.__init__(self, conn, sockmap) - self.smtp_server = server - self.conn = conn - self.addr = addr - self.data_size_limit = None - self.received_lines = [] - self.smtp_state = self.COMMAND - self.seen_greeting = '' - self.mailfrom = None - self.rcpttos = [] - self.received_data = '' - self.fqdn = socket.getfqdn() - self.num_bytes = 0 - try: - self.peer = conn.getpeername() - except OSError as err: - # a race condition may occur if the other end is closing - # before we can get the peername - self.close() - if err.args[0] != errno.ENOTCONN: - raise - return - self.push('220 %s %s' % (self.fqdn, smtpd.__version__)) - self.set_terminator(b'\r\n') - self.extended_smtp = False - - class TestSMTPServer(smtpd.SMTPServer): """ This class implements a test SMTP server. @@ -714,37 +679,14 @@ :func:`asyncore.loop`. This avoids changing the :mod:`asyncore` module's global state. """ - channel_class = TestSMTPChannel def __init__(self, addr, handler, poll_interval, sockmap): - self._localaddr = addr - self._remoteaddr = None - self.data_size_limit = None - self.sockmap = sockmap - asyncore.dispatcher.__init__(self, map=sockmap) - try: - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - sock.setblocking(0) - self.set_socket(sock, map=sockmap) - # try to re-use a server port if possible - self.set_reuse_addr() - self.bind(addr) - self.port = sock.getsockname()[1] - self.listen(5) - except: - self.close() - raise + smtpd.SMTPServer.__init__(self, addr, None, map=sockmap) + self.port = self.socket.getsockname()[1] self._handler = handler self._thread = None self.poll_interval = poll_interval - def handle_accepted(self, conn, addr): - """ - Redefined only because the base class does not pass in a - map, forcing use of a global in :mod:`asyncore`. - """ - channel = self.channel_class(self, conn, addr, self.sockmap) - def process_message(self, peer, mailfrom, rcpttos, data): """ Delegates to the handler passed in to the server's constructor. @@ -775,7 +717,7 @@ :func:`asyncore.loop`. """ try: - asyncore.loop(poll_interval, map=self.sockmap) + asyncore.loop(poll_interval, map=self._map) except OSError: # On FreeBSD 8, closing the server repeatably # raises this error. We swallow it if the