[ADD] core: support for binding IPv6 in worker mode
Because Werkzeug supports ipv6 natively (and has since ~2010 pallets/werkzeug@13a76262a4), running Odoo in threaded mode allows binding to an ipv6 address. However the prefork server is part of Odoo, and only creates AF_INET (ipv4) sockets. Thus switching from threaded to worker mode breaks the bind. Add a family switch on the `http-interface`, so binding to ipv6 addresses also works in ipv6. Gevent already does that switching internally, so the evented worker works out of the box, it was only the prefork / workers which did not. Looking at both the Werkzeug and Gevent implementations: - https://github.com/pallets/werkzeug/blob/f9906fa6d83dd668f9214acef458419756bbc062/src/werkzeug/serving.py#L607-L614 - https://github.com/gevent/gevent/blob/1e412d35526183b26c1abf2eb658cbef661f5f70/src/gevent/baseserver.py#L415-L433 Both primarily check whether the host contains `:`. Werkzeug also checks if `socket.AF_INET6` exists, however gevent doesn't bother with that. Looking at the source (https://github.com/python/cpython/blob/7d801f245e2021d19daff105ce722f22aa844391/Modules/socketmodule.c#L7419-L7421), it is indeed possible for `AF_INET6` to be missing, however that requires specifically compiling Python in an environment which doesn't support IPv6. Meanwhile it's also possible to disable ipv6 at runtime, in which case I'd assume the `socket.AF_INET6` constant is present, and creating the socket fails, which nobody guards against. Therefore just ignore the entire thing, it doesn't seem worth the hassle (or the questioning) to check whether the constant is present, especially since this is only a concern when the user specifically requires an IPv6 address. Fixes #35782 closes odoo/odoo#114666 Signed-off-by: Julien Castiaux (juc) <juc@odoo.com>
This commit is contained in:
@@ -921,7 +921,10 @@ class PreforkServer(CommonServer):
|
||||
if config['http_enable']:
|
||||
# listen to socket
|
||||
_logger.info('HTTP service (werkzeug) running on %s:%s', self.interface, self.port)
|
||||
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
family = socket.AF_INET
|
||||
if ':' in self.interface:
|
||||
family = socket.AF_INET6
|
||||
self.socket = socket.socket(family, socket.SOCK_STREAM)
|
||||
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
self.socket.setblocking(0)
|
||||
self.socket.bind((self.interface, self.port))
|
||||
|
||||
Reference in New Issue
Block a user