From eb5515bee96c2fc60c95c2b4dd23a0a282784d58 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Wed, 8 Mar 2023 09:59:57 +0000 Subject: [PATCH] [ADD] core: support for binding IPv6 in worker mode Because Werkzeug supports ipv6 natively (and has since ~2010 pallets/werkzeug@13a76262a4d827cdd0a95760babc07d2338adb6a), 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) --- odoo/service/server.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/odoo/service/server.py b/odoo/service/server.py index e7b4a210fad..a694148a79f 100644 --- a/odoo/service/server.py +++ b/odoo/service/server.py @@ -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))