From fd753206a6db676b4604fda4349fc44083e9e2df Mon Sep 17 00:00:00 2001 From: Martin Poirier Date: Sat, 12 Nov 2011 16:57:05 +0000 Subject: NetRender OS X bugfix Fix for #26867 Hunted down and debugged with great help from Geoff Murphy --- netrender/client.py | 15 ++++++++++----- netrender/operators.py | 32 ++++++++++++++++---------------- netrender/slave.py | 34 +++++++++++++++++++++++----------- netrender/utils.py | 35 ++++++++++++++++++++++++++++++++--- 4 files changed, 81 insertions(+), 35 deletions(-) (limited to 'netrender') diff --git a/netrender/client.py b/netrender/client.py index ebc9824c..b992f37d 100644 --- a/netrender/client.py +++ b/netrender/client.py @@ -157,7 +157,8 @@ def clientSendJobVCS(conn, scene, anim = False): job.version_info.revision = netsettings.vcs_revision # try to send path first - conn.request("POST", "/job", json.dumps(job.serialize())) + with ConnectionContext(): + conn.request("POST", "/job", json.dumps(job.serialize())) response = conn.getresponse() response.read() @@ -240,7 +241,8 @@ def clientSendJobBlender(conn, scene, anim = False): fillCommonJobSettings(job, job_name, netsettings) # try to send path first - conn.request("POST", "/job", json.dumps(job.serialize())) + with ConnectionContext(): + conn.request("POST", "/job", json.dumps(job.serialize())) response = conn.getresponse() response.read() @@ -250,7 +252,8 @@ def clientSendJobBlender(conn, scene, anim = False): if response.status == http.client.ACCEPTED: for rfile in job.files: f = open(rfile.filepath, "rb") - conn.request("PUT", fileURL(job_id, rfile.index), f) + with ConnectionContext(): + conn.request("PUT", fileURL(job_id, rfile.index), f) f.close() response = conn.getresponse() response.read() @@ -260,7 +263,8 @@ def clientSendJobBlender(conn, scene, anim = False): return job_id def requestResult(conn, job_id, frame): - conn.request("GET", renderURL(job_id, frame)) + with ConnectionContext(): + conn.request("GET", renderURL(job_id, frame)) class NetworkRenderEngine(bpy.types.RenderEngine): bl_idname = 'NET_RENDER' @@ -333,7 +337,8 @@ class NetworkRenderEngine(bpy.types.RenderEngine): # cancel new jobs (animate on network) on break if self.test_break() and new_job: - conn.request("POST", cancelURL(job_id)) + with ConnectionContext(): + conn.request("POST", cancelURL(job_id)) response = conn.getresponse() response.read() print( response.status, response.reason ) diff --git a/netrender/operators.py b/netrender/operators.py index da5f7046..3f27bd71 100644 --- a/netrender/operators.py +++ b/netrender/operators.py @@ -201,8 +201,8 @@ class RENDER_OT_netclientstatus(bpy.types.Operator): conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report) if conn: - conn.request("GET", "/status") - + with ConnectionContext(): + conn.request("GET", "/status") response = conn.getresponse() content = response.read() print( response.status, response.reason ) @@ -229,7 +229,7 @@ class RENDER_OT_netclientstatus(bpy.types.Operator): return self.execute(context) class RENDER_OT_netclientblacklistslave(bpy.types.Operator): - '''Exclude from rendering, by adding slave to the blacklist.''' + '''Exclude from rendering, by adding slave to the blacklist''' bl_idname = "render.netclientblacklistslave" bl_label = "Client Blacklist Slave" @@ -259,7 +259,7 @@ class RENDER_OT_netclientblacklistslave(bpy.types.Operator): return self.execute(context) class RENDER_OT_netclientwhitelistslave(bpy.types.Operator): - '''Remove slave from the blacklist.''' + '''Remove slave from the blacklist''' bl_idname = "render.netclientwhitelistslave" bl_label = "Client Whitelist Slave" @@ -303,8 +303,8 @@ class RENDER_OT_netclientslaves(bpy.types.Operator): conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report) if conn: - conn.request("GET", "/slaves") - + with ConnectionContext(): + conn.request("GET", "/slaves") response = conn.getresponse() content = response.read() print( response.status, response.reason ) @@ -341,7 +341,7 @@ class RENDER_OT_netclientslaves(bpy.types.Operator): return self.execute(context) class RENDER_OT_netclientcancel(bpy.types.Operator): - '''Cancel the selected network rendering job.''' + '''Cancel the selected network rendering job''' bl_idname = "render.netclientcancel" bl_label = "Client Cancel" @@ -357,8 +357,8 @@ class RENDER_OT_netclientcancel(bpy.types.Operator): if conn: job = netrender.jobs[netsettings.active_job_index] - conn.request("POST", cancelURL(job.id), json.dumps({'clear':False})) - + with ConnectionContext(): + conn.request("POST", cancelURL(job.id), json.dumps({'clear':False})) response = conn.getresponse() response.read() print( response.status, response.reason ) @@ -371,7 +371,7 @@ class RENDER_OT_netclientcancel(bpy.types.Operator): return self.execute(context) class RENDER_OT_netclientcancelall(bpy.types.Operator): - '''Cancel all running network rendering jobs.''' + '''Cancel all running network rendering jobs''' bl_idname = "render.netclientcancelall" bl_label = "Client Cancel All" @@ -384,8 +384,8 @@ class RENDER_OT_netclientcancelall(bpy.types.Operator): conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report) if conn: - conn.request("POST", "/clear", json.dumps({'clear':False})) - + with ConnectionContext(): + conn.request("POST", "/clear", json.dumps({'clear':False})) response = conn.getresponse() response.read() print( response.status, response.reason ) @@ -416,10 +416,10 @@ class netclientdownload(bpy.types.Operator): if conn: job_id = netrender.jobs[netsettings.active_job_index].id - conn.request("GET", "/status", headers={"job-id":job_id}) - + with ConnectionContext(): + conn.request("GET", "/status", headers={"job-id":job_id}) response = conn.getresponse() - + if response.status != http.client.OK: self.report({'ERROR'}, "Job ID %i not defined on master" % job_id) return {'ERROR'} @@ -486,7 +486,7 @@ class netclientdownload(bpy.types.Operator): return self.execute(context) class netclientscan(bpy.types.Operator): - '''Listen on network for master server broadcasting its address and port.''' + '''Listen on network for master server broadcasting its address and port''' bl_idname = "render.netclientscan" bl_label = "Client Scan" diff --git a/netrender/slave.py b/netrender/slave.py index 6fef4f4e..6ae09829 100644 --- a/netrender/slave.py +++ b/netrender/slave.py @@ -67,7 +67,8 @@ def slave_Info(): return slave def testCancel(conn, job_id, frame_number): - conn.request("HEAD", "/status", headers={"job-id":job_id, "job-frame": str(frame_number)}) + with ConnectionContext(): + conn.request("HEAD", "/status", headers={"job-id":job_id, "job-frame": str(frame_number)}) # canceled if job isn't found anymore if responseStatus(conn) == http.client.NO_CONTENT: @@ -93,7 +94,8 @@ def testFile(conn, job_id, slave_id, rfile, JOB_PREFIX, main_path = None): # Force prefix path if not found job_full_path = prefixPath(JOB_PREFIX, rfile.filepath, main_path, force = True) temp_path = os.path.join(JOB_PREFIX, "slave.temp") - conn.request("GET", fileURL(job_id, rfile.index), headers={"slave-id":slave_id}) + with ConnectionContext(): + conn.request("GET", fileURL(job_id, rfile.index), headers={"slave-id":slave_id}) response = conn.getresponse() if response.status != http.client.OK: @@ -155,7 +157,8 @@ def render_slave(engine, netsettings, threads): print("Retry %i failed, waiting %is before retrying" % (i + 1, bisleep.current)) if conn: - conn.request("POST", "/slave", json.dumps(slave_Info().serialize())) + with ConnectionContext(): + conn.request("POST", "/slave", json.dumps(slave_Info().serialize())) response = conn.getresponse() response.read() @@ -168,7 +171,8 @@ def render_slave(engine, netsettings, threads): engine.update_stats("", "Network render connected to master, waiting for jobs") while not engine.test_break(): - conn.request("GET", "/job", headers={"slave-id":slave_id}) + with ConnectionContext(): + conn.request("GET", "/job", headers={"slave-id":slave_id}) response = conn.getresponse() if response.status == http.client.OK: @@ -218,7 +222,8 @@ def render_slave(engine, netsettings, threads): # announce log to master logfile = netrender.model.LogFile(job.id, slave_id, [frame.number for frame in job.frames]) - conn.request("POST", "/log", bytes(json.dumps(logfile.serialize()), encoding='utf8')) + with ConnectionContext(): + conn.request("POST", "/log", bytes(json.dumps(logfile.serialize()), encoding='utf8')) response = conn.getresponse() response.read() @@ -258,7 +263,8 @@ def render_slave(engine, netsettings, threads): # update logs if needed if stdout: # (only need to update on one frame, they are linked - conn.request("PUT", logURL(job.id, first_frame), stdout, headers=headers) + with ConnectionContext(): + conn.request("PUT", logURL(job.id, first_frame), stdout, headers=headers) responseStatus(conn) # Also output on console @@ -293,7 +299,9 @@ def render_slave(engine, netsettings, threads): print(str(stdout, encoding='utf8'), end="") # (only need to update on one frame, they are linked - conn.request("PUT", logURL(job.id, first_frame), stdout, headers=headers) + with ConnectionContext(): + conn.request("PUT", logURL(job.id, first_frame), stdout, headers=headers) + if responseStatus(conn) == http.client.NO_CONTENT: continue @@ -323,18 +331,21 @@ def render_slave(engine, netsettings, threads): if thumbname: f = open(thumbname, 'rb') - conn.request("PUT", "/thumb", f, headers=headers) + with ConnectionContext(): + conn.request("PUT", "/thumb", f, headers=headers) f.close() responseStatus(conn) f = open(filename, 'rb') - conn.request("PUT", "/render", f, headers=headers) + with ConnectionContext(): + conn.request("PUT", "/render", f, headers=headers) f.close() if responseStatus(conn) == http.client.NO_CONTENT: continue elif job.type == netrender.model.JOB_PROCESS: - conn.request("PUT", "/render", headers=headers) + with ConnectionContext(): + conn.request("PUT", "/render", headers=headers) if responseStatus(conn) == http.client.NO_CONTENT: continue else: @@ -342,7 +353,8 @@ def render_slave(engine, netsettings, threads): for frame in job.frames: headers["job-frame"] = str(frame.number) # send error result back to server - conn.request("PUT", "/render", headers=headers) + with ConnectionContext(): + conn.request("PUT", "/render", headers=headers) if responseStatus(conn) == http.client.NO_CONTENT: continue diff --git a/netrender/utils.py b/netrender/utils.py index 1ae60a20..5b8e1995 100644 --- a/netrender/utils.py +++ b/netrender/utils.py @@ -16,7 +16,7 @@ # # ##### END GPL LICENSE BLOCK ##### -import sys, os, re +import sys, os, re, platform import http, http.client, http.server, socket import subprocess, time, hashlib @@ -57,6 +57,30 @@ FRAME_STATUS_TEXT = { ERROR: "Error" } +if platform.system() == "Darwin": + class ConnectionContext: + def __init__(self, timeout = None): + self.old_timeout = socket.getdefaulttimeout() + self.timeout = timeout + + def __enter__(self): + if self.old_timeout != self.timeout: + socket.setdefaulttimeout(self.timeout) + def __exit__(self, exc_type, exc_value, traceback): + if self.old_timeout != self.timeout: + socket.setdefaulttimeout(self.old_timeout) +else: + # On sane OSes we can use the connection timeout value correctly + class ConnectionContext: + def __init__(self, timeout = None): + pass + + def __enter__(self): + pass + + def __exit__(self, exc_type, exc_value, traceback): + pass + class DirectoryContext: def __init__(self, path): self.path = path @@ -146,7 +170,11 @@ def clientConnection(address, port, report = None, scan = True, timeout = 5): return None try: - conn = http.client.HTTPConnection(address, port, timeout = timeout) + if platform.system() == "Darwin": + with ConnectionContext(timeout): + conn = http.client.HTTPConnection(address, port) + else: + conn = http.client.HTTPConnection(address, port, timeout = timeout) if conn: if clientVerifyVersion(conn): @@ -163,7 +191,8 @@ def clientConnection(address, port, report = None, scan = True, timeout = 5): return None def clientVerifyVersion(conn): - conn.request("GET", "/version") + with ConnectionContext(): + conn.request("GET", "/version") response = conn.getresponse() if response.status != http.client.OK: -- cgit v1.2.3