From 6bb3c64529ab99866de5db70f06d00e2c50b30a5 Mon Sep 17 00:00:00 2001 From: Helmut Grohne Date: Fri, 19 Aug 2011 21:01:52 +0200 Subject: scgi: support reusing a listen socket This is useful when used in combination with e.g. systemd. --- wsgitools/scgi/asynchronous.py | 21 +++++++++++++++------ wsgitools/scgi/forkpool.py | 23 +++++++++++++++++------ 2 files changed, 32 insertions(+), 12 deletions(-) (limited to 'wsgitools') diff --git a/wsgitools/scgi/asynchronous.py b/wsgitools/scgi/asynchronous.py index 75f1ff0..e1dbcc6 100644 --- a/wsgitools/scgi/asynchronous.py +++ b/wsgitools/scgi/asynchronous.py @@ -191,7 +191,7 @@ class SCGIServer(asyncore.dispatcher): multiple threads.""" def __init__(self, wsgiapp, port, interface="localhost", error=sys.stderr, maxrequestsize=None, maxpostsize=None, blocksize=None, - config={}): + config={}, reusesocket=None): """ @param wsgiapp: is the wsgi application to be run. @type port: int @@ -215,8 +215,16 @@ class SCGIServer(asyncore.dispatcher): @type config: {} @param config: the environ dictionary is updated using these values for each request. + @type reusesocket: None or socket.socket + @param reusesocket: If a socket is passed, do not create a socket. + Instead use given socket as listen socket. The passed socket + must be set up for accepting tcp connections (i.e. AF_INET, + SOCK_STREAM with bind and listen called). """ - asyncore.dispatcher.__init__(self) + if reusesocket is None: + asyncore.dispatcher.__init__(self) + else: + asyncore.dispatcher.__init__(self, reusesocket) self.wsgiapp = wsgiapp self.error = error @@ -229,10 +237,11 @@ class SCGIServer(asyncore.dispatcher): self.conf["blocksize"] = blocksize self.conf["config"] = config - self.create_socket(socket.AF_INET, socket.SOCK_STREAM) - self.set_reuse_addr() - self.bind((interface, port)) - self.listen(5) + if reusesocket is None: + self.create_socket(socket.AF_INET, socket.SOCK_STREAM) + self.set_reuse_addr() + self.bind((interface, port)) + self.listen(5) def handle_accept(self): """asyncore interface""" diff --git a/wsgitools/scgi/forkpool.py b/wsgitools/scgi/forkpool.py index b090a54..8ccd579 100644 --- a/wsgitools/scgi/forkpool.py +++ b/wsgitools/scgi/forkpool.py @@ -168,7 +168,8 @@ class SCGIServer: self.state = state def __init__(self, wsgiapp, port, interface="localhost", error=sys.stderr, - minworkers=2, maxworkers=32, maxrequests=1000, config={}): + minworkers=2, maxworkers=32, maxrequests=1000, config={}, + reusesocket=None): """ @param wsgiapp: is the WSGI application to be run. @type port: int @@ -188,6 +189,11 @@ class SCGIServer: @type config: {} @param config: the environ dictionary is updated using these values for each request. + @type reusesocket: None or socket.socket + @param reusesocket: If a socket is passed, do not create a socket. + Instead use given socket as listen socket. The passed socket + must be set up for accepting tcp connections (i.e. AF_INET, + SOCK_STREAM with bind and listen called). """ assert hasattr(error, "write") self.wsgiapp = wsgiapp @@ -198,6 +204,7 @@ class SCGIServer: self.maxrequests = maxrequests self.config = config self.error = error + self.reusesocket = reusesocket self.server = None # becomes a socket # maps filedescriptors to WorkerStates self.workers = {} @@ -218,10 +225,13 @@ class SCGIServer: """ Serve the wsgi application. """ - self.server = socket.socket() - self.server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - self.server.bind((self.interface, self.port)) - self.server.listen(5) + if self.reusesocket is None: + self.server = socket.socket() + self.server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + self.server.bind((self.interface, self.port)) + self.server.listen(5) + else: + self.server = self.reusesocket self.running = True while self.running: while (len(self.workers) < self.minworkers or # less than min @@ -254,7 +264,8 @@ class SCGIServer: pid, _ = os.waitpid(0, os.WNOHANG) except OSError: pass - self.server.close() + if self.reusesocket is None: + self.server.close() self.server = None self.killworkers() -- cgit v1.2.3