Exemple #1
0
class BEConnection( object ):
    """
    This is the basic backend connection object.
    You probably don't want to use this directly.
    """
    logmodule = 'Python Backend Connection'

    def __init__(self, backend, port, localname=None,
                    blockshutdown=False, timeout=10.0):
        self.connected = False
        self.log = MythLog(self.logmodule)
        self._socklock = allocate_lock()

        self.host = backend
        self.port = port
        self.hostname = None
        self.deadline = timeout
        self.blockshutdown = blockshutdown

        self.localname = localname
        if self.localname is None:
            self.localname = socket.gethostname()

        try:
            self.connect()
        except socket.error, e:
            self.log.logTB(MythLog.SOCKET)
            self.connected = False
            self.log(MythLog.GENERAL, MythLog.CRIT,
                    "Couldn't connect to backend [%s]:%d" \
                    % (self.host, self.port))
            raise MythBEError(MythError.PROTO_CONNECTION, self.host, self.port)
        except:
class BEConnection( object ):
    """
    This is the basic backend connection object.
    You probably don't want to use this directly.
    """
    logmodule = 'Python Backend Connection'

    def __init__(self, backend, port, localname=None,
                    blockshutdown=False, timeout=10.0):
        self.connected = False
        self.log = MythLog(self.logmodule)
        self._socklock = allocate_lock()

        self.host = backend
        self.port = port
        self.hostname = None
        self.deadline = timeout
        self.blockshutdown = blockshutdown

        self.localname = localname
        if self.localname is None:
            self.localname = socket.gethostname()

        try:
            self.connect()
        except socket.error, e:
            self.log.logTB(MythLog.SOCKET)
            self.connected = False
            self.log(MythLog.GENERAL, MythLog.CRIT,
                    "Couldn't connect to backend [%s]:%d" \
                    % (self.host, self.port))
            raise MythBEError(MythError.PROTO_CONNECTION, self.host, self.port)
        except:
Exemple #3
0
class BEConnection(object):
    """
    This is the basic backend connection object.
    You probably don't want to use this directly.
    """
    logmodule = 'Python Backend Connection'

    def __init__(self,
                 backend,
                 port,
                 localname=None,
                 blockshutdown=False,
                 timeout=10.0):
        self.connected = False
        self.log = MythLog(self.logmodule)
        self._socklock = allocate_lock()

        self.host = backend
        self.port = port
        self.hostname = None
        self.deadline = timeout
        self.blockshutdown = blockshutdown

        self.localname = localname
        if self.localname is None:
            self.localname = socket.gethostname()

        try:
            self.connect()
        except socket.error as e:
            self.log.logTB(MythLog.SOCKET)
            self.connected = False
            self.log(MythLog.GENERAL, MythLog.CRIT,
                    "Couldn't connect to backend [%s]:%d" \
                    % (self.host, self.port))
            raise MythBEError(MythError.PROTO_CONNECTION, self.host, self.port)
        except:
            raise

    def __del__(self):
        self.disconnect()

    def connect(self):
        if self.connected:
            return
        self.log(MythLog.SOCKET | MythLog.NETWORK, MythLog.INFO,
                 "Connecting to backend [%s]:%d" % (self.host, self.port))
        if ':' in self.host:
            self.socket = deadlinesocket(socket.AF_INET6, socket.SOCK_STREAM)
        else:
            self.socket = deadlinesocket(socket.AF_INET, socket.SOCK_STREAM)
        self.socket.log = self.log
        self.socket.connect((self.host, self.port))
        self.socket.setdeadline(self.deadline)
        self.connected = True
        self.check_version()
        self.announce()

    def disconnect(self, hard=False):
        if not self.connected:
            return
        self.log(MythLog.SOCKET | MythLog.NETWORK, MythLog.INFO,
                 "Terminating connection to [%s]:%d" % (self.host, self.port))
        if not hard:
            self.backendCommand('DONE', 0)
        self.connected = False
        self.socket.shutdown(1)
        self.socket.close()

    def reconnect(self, hard=False):
        self.disconnect(hard)
        self.connect()

    def announce(self):
        # set type, 'Playback' blocks backend shutdown
        type = ('Monitor', 'Playback')[self.blockshutdown]

        res = self.backendCommand('ANN %s %s 0' % (type, self.localname))
        if res != 'OK':
            self.log(MythLog.GENERAL, MythLog.ERR, "Unexpected answer to ANN",
                     res)
            raise MythBEError(MythError.PROTO_ANNOUNCE, self.host, self.port,
                              res)
        else:
            self.log(MythLog.SOCKET, MythLog.INFO,
                     "Successfully connected to backend",
                     "[%s]:%d" % (self.host, self.port))
        self.hostname = self.backendCommand('QUERY_HOSTNAME')

    def check_version(self):
        res = self.backendCommand('MYTH_PROTO_VERSION %s %s' \
                    % (PROTO_VERSION, PROTO_TOKEN)).split(BACKEND_SEP)
        if res[0] == 'REJECT':
            self.log(MythLog.GENERAL, MythLog.ERR,
                            "Backend has version %s, and we speak %s" %\
                            (res[1], PROTO_VERSION))
            raise MythBEError(MythError.PROTO_MISMATCH, int(res[1]),
                              PROTO_VERSION)

    def backendCommand(self, data, deadline=None):
        """
        obj.backendCommand(data=None, timeout=None) -> response string

        Sends a formatted command via a socket to the mythbackend. 'timeout'
            will override the default timeout given when the object was
            created. If 'data' is None, the method will return any events
            in the receive buffer.
        """

        # return if not connected
        if not self.connected:
            return u''

        # pull default timeout
        if deadline is None:
            deadline = self.socket.getdeadline()
        if deadline < 1000:
            deadline += time()

        try:
            # lock socket access
            with self._socklock:
                # send command string
                self.socket.sendheader(data.encode("utf-8"))
                # wait timeout for data to be received on the socket
                t = time()
                timeout = (deadline - t) if (deadline - t > 0) else 0.0
                if len(select([self.socket], [], [], timeout)[0]) == 0:
                    # no data, return
                    return u''
                res = self.socket.recvheader(deadline=deadline)

                # convert to unicode
                try:
                    res = str(''.join([res]), 'utf8')
                except:
                    res = u''.join([res])

                return res
        except MythError as e:
            if e.sockcode == 54:
                # remote has closed connection, attempt reconnect
                self.reconnect(True)
                return self.backendCommand(data, deadline)
            else:
                raise

    def blockShutdown(self):
        if not self.blockshutdown:
            self.backendCommand('BLOCK_SHUTDOWN')
            self.blockshutdown = True

    def unblockShutdown(self):
        if self.blockshutdown:
            self.backendCommand('ALLOW_SHUTDOWN')
            self.blockshutdown = False