diff --git a/CHANGELOG b/CHANGELOG index db94a58be5..dfaba16016 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,4 @@ +* Drop NetRPC and activate JSON-RPC by default * Remove ir.action.wizard_size * Rename expand and fill attributes into yexpand and yfill * Add xalign and yalign as field attributes diff --git a/etc/trytond.conf b/etc/trytond.conf index f99ac12a04..f1d439b4ab 100644 --- a/etc/trytond.conf +++ b/etc/trytond.conf @@ -9,18 +9,13 @@ # If empty, the server will listen on all available interfaces #interface = -# Activate the netrpc protocol -#netrpc = True -# Configure the port for the netrpc protocol to listen -#netport = 8070 - # Activate the xml-rpc protocol #xmlrpc = False # Configure the port for the xml-rpc protocol to listen #xmlport = 8069 # Activate the json-rpc protocol -#jsonrpc = False +#jsonrpc = True # Configure the port for the json-rpc protocol to listen #jsonport = 8000 # Configure the path of json-rpc data @@ -57,7 +52,6 @@ #logfile = False # Enable secure connection with SSL -#secure_netrpc = False #secure_xmlrpc = False #secure_jsonrpc = False #secure_webdav = False @@ -75,9 +69,6 @@ # Configure the path to store attachments and sqlite database #data_path = /var/lib/trytond -# Limit the number of threads -#max_thread = 40 - # Allow to run more than one instance of trytond #multi_server = False diff --git a/trytond/config.py b/trytond/config.py index e4c5fe374c..131e2c94de 100644 --- a/trytond/config.py +++ b/trytond/config.py @@ -8,11 +8,9 @@ class ConfigManager(object): self.options = { 'hostname': None, 'interface': '', - 'netrpc': True, - 'netport': 8070, 'xmlrpc': False, 'xmlport': 8069, - 'jsonrpc': False, + 'jsonrpc': True, 'jsonport': 8000, 'jsondata_path': '/var/www/localhost/tryton', 'webdav': False, @@ -31,7 +29,6 @@ class ConfigManager(object): 'debug_mode': False, 'pidfile': None, 'logfile': None, - 'secure_netrpc': False, 'secure_xmlrpc': False, 'secure_jsonrpc': False, 'secure_webdav': False, @@ -44,7 +41,6 @@ class ConfigManager(object): 'smtp_user': False, 'smtp_password': False, 'data_path': '/var/lib/trytond', - 'max_thread': 40, 'multi_server': False, 'session_timeout': 600, 'psyco': False, diff --git a/trytond/protocols/common.py b/trytond/protocols/common.py index e6d0a5cc8b..13092f77dc 100644 --- a/trytond/protocols/common.py +++ b/trytond/protocols/common.py @@ -4,6 +4,13 @@ import errno import os import socket import threading +import select +import sys +import gzip +try: + import cStringIO as StringIO +except ImportError: + import StringIO def endsocket(sock): if os.name != 'nt': @@ -17,7 +24,6 @@ class daemon(threading.Thread): def __init__(self, interface, port, secure, name=None): threading.Thread.__init__(self, name=name) self.secure = secure - self.running = False self.ipv6 = False if socket.has_ipv6: try: @@ -27,11 +33,96 @@ class daemon(threading.Thread): pass def stop(self): - self.running = False + self.server.shutdown() + return def run(self): - self.running = True - while self.running: - self.server.handle_request() - endsocket(self.server.socket) + self.server.serve_forever() return True + +class GZipRequestHandlerMixin: + + if sys.version_info[:2] <= (2, 6): + # Copy from SimpleXMLRPCServer.py with gzip encoding added + def do_POST(self): + """Handles the HTTP POST request. + + Attempts to interpret all HTTP POST requests as XML-RPC calls, + which are forwarded to the server's _dispatch method for handling. + """ + + # Check that the path is legal + if not self.is_rpc_path_valid(): + self.report_404() + return + + try: + # Get arguments by reading body of request. + # We read this in chunks to avoid straining + # socket.read(); around the 10 or 15Mb mark, some platforms + # begin to have problems (bug #792570). + max_chunk_size = 10*1024*1024 + size_remaining = int(self.headers["content-length"]) + L = [] + while size_remaining: + chunk_size = min(size_remaining, max_chunk_size) + L.append(self.rfile.read(chunk_size)) + size_remaining -= len(L[-1]) + data = ''.join(L) + + data = self.decode_request_content(data) + if data is None: + return #response has been sent + + # In previous versions of SimpleXMLRPCServer, _dispatch + # could be overridden in this class, instead of in + # SimpleXMLRPCDispatcher. To maintain backwards compatibility, + # check to see if a subclass implements _dispatch and dispatch + # using that method if present. + response = self.server._marshaled_dispatch( + data, getattr(self, '_dispatch', None) + ) + except Exception: # This should only happen if the module is buggy + # internal error, report as HTTP server error + self.send_response(500) + self.end_headers() + else: + # got a valid XML RPC response + self.send_response(200) + self.send_header("Content-type", "text/xml") + + # Handle gzip encoding + if 'gzip' in self.headers.get('Accept-Encoding', '').split(',') \ + and len(response) > self.encode_threshold: + buffer = StringIO.StringIO() + output = gzip.GzipFile(mode='wb', fileobj=buffer) + output.write(response) + output.close() + buffer.seek(0) + response = buffer.getvalue() + self.send_header('Content-Encoding', 'gzip') + + self.send_header("Content-length", str(len(response))) + self.end_headers() + self.wfile.write(response) + + def decode_request_content(self, data): + #support gzip encoding of request + encoding = self.headers.get("content-encoding", "identity").lower() + if encoding == "identity": + return data + if encoding == "gzip": + f = StringIO.StringIO(data) + gzf = gzip.GzipFile(mode="rb", fileobj=f) + try: + decoded = gzf.read() + except IOError: + self.send_response(400, "error decoding gzip content") + f.close() + gzf.close() + return decoded + else: + self.send_response(501, "encoding %r not supported" % encoding) + self.send_header("Content-length", "0") + self.end_headers() + diff --git a/trytond/protocols/jsonrpc.py b/trytond/protocols/jsonrpc.py index 8933d6b438..ea950b22b7 100644 --- a/trytond/protocols/jsonrpc.py +++ b/trytond/protocols/jsonrpc.py @@ -4,7 +4,7 @@ from trytond.protocols.sslsocket import SSLSocket from trytond.protocols.dispatcher import dispatch from trytond.config import CONFIG from trytond.protocols.datatype import Float -from trytond.protocols.common import daemon +from trytond.protocols.common import daemon, GZipRequestHandlerMixin import SimpleXMLRPCServer import SimpleHTTPServer import SocketServer @@ -12,8 +12,6 @@ import traceback import socket import sys import os -import gzip -import StringIO try: import fcntl except ImportError: @@ -31,6 +29,8 @@ def object_hook(dct): dct['hour'], dct['minute'], dct['second']) elif dct['__class__'] == 'date': return datetime.date(dct['year'], dct['month'], dct['day']) + elif dct['__class__'] == 'Decimal': + return Decimal(dct['decimal']) return dct class JSONEncoder(json.JSONEncoder): @@ -52,7 +52,9 @@ class JSONEncoder(json.JSONEncoder): 'day': obj.day, } elif isinstance(obj, Decimal): - return float(obj) + return {'__class__': 'Decimal', + 'decimal': str(obj), + } return super(JSONEncoder, self).default(obj) @@ -64,7 +66,7 @@ class SimpleJSONRPCDispatcher(SimpleXMLRPCServer.SimpleXMLRPCDispatcher): reason to instantiate this class directly. """ - def _marshaled_dispatch(self, data, dispatch_method=None): + def _marshaled_dispatch(self, data, dispatch_method=None, path=None): """Dispatches an JSON-RPC method from marshalled (JSON) data. JSON-RPC methods are dispatched from the marshalled (JSON) data @@ -75,7 +77,7 @@ class SimpleJSONRPCDispatcher(SimpleXMLRPCServer.SimpleXMLRPCDispatcher): existing method through subclassing is the prefered means of changing method dispatch behavior. """ - rawreq = json.loads(data, object_hook=object_hook, parse_float=Float) + rawreq = json.loads(data, object_hook=object_hook) req_id = rawreq.get('id', 0) method = rawreq['method'] @@ -104,7 +106,7 @@ class SimpleJSONRPCDispatcher(SimpleXMLRPCServer.SimpleXMLRPCDispatcher): traceb = sys.exc_info()[2] pdb.post_mortem(traceb) # report exception back to server - response['error'] = "%s:\n%s" % (sys.exc_value, tb_s) + response['error'] = (str(sys.exc_value), tb_s) return json.dumps(response, cls=JSONEncoder) @@ -126,7 +128,8 @@ class GenericJSONRPCRequestHandler: return res -class SimpleJSONRPCRequestHandler(GenericJSONRPCRequestHandler, +class SimpleJSONRPCRequestHandler(GZipRequestHandlerMixin, + GenericJSONRPCRequestHandler, SimpleXMLRPCServer.SimpleXMLRPCRequestHandler, SimpleHTTPServer.SimpleHTTPRequestHandler): """Simple JSON-RPC request handler class. @@ -134,71 +137,15 @@ class SimpleJSONRPCRequestHandler(GenericJSONRPCRequestHandler, Handles all HTTP POST requests and attempts to decode them as JSON-RPC requests. """ + protocol_version = "HTTP/1.1" rpc_paths = None encode_threshold = 1400 # common MTU - # Copy from SimpleXMLRPCServer.py with gzip encoding added - def do_POST(self): - """Handles the HTTP POST request. - - Attempts to interpret all HTTP POST requests as JSON-RPC calls, - which are forwarded to the server's _dispatch method for handling. - """ - - # Check that the path is legal - if not self.is_rpc_path_valid(): - self.report_404() - return - - try: - # Get arguments by reading body of request. - # We read this in chunks to avoid straining - # socket.read(); around the 10 or 15Mb mark, some platforms - # begin to have problems (bug #792570). - max_chunk_size = 10*1024*1024 - size_remaining = int(self.headers["content-length"]) - L = [] - while size_remaining: - chunk_size = min(size_remaining, max_chunk_size) - L.append(self.rfile.read(chunk_size)) - size_remaining -= len(L[-1]) - data = ''.join(L) - - # In previous versions of SimpleXMLRPCServer, _dispatch - # could be overridden in this class, instead of in - # SimpleXMLRPCDispatcher. To maintain backwards compatibility, - # check to see if a subclass implements _dispatch and dispatch - # using that method if present. - response = self.server._marshaled_dispatch( - data, getattr(self, '_dispatch', None) - ) - except Exception: # This should only happen if the module is buggy - # internal error, report as HTTP server error - self.send_response(500) - self.end_headers() - else: - # got a valid JSON RPC response - self.send_response(200) - self.send_header("Content-type", "application/json-rpc") - - # Handle gzip encoding - if 'gzip' in self.headers.get('Accept-Encoding', '').split(',') \ - and len(response) > self.encode_threshold: - buffer = StringIO.StringIO() - output = gzip.GzipFile(mode='wb', fileobj=buffer) - output.write(response) - output.close() - buffer.seek(0) - response = buffer.getvalue() - self.send_header('Content-Encoding', 'gzip') - - self.send_header("Content-length", str(len(response))) - self.end_headers() - self.wfile.write(response) - - # shut down the connection - self.wfile.flush() - self.connection.shutdown(1) + def send_header(self, keyword, value): + if keyword == 'Content-type' and value == 'text/xml': + value = 'application/json-rpc' + SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.send_header(self, + keyword, value) def translate_path(self, path): """Translate a /-separated PATH to the local filename syntax. @@ -274,6 +221,7 @@ class SimpleJSONRPCServer(SocketServer.TCPServer, class SimpleThreadedJSONRPCServer(SocketServer.ThreadingMixIn, SimpleJSONRPCServer): timeout = 1 + daemon_threads = True def server_bind(self): self.socket.setsockopt(socket.SOL_SOCKET, @@ -304,7 +252,6 @@ class JSONRPCDaemon(daemon): def __init__(self, interface, port, secure=False): daemon.__init__(self, interface, port, secure, name='JSONRPCDaemon') - if self.secure: handler_class = SecureJSONRPCRequestHandler server_class = SecureThreadedJSONRPCServer diff --git a/trytond/protocols/netrpc.py b/trytond/protocols/netrpc.py deleted file mode 100644 index 238fb208bb..0000000000 --- a/trytond/protocols/netrpc.py +++ /dev/null @@ -1,139 +0,0 @@ -#This file is part of Tryton. The COPYRIGHT file at the top level of -#this repository contains the full copyright notices and license terms. -from trytond.pysocket import PySocket -from trytond.protocols.sslsocket import SSLSocket -from trytond.config import CONFIG -from trytond.protocols.dispatcher import dispatch -from trytond.protocols.common import endsocket -import threading -import select -import traceback -import socket -import sys - - -class NetRPCClientThread(threading.Thread): - def __init__(self, sock, threads, secure): - threading.Thread.__init__(self, name='NetRPCClientThread') - self.sock = sock - self.threads = threads - self.running = False - self.secure = secure - - def run(self): - self.running = True - try: - pysocket = PySocket(self.sock) - except Exception: - self.sock.close() - self.threads.remove(self) - return False - timeout = 0 - while self.running: - try: - rlist, _, _ = select.select([self.sock], [], [], 1) - except select.error: - continue - if not rlist: - timeout += 1 - if timeout > 600: - break - continue - timeout = 0 - try: - msg = pysocket.receive() - except Exception: - pysocket.disconnect() - self.threads.remove(self) - return False - host, port = self.sock.getpeername()[:2] - try: - res = dispatch(host, port, 'NetRPC', *msg) - pysocket.send(res) - except Exception, exception: - tb_s = '' - for line in traceback.format_exception(*sys.exc_info()): - try: - line = line.encode('utf-8', 'ignore') - except Exception: - continue - tb_s += line - for path in sys.path: - tb_s = tb_s.replace(path, '') - if CONFIG['debug_mode']: - import pdb - tback = sys.exc_info()[2] - pdb.post_mortem(tback) - try: - pysocket.send(exception.args, exception=True, - traceback=tb_s) - except Exception: - pysocket.disconnect() - self.threads.remove(self) - return False - pysocket.disconnect() - self.threads.remove(self) - return True - - def stop(self): - self.running = False - - -class NetRPCServerThread(threading.Thread): - def __init__(self, interface, port, secure=False): - threading.Thread.__init__(self, name='NetRPCServerThread') - self.socket = None - if socket.has_ipv6: - try: - socket.getaddrinfo(interface or None, port, socket.AF_INET6) - self.socket = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) - except Exception: - pass - if self.socket is None: - self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - if secure: - self.socket = SSLSocket(self.socket) - self.socket.bind((interface, port)) - self.socket.listen(5) - self.threads = [] - self.secure = secure - self.running = False - - def run(self): - try: - self.running = True - while self.running: - if not int(CONFIG['max_thread']) \ - or len(self.threads) < int(CONFIG['max_thread']): - try: - rlist, _, _ = select.select([self.socket], [], [], 1) - except select.error: - continue - if not rlist: - continue - (clientsocket, _) = self.socket.accept() - c_thread = NetRPCClientThread(clientsocket, self.threads, - self.secure) - self.threads.append(c_thread) - c_thread.start() - except Exception: - try: - self.socket.close() - except Exception: - pass - return False - - def stop(self): - self.running = False - while len(self.threads): - try: - thread = self.threads[0] - thread.stop() - thread.join() - except Exception: - pass - try: - endsocket(self.socket) - except Exception: - return False diff --git a/trytond/protocols/webdav.py b/trytond/protocols/webdav.py index b0be2a9010..96aaa5308d 100644 --- a/trytond/protocols/webdav.py +++ b/trytond/protocols/webdav.py @@ -78,7 +78,6 @@ if not hasattr(WebDAVServer.DAVRequestHandler, '_config'): class BaseThreadedHTTPServer(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer): timeout = 1 - max_children = CONFIG['max_thread'] def server_bind(self): self.socket.setsockopt(socket.SOL_SOCKET, diff --git a/trytond/protocols/xmlrpc.py b/trytond/protocols/xmlrpc.py index ded00e6c3d..137ae45518 100644 --- a/trytond/protocols/xmlrpc.py +++ b/trytond/protocols/xmlrpc.py @@ -4,7 +4,7 @@ from trytond.protocols.sslsocket import SSLSocket from trytond.protocols.dispatcher import dispatch from trytond.config import CONFIG from trytond.protocols.datatype import Float -from trytond.protocols.common import daemon +from trytond.protocols.common import daemon, GZipRequestHandlerMixin from trytond import security import SimpleXMLRPCServer import SocketServer @@ -13,8 +13,6 @@ import traceback import socket import sys import os -import gzip -import StringIO import base64 import datetime from types import DictType @@ -102,8 +100,10 @@ class GenericXMLRPCRequestHandler: security.logout(database_name, user, session) -class SimpleXMLRPCRequestHandler(GenericXMLRPCRequestHandler, +class SimpleXMLRPCRequestHandler(GZipRequestHandlerMixin, + GenericXMLRPCRequestHandler, SimpleXMLRPCServer.SimpleXMLRPCRequestHandler): + protocol_version = "HTTP/1.1" rpc_paths = None encode_threshold = 1400 # common MTU @@ -127,69 +127,6 @@ class SimpleXMLRPCRequestHandler(GenericXMLRPCRequestHandler, self.send_header("WWW-Authenticate", 'Basic realm="Tryton"') return False - # Copy from SimpleXMLRPCServer.py with gzip encoding added - def do_POST(self): - """Handles the HTTP POST request. - - Attempts to interpret all HTTP POST requests as XML-RPC calls, - which are forwarded to the server's _dispatch method for handling. - """ - - # Check that the path is legal - if not self.is_rpc_path_valid(): - self.report_404() - return - - try: - # Get arguments by reading body of request. - # We read this in chunks to avoid straining - # socket.read(); around the 10 or 15Mb mark, some platforms - # begin to have problems (bug #792570). - max_chunk_size = 10*1024*1024 - size_remaining = int(self.headers["content-length"]) - L = [] - while size_remaining: - chunk_size = min(size_remaining, max_chunk_size) - L.append(self.rfile.read(chunk_size)) - size_remaining -= len(L[-1]) - data = ''.join(L) - - # In previous versions of SimpleXMLRPCServer, _dispatch - # could be overridden in this class, instead of in - # SimpleXMLRPCDispatcher. To maintain backwards compatibility, - # check to see if a subclass implements _dispatch and dispatch - # using that method if present. - response = self.server._marshaled_dispatch( - data, getattr(self, '_dispatch', None) - ) - except Exception: # This should only happen if the module is buggy - # internal error, report as HTTP server error - self.send_response(500) - self.end_headers() - else: - # got a valid XML RPC response - self.send_response(200) - self.send_header("Content-type", "text/xml") - - # Handle gzip encoding - if 'gzip' in self.headers.get('Accept-Encoding', '').split(',') \ - and len(response) > self.encode_threshold: - buffer = StringIO.StringIO() - output = gzip.GzipFile(mode='wb', fileobj=buffer) - output.write(response) - output.close() - buffer.seek(0) - response = buffer.getvalue() - self.send_header('Content-Encoding', 'gzip') - - self.send_header("Content-length", str(len(response))) - self.end_headers() - self.wfile.write(response) - - # shut down the connection - self.wfile.flush() - self.connection.shutdown(1) - class SecureXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): @@ -202,6 +139,7 @@ class SecureXMLRPCRequestHandler(SimpleXMLRPCRequestHandler): class SimpleThreadedXMLRPCServer(SocketServer.ThreadingMixIn, SimpleXMLRPCServer.SimpleXMLRPCServer): timeout = 1 + daemon_threads = True def server_bind(self): self.socket.setsockopt(socket.SOL_SOCKET, diff --git a/trytond/pysocket.py b/trytond/pysocket.py deleted file mode 100644 index abbcf7daae..0000000000 --- a/trytond/pysocket.py +++ /dev/null @@ -1,253 +0,0 @@ -#This file is part of Tryton. The COPYRIGHT file at the top level of -#this repository contains the full copyright notices and license terms. -import socket -# can't use/fall-back pickle due to different interface :-( -import cPickle -try: - import cStringIO as StringIO -except ImportError: - import StringIO -try: - import ssl -except ImportError: - ssl = None -import gzip -try: - import hashlib -except ImportError: - hashlib = None - import sha -import os - -DNS_CACHE = {} -MAX_SIZE = 999999999 -MAX_LENGHT = len(str(MAX_SIZE)) -CONNECT_TIMEOUT = 5 -TIMEOUT = 3600 -GZIP_THRESHOLD = 1400 # common MTU - -_ALLOWED_MODULES = {'datetime': ['datetime', 'date'], 'decimal': ['Decimal']} - -def checkfunction(module, klass): - if module in _ALLOWED_MODULES and klass in _ALLOWED_MODULES[module]: - mod = __import__(module, {}, {}, ['__all__']) - _class = getattr(mod, klass) - return _class - raise ValueError('Not supported: %s/%s' % (module, klass)) - - -class PySocket: - - def __init__(self, sock=None, fingerprints=None, ca_certs=None): - self.sock = sock - self.host = None - self.hostname = None - self.port = None - self.ssl = False - self.ssl_sock = None - self.connected = False - self.buffer = '' - self.fingerprints = fingerprints - if ca_certs and os.path.isfile(ca_certs): - self.ca_certs = ca_certs - else: - self.ca_certs = None - - def connect(self, host, port=False): - if not port: - buf = host.split('//')[1] - host, port = buf.rsplit(':', 1) - hostname = host - if host in DNS_CACHE: - host = DNS_CACHE[host] - self.sock = None - if socket.has_ipv6: - try: - socket.getaddrinfo(host, int(port), socket.AF_INET6) - self.sock = socket.socket(socket.AF_INET6, - socket.SOCK_STREAM) - self.sock.settimeout(CONNECT_TIMEOUT) - self.sock.connect((host, int(port))) - except socket.error: - self.sock = None - if self.sock is None: - self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - self.sock.settimeout(CONNECT_TIMEOUT) - self.sock.connect((host, int(port))) - DNS_CACHE[hostname], port = self.sock.getpeername()[:2] - try: - sock = None - if socket.has_ipv6: - try: - socket.getaddrinfo(host, int(port), socket.AF_INET6) - sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) - sock.settimeout(CONNECT_TIMEOUT) - sock.connect((host, int(port))) - except socket.error: - sock = None - if sock is None: - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - sock.settimeout(CONNECT_TIMEOUT) - sock.connect((host, int(port))) - if ssl: - ssl_sock = ssl.wrap_socket(sock) - self.ssl = True - elif hasattr(socket, 'ssl'): - ssl_sock = socket.ssl(sock) - self.ssl = True - except socket.error: - pass - self.sock.settimeout(TIMEOUT) - fingerprint = None - if self.ssl: - if ssl: - self.ssl_sock = ssl.wrap_socket(self.sock, - ca_certs=self.ca_certs, cert_reqs=(self.ca_certs and - ssl.CERT_REQUIRED or ssl.CERT_NONE)) - elif hasattr(socket, 'ssl'): - self.ssl_sock = socket.ssl(self.sock, certfile=self.ca_certs) - try: - peercert = self.ssl_sock.getpeercert(True) - except socket.error: - peercert = None - def format_hash(value): - return reduce(lambda x, y: x + y[1].upper() + - ((y[0] % 2 and y[0] + 1 < len(value)) and ':' or ''), - enumerate(value), '') - if peercert and hashlib: - fingerprint = format_hash(hashlib.sha1(peercert).hexdigest()) - elif peercert: - fingerprint = format_hash(sha1.new(peercert).hexdigest()) - self.host = host - self.hostname = hostname - self.port = port - self.connected = True - self.buffer = '' - if self.fingerprints is not None: - key = (self.hostname, str(self.port)) - if key in self.fingerprints: - if self.fingerprints[key] != fingerprint: - self.disconnect() - raise Exception('BadFingerprint') - elif fingerprint: - self.fingerprints[key] = fingerprint - - def disconnect(self): - try: - sock = self.sock - if self.ssl: - sock = self.ssl_sock - try: - shutdown_value = 2 - if hasattr(socket, 'SHUT_RDWR'): - shutdown_value = socket.SHUT_RDWR - if hasattr(sock, 'sock_shutdown'): - sock.sock_shutdown(shutdown_value) - else: - sock.shutdown(shutdown_value) - except socket.error: - pass - sock.close() - except socket.error: - pass - self.sock = None - self.ssl = False - self.ssl_sock = None - self.connected = False - self.buffer = '' - - def reconnect(self): - if self.hostname and self.port: - self.disconnect() - self.connect(self.hostname, self.port) - - def send(self, msg, exception=False, traceback=None): - msg = cPickle.dumps([msg, traceback], protocol=2) - gzip_p = False - if len(msg) > GZIP_THRESHOLD: - buffer = StringIO.StringIO() - output = gzip.GzipFile(mode='wb', fileobj=buffer) - output.write(msg) - output.close() - buffer.seek(0) - msg = buffer.getvalue() - gzip_p = True - size = len(msg) - msg = str(size) + ' ' + (exception and "1" or "0") \ - + (gzip_p and "1" or "0") + msg - size = len(msg) - - if self.ssl: - totalsent = 0 - while totalsent < size: - sent = self.ssl_sock.write(msg[totalsent:]) - if sent == 0: - raise RuntimeError("socket connection broken") - totalsent = totalsent + sent - else: - self.sock.sendall(msg) - - def receive(self): - buf = self.buffer - L = [] - size_remaining = MAX_LENGHT - while size_remaining: - chunk_size = min(size_remaining, 4096) - if self.ssl: - chunk = self.ssl_sock.read(chunk_size) - else: - chunk = self.sock.recv(chunk_size) - if chunk == '': - raise RuntimeError("socket connection broken") - L.append(chunk) - size_remaining -= len(chunk) - if ' ' in chunk: - break - if size_remaining < 0: - raise RuntimeError("socket connection broken") - buf += ''.join(L) - size, msg = buf.split(' ', 1) - size = int(size) - if size > MAX_SIZE: - raise RuntimeError("socket connection broken") - while len(msg) < 2: - chunk_size = min(size + 2, 4096) - if self.ssl: - msg += self.ssl_sock.read(chunk_size) - else: - msg += self.sock.recv(chunk_size) - if msg == '': - raise RuntimeError("socket connection broken") - exception = msg[0] != "0" - gzip_p = msg[1] != "0" - L = [msg[2:]] - size_remaining = size - len(L[0]) - while size_remaining: - chunk_size = min(size_remaining, 4096) - if self.ssl: - chunk = self.ssl_sock.read(chunk_size) - else: - chunk = self.sock.recv(chunk_size) - if chunk == '': - raise RuntimeError("socket connection broken") - L.append(chunk) - size_remaining -= len(chunk) - msg = ''.join(L) - if len(msg) > size: - self.buffer = msg[size:] - msg = msg[:size] - else: - self.buffer = '' - msgio = StringIO.StringIO(msg) - if gzip_p: - output = gzip.GzipFile(mode='r', fileobj=msgio) - msgio = StringIO.StringIO(output.read(-1)) - output.close() - unpickler = cPickle.Unpickler(msgio) - # cPickle mechanism to import instances (pickle differs here) - unpickler.find_global = checkfunction - res = unpickler.load() - if exception: - raise Exception(*(list(res[0]) + [res[1]])) - else: - return res[0] diff --git a/trytond/server.py b/trytond/server.py index ccb5f96a32..79a9c1dd35 100644 --- a/trytond/server.py +++ b/trytond/server.py @@ -170,14 +170,6 @@ class TrytonServer(object): (CONFIG['secure_jsonrpc'] and ' Secure' or '', CONFIG['jsonport'])) - if CONFIG['netrpc']: - from trytond.protocols.netrpc import NetRPCServerThread - netrpcd = NetRPCServerThread(CONFIG['interface'], CONFIG['netport'], - CONFIG['secure_netrpc']) - self.logger.info("starting NetRPC%s protocol, port %d" % \ - (CONFIG['secure_netrpc'] and ' Secure' or '', - CONFIG['netport'])) - if CONFIG['webdav']: from trytond.protocols.webdav import WebDAVServerThread webdavd = WebDAVServerThread(CONFIG['interface'], @@ -191,9 +183,6 @@ class TrytonServer(object): if signum == signal.SIGUSR1: Pool.start() return - if CONFIG['netrpc']: - netrpcd.stop() - netrpcd.join() if CONFIG['xmlrpc']: xmlrpcd.stop() xmlrpcd.join() @@ -221,8 +210,6 @@ class TrytonServer(object): signal.signal(signal.SIGUSR1, handler) self.logger.info('waiting for connections...') - if CONFIG['netrpc']: - netrpcd.start() if CONFIG['xmlrpc']: xmlrpcd.start() if CONFIG['jsonrpc']: