From 966ba9eb6fd82de0e0b1c227aeaca0d0adcd9c17 Mon Sep 17 00:00:00 2001 From: Antoine Martin Date: Thu, 25 Aug 2016 15:44:21 +0700 Subject: [PATCH] win32 platform support: * no daemonizing support * no SIGCHLD signal * no multiprocessing support * override copyfile so we can retry on WSAEWOULDBLOCK --- websockify/websocket.py | 46 ++++++++++++++++++++++++++---------- websockify/websocketproxy.py | 2 ++ 2 files changed, 36 insertions(+), 12 deletions(-) diff --git a/websockify/websocket.py b/websockify/websocket.py index c9c35b3..eaabe1b 100644 --- a/websockify/websocket.py +++ b/websockify/websocket.py @@ -50,10 +50,15 @@ except: return struct.unpack(fmt, slice) # Degraded functionality if these imports are missing -for mod, msg in [('numpy', 'HyBi protocol will be slower'), - ('ssl', 'TLS/SSL/wss is disabled'), - ('multiprocessing', 'Multi-Processing is disabled'), - ('resource', 'daemonizing is disabled')]: +OPTIONAL_FEATURES = [ + ('numpy', 'HyBi protocol will be slower'), + ('ssl', 'TLS/SSL/wss is disabled'), + ('multiprocessing', 'Multi-Processing is disabled'), + ] +if not sys.platform.startswith("win"): + #resource module is not available on Windows + OPTIONAL_FEATURES.append(('resource', 'daemonizing is disabled')) +for mod, msg in OPTIONAL_FEATURES: try: globals()[mod] = __import__(mod) except ImportError: @@ -535,6 +540,20 @@ class WebSocketRequestHandler(SimpleHTTPRequestHandler): else: SimpleHTTPRequestHandler.do_GET(self) + def copyfile(self, source, outputfile): + """Adds retry code for WSAEWOULDBLOCK on MS Windows""" + if not sys.platform.startswith("win"): + return SimpleHTTPRequestHandler.copyfile(self, source, outputfile) + import shutil + while True: + try: + shutil.copyfileobj(source, outputfile) + return + except (IOError, OSError) as e: + if e[0]==errno.WSAEWOULDBLOCK: + continue + raise + def list_directory(self, path): if self.file_only: self.send_error(404, "No such file") @@ -972,17 +991,20 @@ class WebSocketServer(object): original_signals = { signal.SIGINT: signal.getsignal(signal.SIGINT), signal.SIGTERM: signal.getsignal(signal.SIGTERM), - signal.SIGCHLD: signal.getsignal(signal.SIGCHLD), } signal.signal(signal.SIGINT, self.do_SIGINT) signal.signal(signal.SIGTERM, self.do_SIGTERM) - if not multiprocessing: - # os.fork() (python 2.4) child reaper - signal.signal(signal.SIGCHLD, self.fallback_SIGCHLD) - else: - # make sure that _cleanup is called when children die - # by calling active_children on SIGCHLD - signal.signal(signal.SIGCHLD, self.multiprocessing_SIGCHLD) + #SIGCHLD is only available on posix: + SIGCHLD = getattr(signal, "SIGCHLD", None) + if SIGCHLD: + original_signals[SIGCHLD] = signal.getsignal(SIGCHLD) + if not multiprocessing: + # os.fork() (python 2.4) child reaper + signal.signal(SIGCHLD, self.fallback_SIGCHLD) + else: + # make sure that _cleanup is called when children die + # by calling active_children on SIGCHLD + signal.signal(SIGCHLD, self.multiprocessing_SIGCHLD) last_active_time = self.launch_time try: diff --git a/websockify/websocketproxy.py b/websockify/websocketproxy.py index dfda54a..14b0e06 100755 --- a/websockify/websocketproxy.py +++ b/websockify/websocketproxy.py @@ -228,6 +228,8 @@ class WebSocketProxy(websocket.WebSocketServer): def __init__(self, RequestHandlerClass=ProxyRequestHandler, *args, **kwargs): # Save off proxy specific options + if sys.platform.startswith("win"): + kwargs.pop("multiprocessing_fork", None) self.target_host = kwargs.pop('target_host', None) self.target_port = kwargs.pop('target_port', None) self.wrap_cmd = kwargs.pop('wrap_cmd', None)