diff options
Diffstat (limited to 'module/remote/thriftbackend/Socket.py')
-rw-r--r-- | module/remote/thriftbackend/Socket.py | 129 |
1 files changed, 129 insertions, 0 deletions
diff --git a/module/remote/thriftbackend/Socket.py b/module/remote/thriftbackend/Socket.py new file mode 100644 index 000000000..f6edc8408 --- /dev/null +++ b/module/remote/thriftbackend/Socket.py @@ -0,0 +1,129 @@ +# -*- coding: utf-8 -*- + +import sys +import socket +import errno + +from time import sleep + +from thrift.transport.TSocket import TSocket, TServerSocket, TTransportException + +WantReadError = Exception #overwritten when ssl is used + +class SecureSocketConnection(object): + def __init__(self, connection): + self.__dict__["connection"] = connection + + def __getattr__(self, name): + return getattr(self.__dict__["connection"], name) + + def __setattr__(self, name, value): + setattr(self.__dict__["connection"], name, value) + + def shutdown(self, how=1): + self.__dict__["connection"].shutdown() + + def accept(self): + connection, address = self.__dict__["connection"].accept() + return SecureSocketConnection(connection), address + + def send(self, buff): + try: + return self.__dict__["connection"].send(buff) + except WantReadError: + sleep(0.1) + return self.send(buff) + + def recv(self, buff): + try: + return self.__dict__["connection"].recv(buff) + except WantReadError: + sleep(0.1) + return self.recv(buff) + +class Socket(TSocket): + def __init__(self, host='localhost', port=7228, ssl=False): + TSocket.__init__(self, host, port) + self.ssl = ssl + + def open(self): + if self.ssl: + SSL = __import__("OpenSSL", globals(), locals(), "SSL", -1).SSL + WantReadError = SSL.WantReadError + ctx = SSL.Context(SSL.SSLv23_METHOD) + c = SSL.Connection(ctx, socket.socket(socket.AF_INET, socket.SOCK_STREAM)) + c.set_connect_state() + self.handle = SecureSocketConnection(c) + else: + self.handle = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + #errno 104 connection reset + + self.handle.settimeout(self._timeout) + self.handle.connect((self.host, self.port)) + + def read(self, sz): + try: + buff = self.handle.recv(sz) + except socket.error, e: + if (e.args[0] == errno.ECONNRESET and + (sys.platform == 'darwin' or sys.platform.startswith('freebsd'))): + # freebsd and Mach don't follow POSIX semantic of recv + # and fail with ECONNRESET if peer performed shutdown. + # See corresponding comment and code in TSocket::read() + # in lib/cpp/src/transport/TSocket.cpp. + self.close() + # Trigger the check to raise the END_OF_FILE exception below. + buff = '' + else: + raise + except Exception, e: + # SSL connection was closed + if e.args == (-1, 'Unexpected EOF'): + buff = '' + elif e.args == ([('SSL routines', 'SSL23_GET_CLIENT_HELLO', 'unknown protocol')],): + #a socket not using ssl tried to connect + buff = '' + else: + raise + + if not len(buff): + raise TTransportException(type=TTransportException.END_OF_FILE, message='TSocket read 0 bytes') + return buff + + +class ServerSocket(TServerSocket, Socket): + def __init__(self, port=7228, host="0.0.0.0", key="", cert=""): + self.host = host + self.port = port + self.key = key + self.cert = cert + self.handle = None + + def listen(self): + if self.cert and self.key: + SSL = __import__("OpenSSL", globals(), locals(), "SSL", -1).SSL + WantReadError = SSL.WantReadError + ctx = SSL.Context(SSL.SSLv23_METHOD) + ctx.use_privatekey_file(self.key) + ctx.use_certificate_file(self.cert) + + tmpConnection = SSL.Connection(ctx, socket.socket(socket.AF_INET, socket.SOCK_STREAM)) + tmpConnection.set_accept_state() + self.handle = SecureSocketConnection(tmpConnection) + + else: + self.handle = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + + self.handle.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + if hasattr(self.handle, 'set_timeout'): + self.handle.set_timeout(None) + self.handle.bind((self.host, self.port)) + self.handle.listen(128) + + def accept(self): + client, addr = self.handle.accept() + result = Socket() + result.setHandle(client) + return result |