This repository has been archived on 2023-02-21. You can view files and clone it, but cannot push or open issues or pull requests.
python-emails/emails/testsuite/contrib/local-smtpd/secure_smtpd/smtp_server.py

94 lines
3.5 KiB
Python

import secure_smtpd
import ssl, smtpd, asyncore, socket, logging, signal, time, sys
from .smtp_channel import SMTPChannel
from asyncore import ExitNow
from .process_pool import ProcessPool
from ssl import SSLError
try:
from Queue import Empty
except ImportError:
# We're on python3
from queue import Empty
class SMTPServer(smtpd.SMTPServer):
def __init__(self, localaddr, remoteaddr, ssl=False, certfile=None, keyfile=None, ssl_version=ssl.PROTOCOL_SSLv23, require_authentication=False, credential_validator=None, maximum_execution_time=30, process_count=5):
smtpd.SMTPServer.__init__(self, localaddr, remoteaddr)
self.logger = logging.getLogger( secure_smtpd.LOG_NAME )
self.certfile = certfile
self.keyfile = keyfile
self.ssl_version = ssl_version
self.subprocesses = []
self.require_authentication = require_authentication
self.credential_validator = credential_validator
self.ssl = ssl
self.maximum_execution_time = maximum_execution_time
self.process_count = process_count
self.process_pool = None
def handle_accept(self):
self.process_pool = ProcessPool(self._accept_subprocess, process_count=self.process_count)
self.close()
def _accept_subprocess(self, queue):
while True:
try:
self.socket.setblocking(1)
pair = self.accept()
map = {}
if pair is not None:
self.logger.info('_accept_subprocess(): smtp connection accepted within subprocess.')
newsocket, fromaddr = pair
newsocket.settimeout(self.maximum_execution_time)
if self.ssl:
newsocket = ssl.wrap_socket(
newsocket,
server_side=True,
certfile=self.certfile,
keyfile=self.keyfile,
ssl_version=self.ssl_version,
)
channel = SMTPChannel(
self,
newsocket,
fromaddr,
require_authentication=self.require_authentication,
credential_validator=self.credential_validator,
map=map
)
self.logger.info('_accept_subprocess(): starting asyncore within subprocess.')
asyncore.loop(map=map)
self.logger.error('_accept_subprocess(): asyncore loop exited.')
except (ExitNow, SSLError):
self._shutdown_socket(newsocket)
self.logger.info('_accept_subprocess(): smtp channel terminated asyncore.')
except Exception as e:
self._shutdown_socket(newsocket)
self.logger.error('_accept_subprocess(): uncaught exception: %s' % str(e))
def _shutdown_socket(self, s):
try:
s.shutdown(socket.SHUT_RDWR)
s.close()
except Exception as e:
self.logger.error('_shutdown_socket(): failed to cleanly shutdown socket: %s' % str(e))
def run(self):
asyncore.loop()
if hasattr(signal, 'SIGTERM'):
def sig_handler(signal,frame):
self.logger.info("Got signal %s, shutting down." % signal)
sys.exit(0)
signal.signal(signal.SIGTERM, sig_handler)
while 1:
time.sleep(1)