diff options
| author | Barry Warsaw | 2009-10-18 20:05:15 -0400 |
|---|---|---|
| committer | Barry Warsaw | 2009-10-18 20:05:15 -0400 |
| commit | 34e27b816aa120e81a8e970ac1d8847384bd3edf (patch) | |
| tree | ed28c04e1b0a15cef0cc528031ef243df21d3210 | |
| parent | 9f6eaef1d836a4234773c0f64dbb09b901ccf21f (diff) | |
| download | mailman-34e27b816aa120e81a8e970ac1d8847384bd3edf.tar.gz mailman-34e27b816aa120e81a8e970ac1d8847384bd3edf.tar.zst mailman-34e27b816aa120e81a8e970ac1d8847384bd3edf.zip | |
| -rw-r--r-- | src/mailman/mta/connection.py | 6 | ||||
| -rw-r--r-- | src/mailman/mta/docs/connection.txt | 130 | ||||
| -rw-r--r-- | src/mailman/testing/layers.py | 4 | ||||
| -rw-r--r-- | src/mailman/testing/mta.py | 34 |
4 files changed, 144 insertions, 30 deletions
diff --git a/src/mailman/mta/connection.py b/src/mailman/mta/connection.py index 922c492e9..105d25afb 100644 --- a/src/mailman/mta/connection.py +++ b/src/mailman/mta/connection.py @@ -54,6 +54,7 @@ class Connection: self._host = host self._port = port self._sessions_per_connection = sessions_per_connection + self._session_count = None self._connection = None def _connect(self): @@ -61,6 +62,7 @@ class Connection: self._connection = smtplib.SMTP() log.debug('Connecting to %s:%s', self._host, self._port) self._connection.connect(self._host, self._port) + self._session_count = self._sessions_per_connection def sendmail(self, envsender, recips, msgtext): """Mimic `smtplib.SMTP.sendmail`.""" @@ -74,11 +76,11 @@ class Connection: self.quit() raise # This session has been successfully completed. - self._sessions_per_connection -= 1 + self._session_count -= 1 # By testing exactly for equality to 0, we automatically handle the # case for SMTP_MAX_SESSIONS_PER_CONNECTION <= 0 meaning never close # the connection. We won't worry about wraparound <wink>. - if self._sessions_per_connection == 0: + if self._session_count == 0: self.quit() return results diff --git a/src/mailman/mta/docs/connection.txt b/src/mailman/mta/docs/connection.txt index d57e301d6..8924826c8 100644 --- a/src/mailman/mta/docs/connection.txt +++ b/src/mailman/mta/docs/connection.txt @@ -4,22 +4,23 @@ MTA connections Outgoing connections to the outgoing mail transport agent (MTA) are mitigated through a Connection class, which can transparently manage multiple sessions -to a single physical MTA. +in a single connection. >>> from mailman.mta.connection import Connection -The number of connections per session is specified when the Connection object -is created, as is the host and port number of the SMTP server. +The number of sessions per connections is specified when the Connection object +is created, as is the host and port number of the SMTP server. Zero means +there's an unlimited number of sessions per connection. >>> connection = Connection( - ... config.mta.smtp_host, int(config.mta.smtp_port), 1) + ... config.mta.smtp_host, int(config.mta.smtp_port), 0) At the start, there have been no connections to the server. - >>> smtpd.get_session_count() + >>> smtpd.get_connection_count() 0 -By sending a message to the server, a session is started. +By sending a message to the server, a connection is opened. >>> connection.sendmail('anne@example.com', ['bart@example.com'], """\ ... From: anne@example.com @@ -29,10 +30,10 @@ By sending a message to the server, a session is started. ... """) {} - >>> smtpd.get_session_count() + >>> smtpd.get_connection_count() 1 -We can reset the session count back to zero. +We can reset the connection count back to zero. >>> from smtplib import SMTP >>> def reset(): @@ -41,5 +42,116 @@ We can reset the session count back to zero. ... smtpd.docmd('RSET') >>> reset() - >>> smtpd.get_session_count() + >>> smtpd.get_connection_count() 0 + + >>> connection.quit() + + +Sessions per connection +======================= + +Let's say we specify a maximum number of sessions per connection of 2. When +the third message is sent, the connection is torn down and a new one is +created. + +The connection count starts at zero. + + >>> connection = Connection( + ... config.mta.smtp_host, int(config.mta.smtp_port), 2) + + >>> smtpd.get_connection_count() + 0 + +We send two messages through the Connection object. Only one connection is +opened. + + >>> connection.sendmail('anne@example.com', ['bart@example.com'], """\ + ... From: anne@example.com + ... To: bart@example.com + ... Subject: aardvarks + ... + ... """) + {} + + >>> smtpd.get_connection_count() + 1 + + >>> connection.sendmail('anne@example.com', ['bart@example.com'], """\ + ... From: anne@example.com + ... To: bart@example.com + ... Subject: aardvarks + ... + ... """) + {} + + >>> smtpd.get_connection_count() + 1 + +The third message causes a third session, which exceeds the maximum. So the +current connection is closed and a new one opened. + + >>> connection.sendmail('anne@example.com', ['bart@example.com'], """\ + ... From: anne@example.com + ... To: bart@example.com + ... Subject: aardvarks + ... + ... """) + {} + + >>> smtpd.get_connection_count() + 2 + +A fourth message does not cause a new connection to be made. + + >>> connection.sendmail('anne@example.com', ['bart@example.com'], """\ + ... From: anne@example.com + ... To: bart@example.com + ... Subject: aardvarks + ... + ... """) + {} + + >>> smtpd.get_connection_count() + 2 + +But a fifth one does. + + >>> connection.sendmail('anne@example.com', ['bart@example.com'], """\ + ... From: anne@example.com + ... To: bart@example.com + ... Subject: aardvarks + ... + ... """) + {} + + >>> smtpd.get_connection_count() + 3 + + +No maximum +========== + +A value of zero means that there is an unlimited number of sessions per +connection. + + >>> connection = Connection( + ... config.mta.smtp_host, int(config.mta.smtp_port), 0) + >>> reset() + +Even after ten messages are sent, there's still been only one connection to +the server. + + >>> connection.debug = True + >>> for i in range(10): + ... # Ignore the results. + ... results = connection.sendmail( + ... 'anne@example.com', ['bart@example.com'], """\ + ... From: anne@example.com + ... To: bart@example.com + ... Subject: aardvarks + ... + ... """) + + >>> smtpd.get_connection_count() + 1 diff --git a/src/mailman/testing/layers.py b/src/mailman/testing/layers.py index 034e26f83..70b0ae9b1 100644 --- a/src/mailman/testing/layers.py +++ b/src/mailman/testing/layers.py @@ -47,7 +47,7 @@ from mailman.i18n import _ from mailman.interfaces.domain import IDomainManager from mailman.interfaces.messages import IMessageStore from mailman.testing.helpers import TestableMaster -from mailman.testing.mta import SessionCountingController +from mailman.testing.mta import ConnectionCountingController from mailman.utilities.datetime import factory from mailman.utilities.string import expand @@ -220,7 +220,7 @@ class SMTPLayer(ConfigLayer): assert cls.smtpd is None, 'Layer already set up' host = config.mta.smtp_host port = int(config.mta.smtp_port) - cls.smtpd = SessionCountingController(host, port) + cls.smtpd = ConnectionCountingController(host, port) cls.smtpd.start() @classmethod diff --git a/src/mailman/testing/mta.py b/src/mailman/testing/mta.py index 28e5ec77c..62070cc5d 100644 --- a/src/mailman/testing/mta.py +++ b/src/mailman/testing/mta.py @@ -56,8 +56,8 @@ class FakeMTA: -class SessionCountingChannel(Channel): - """Count the number of SMTP sessions opened and closed.""" +class StatisticsChannel(Channel): + """A channel that can answers to the fake STAT command.""" def smtp_STAT(self, arg): """Cause the server to send statistics to its controller.""" @@ -66,13 +66,13 @@ class SessionCountingChannel(Channel): -class SessionCountingServer(QueueServer): - """Count the number of SMTP sessions opened and closed.""" +class ConnectionCountingServer(QueueServer): + """Count the number of SMTP connections opened.""" def __init__(self, host, port, queue, oob_queue): """See `lazr.smtptest.server.QueueServer`.""" QueueServer.__init__(self, host, port, queue) - self.session_count = 0 + self._connection_count = 0 # The out-of-band queue is where the server sends statistics to the # controller upon request. self._oob_queue = oob_queue @@ -80,25 +80,25 @@ class SessionCountingServer(QueueServer): def handle_accept(self): """See `lazr.smtp.server.Server`.""" connection, address = self.accept() - self.session_count += 1 - log.info('[SessionCountingServer] accepted: %s', address) - SessionCountingChannel(self, connection, address) + self._connection_count += 1 + log.info('[ConnectionCountingServer] accepted: %s', address) + StatisticsChannel(self, connection, address) def reset(self): """See `lazr.smtp.server.Server`.""" QueueServer.reset(self) - self.session_count = 0 + self._connection_count = 0 def send_statistics(self): """Send the current connection statistics to the controller.""" # Do not count the connection caused by the STAT connect. - self.session_count -= 1 - self._oob_queue.put(self.session_count) + self._connection_count -= 1 + self._oob_queue.put(self._connection_count) -class SessionCountingController(QueueController): - """Count the number of SMTP sessions opened and closed.""" +class ConnectionCountingController(QueueController): + """Count the number of SMTP connections opened.""" def __init__(self, host, port): """See `lazr.smtptest.controller.QueueController`.""" @@ -107,7 +107,7 @@ class SessionCountingController(QueueController): def _make_server(self, host, port): """See `lazr.smtptest.controller.QueueController`.""" - self.server = SessionCountingServer( + self.server = ConnectionCountingServer( host, port, self.queue, self.oob_queue) def start(self): @@ -117,10 +117,10 @@ class SessionCountingController(QueueController): # method causes a connection to occur. self.reset() - def get_session_count(self): - """Retrieve the number of sessions. + def get_connection_count(self): + """Retrieve the number of connections. - :return: The number of sessions that have been opened. + :return: The number of connections to the server that have been made. :rtype: integer """ smtpd = self._connect() |
