| # Copyright (c) 2006- Facebook |
| # Distributed under the Thrift Software License |
| # |
| # See accompanying file LICENSE or visit the Thrift site at: |
| # http://developers.facebook.com/thrift/ |
| |
| from TTransport import * |
| import os |
| import errno |
| import socket |
| |
| class TSocketBase(TTransportBase): |
| def _resolveAddr(self): |
| if self._unix_socket is not None: |
| return [(socket.AF_UNIX, socket.SOCK_STREAM, None, None, self._unix_socket)] |
| else: |
| return socket.getaddrinfo(self.host, self.port, socket.AF_UNSPEC, socket.SOCK_STREAM, 0, socket.AI_PASSIVE | socket.AI_ADDRCONFIG) |
| |
| def close(self): |
| if self.handle: |
| self.handle.close() |
| self.handle = None |
| |
| class TSocket(TSocketBase): |
| """Socket implementation of TTransport base.""" |
| |
| def __init__(self, host='localhost', port=9090, unix_socket=None): |
| """Initialize a TSocket |
| |
| @param host(str) The host to connect to. |
| @param port(int) The (TCP) port to connect to. |
| @param unix_socket(str) The filename of a unix socket to connect to. |
| (host and port will be ignored.) |
| """ |
| |
| self.host = host |
| self.port = port |
| self.handle = None |
| self._unix_socket = unix_socket |
| self._timeout = None |
| |
| def setHandle(self, h): |
| self.handle = h |
| |
| def isOpen(self): |
| return self.handle != None |
| |
| def setTimeout(self, ms): |
| if ms is None: |
| self._timeout = None |
| else: |
| self._timeout = ms/1000.0 |
| |
| if (self.handle != None): |
| self.handle.settimeout(self._timeout) |
| |
| def open(self): |
| try: |
| res0 = self._resolveAddr() |
| for res in res0: |
| self.handle = socket.socket(res[0], res[1]) |
| self.handle.settimeout(self._timeout) |
| try: |
| self.handle.connect(res[4]) |
| except socket.error, e: |
| if res is not res0[-1]: |
| continue |
| else: |
| raise e |
| break |
| except socket.error, e: |
| if self._unix_socket: |
| message = 'Could not connect to socket %s' % self._unix_socket |
| else: |
| message = 'Could not connect to %s:%d' % (self.host, self.port) |
| raise TTransportException(TTransportException.NOT_OPEN, message) |
| |
| def read(self, sz): |
| buff = self.handle.recv(sz) |
| if len(buff) == 0: |
| raise TTransportException('TSocket read 0 bytes') |
| return buff |
| |
| def write(self, buff): |
| sent = 0 |
| have = len(buff) |
| while sent < have: |
| plus = self.handle.send(buff) |
| if plus == 0: |
| raise TTransportException('TSocket sent 0 bytes') |
| sent += plus |
| buff = buff[plus:] |
| |
| def flush(self): |
| pass |
| |
| class TServerSocket(TServerTransportBase, TSocketBase): |
| """Socket implementation of TServerTransport base.""" |
| |
| def __init__(self, port=9090, unix_socket=None): |
| self.host = None |
| self.port = port |
| self._unix_socket = unix_socket |
| self.handle = None |
| |
| def listen(self): |
| res0 = self._resolveAddr() |
| for res in res0: |
| if res[0] is socket.AF_INET6 or res is res0[-1]: |
| break |
| |
| # We need remove the old unix socket if the file exists and |
| # nobody is listening on it. |
| if self._unix_socket: |
| tmp = socket.socket(res[0], res[1]) |
| try: |
| tmp.connect(res[4]) |
| except socket.error, err: |
| eno, message = err.args |
| if eno == errno.ECONNREFUSED: |
| os.unlink(res[4]) |
| |
| self.handle = socket.socket(res[0], res[1]) |
| self.handle.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) |
| if hasattr(self.handle, 'set_timeout'): |
| self.handle.set_timeout(None) |
| self.handle.bind(res[4]) |
| self.handle.listen(128) |
| |
| def accept(self): |
| client, addr = self.handle.accept() |
| result = TSocket() |
| result.setHandle(client) |
| return result |