Пример #1
0
 def __init__(self):
     self.cred = X509Credentials(cert_name='relay')
     self.tls_context = TLSContext(self.cred)
     self.session_manager = SessionManager(self, RelayConfig.port_range.start, RelayConfig.port_range.end)
     self.dispatchers = set()
     self.dispatcher_session_count = {}
     self.dispatcher_connectors = {}
     self.old_connectors = {}
     self.shutting_down = False
     self.graceful_shutdown = False
     self.start_time = time()
     MediaRelayBase.__init__(self)
Пример #2
0
 def __init__(self):
     self.cred = X509Credentials(cert_name='relay')
     self.session_manager = SessionManager(self, RelayConfig.port_range.start, RelayConfig.port_range.end)
     self.dispatchers = set()
     self.dispatcher_session_count = {}
     self.dispatcher_connectors = {}
     self.old_connectors = {}
     self.shutting_down = False
     self.graceful_shutdown = False
     self.start_time = time()
     MediaRelayBase.__init__(self)
Пример #3
0
 def __init__(self):
     try:
         ip_forward = bool(int(open(IP_FORWARD_FILE).read()))
     except:
         ip_forward = False
     if not ip_forward:
         raise RuntimeError("IP forwarding is not available or not enabled (check %s)" % IP_FORWARD_FILE)
     try:
         major, minor, revision = [int(num) for num in open(KERNEL_VERSION_FILE).read().split("-", 1)[0].split(".")[:3]]
     except:
         raise RuntimeError("Could not determine Linux kernel version")
     if (major, minor, revision) < (2, 6, 18):
         raise RuntimeError("A mimimum Linux kernel version of 2.6.18 is required")
     self.cred = X509Credentials(cert_name='relay')
     self.session_manager = SessionManager(self, Config.port_range.start, Config.port_range.end)
     self.dispatchers = set()
     self.dispatcher_session_count = {}
     self.dispatcher_connectors = {}
     self.old_connectors = {}
     self.shutting_down = False
     self.graceful_shutdown = False
     self.start_time = time()
     MediaRelayBase.__init__(self)
Пример #4
0
class MediaRelay(MediaRelayBase):

    def __init__(self):
        self.cred = X509Credentials(cert_name='relay')
        self.session_manager = SessionManager(self, RelayConfig.port_range.start, RelayConfig.port_range.end)
        self.dispatchers = set()
        self.dispatcher_session_count = {}
        self.dispatcher_connectors = {}
        self.old_connectors = {}
        self.shutting_down = False
        self.graceful_shutdown = False
        self.start_time = time()
        MediaRelayBase.__init__(self)

    @property
    def status(self):
        if self.graceful_shutdown or self.shutting_down:
            return 'halting'
        else:
            return 'active'

    def update_dispatchers(self, dispatchers):
        dispatchers = set(dispatchers)
        for new_dispatcher in dispatchers.difference(self.dispatchers):
            if new_dispatcher in self.old_connectors.iterkeys():
                log.debug('Restoring old dispatcher at %s:%d' % new_dispatcher)
                self.dispatcher_connectors[new_dispatcher] = self.old_connectors.pop(new_dispatcher)
            else:
                log.debug('Adding new dispatcher at %s:%d' % new_dispatcher)
                dispatcher_addr, dispatcher_port = new_dispatcher
                factory = DispatcherConnectingFactory(self, dispatcher_addr, dispatcher_port)
                self.dispatcher_connectors[new_dispatcher] = reactor.connectTLS(dispatcher_addr, dispatcher_port, factory, self.cred)
        for old_dispatcher in self.dispatchers.difference(dispatchers):
            log.debug('Removing old dispatcher at %s:%d' % old_dispatcher)
            self.old_connectors[old_dispatcher] = self.dispatcher_connectors.pop(old_dispatcher)
            self._check_disconnect(old_dispatcher)
        self.dispatchers = dispatchers

    def got_command(self, dispatcher, command, headers):
        if command == "summary":
            summary = {'ip'            : RelayConfig.relay_ip,
                       'version'       : __version__,
                       'status'        : self.status,
                       'uptime'        : int(time() - self.start_time),
                       'session_count' : len(self.session_manager.sessions),
                       'stream_count'  : self.session_manager.stream_count,
                       'bps_relayed'   : self.session_manager.bps_relayed}
            return cjson.encode(summary)
        elif command == "sessions":
            return cjson.encode(self.session_manager.statistics)
        elif command == "update":
            if self.graceful_shutdown or self.shutting_down:
                if not self.session_manager.has_session(**headers):
                    log.debug("cannot add new session: media-relay is shutting down")
                    return 'halting'
            try:
                local_media = self.session_manager.update_session(dispatcher, **headers)
            except RelayPortsExhaustedError:
                log.error("Could not reserve relay ports for session, all allocated ports are being used")
                return "error"
            if local_media:
                return " ".join([RelayConfig.advertised_ip or local_media[0][0]] + [str(media[1]) for media in local_media])
        else: # remove
            session = self.session_manager.remove_session(**headers)
            if session is None:
                return "error"
            else:
                return cjson.encode(session.statistics)

    def session_expired(self, session):
        connector = self.dispatcher_connectors.get(session.dispatcher)
        if connector is None:
            connector = self.old_connectors.get(session.dispatcher)
        if connector and connector.state == "connected":
            connector.transport.write(" ".join(["expired", cjson.encode(session.statistics)]) + "\r\n")
        else:
            log.warn("dispatcher for expired session is no longer online, statistics are lost!")

    def add_session(self, dispatcher):
        self.dispatcher_session_count[dispatcher] = self.dispatcher_session_count.get(dispatcher, 0) + 1

    def remove_session(self, dispatcher):
        self.dispatcher_session_count[dispatcher] -= 1
        if self.dispatcher_session_count[dispatcher] == 0:
            del self.dispatcher_session_count[dispatcher]
        if self.graceful_shutdown and not self.dispatcher_session_count:
            self.shutdown()
        elif dispatcher in self.old_connectors:
            self._check_disconnect(dispatcher)

    def _check_disconnect(self, dispatcher):
        connector = self.old_connectors[dispatcher]
        if self.dispatcher_session_count.get(dispatcher, 0) == 0:
            old_state = connector.state
            connector.factory.cancel_delayed()
            connector.disconnect()
            if old_state == "disconnected":
                del self.old_connectors[dispatcher]
                if self.shutting_down and len(self.dispatcher_connectors) + len(self.old_connectors) == 0:
                    self._shutdown()

    def connector_needs_reconnect(self, connector):
        if connector in self.dispatcher_connectors.values():
            return True
        else:
            for dispatcher, old_connector in self.old_connectors.items():
                if old_connector is connector:
                    if self.dispatcher_session_count.get(dispatcher, 0) > 0:
                        return True
                    else:
                        del self.old_connectors[dispatcher]
                        break
            if self.shutting_down:
                if len(self.old_connectors) == 0:
                    self._shutdown()
            return False

    def shutdown(self, graceful=False):
        if graceful:
            self.graceful_shutdown = True
            if self.dispatcher_session_count:
                return
        if not self.shutting_down:
            self.shutting_down = True
            self.srv_monitor.cancel()
            self.session_manager.cleanup()
            if len(self.dispatcher_connectors) + len(self.old_connectors) == 0:
                self._shutdown()
            else:
                self.update_dispatchers([])
Пример #5
0
class MediaRelay(MediaRelayBase):
    def __init__(self):
        self.cred = X509Credentials(cert_name='relay')
        self.tls_context = TLSContext(self.cred)
        self.session_manager = SessionManager(self,
                                              RelayConfig.port_range.start,
                                              RelayConfig.port_range.end)
        self.dispatchers = set()
        self.dispatcher_session_count = {}
        self.dispatcher_connectors = {}
        self.old_connectors = {}
        self.shutting_down = False
        self.graceful_shutdown = False
        self.start_time = time()
        super(MediaRelay, self).__init__()

    @property
    def status(self):
        if self.graceful_shutdown or self.shutting_down:
            return 'halting'
        else:
            return 'active'

    def update_dispatchers(self, dispatchers):
        dispatchers = set(dispatchers)
        for new_dispatcher in dispatchers.difference(self.dispatchers):
            if new_dispatcher in self.old_connectors.iterkeys():
                log.info('Restoring old dispatcher at %s:%d' % new_dispatcher)
                self.dispatcher_connectors[
                    new_dispatcher] = self.old_connectors.pop(new_dispatcher)
            else:
                log.info('Adding new dispatcher at %s:%d' % new_dispatcher)
                dispatcher_addr, dispatcher_port = new_dispatcher
                factory = DispatcherConnectingFactory(self, dispatcher_addr,
                                                      dispatcher_port)
                self.dispatcher_connectors[
                    new_dispatcher] = reactor.connectTLS(
                        dispatcher_addr, dispatcher_port, factory,
                        self.tls_context)
        for old_dispatcher in self.dispatchers.difference(dispatchers):
            log.info('Removing old dispatcher at %s:%d' % old_dispatcher)
            self.old_connectors[
                old_dispatcher] = self.dispatcher_connectors.pop(
                    old_dispatcher)
            self._check_disconnect(old_dispatcher)
        self.dispatchers = dispatchers

    def got_command(self, dispatcher, command, headers):
        if command == 'summary':
            summary = {
                'ip': RelayConfig.relay_ip,
                'version': __version__,
                'status': self.status,
                'uptime': int(time() - self.start_time),
                'session_count': len(self.session_manager.sessions),
                'stream_count': self.session_manager.stream_count,
                'bps_relayed': self.session_manager.bps_relayed
            }
            return cjson.encode(summary)
        elif command == 'sessions':
            return cjson.encode(self.session_manager.statistics)
        elif command == 'update':
            if self.graceful_shutdown or self.shutting_down:
                if not self.session_manager.has_session(**headers):
                    log.info(
                        'cannot add new session: media-relay is shutting down')
                    return 'halting'
            try:
                local_media = self.session_manager.update_session(
                    dispatcher, **headers)
            except RelayPortsExhaustedError:
                log.error(
                    'Could not reserve relay ports for session, all allocated ports are being used'
                )
                return 'error'
            if local_media:
                return ' '.join(
                    [RelayConfig.advertised_ip or local_media[0][0]] +
                    [str(media[1]) for media in local_media])
        else:  # command == 'remove'
            session = self.session_manager.remove_session(**headers)
            if session is None:
                return 'error'
            else:
                return cjson.encode(session.statistics)

    def session_expired(self, session):
        connector = self.dispatcher_connectors.get(session.dispatcher)
        if connector is None:
            connector = self.old_connectors.get(session.dispatcher)
        if connector and connector.state == 'connected':
            connector.transport.write(' '.join(
                ['expired', cjson.encode(session.statistics)]) +
                                      connector.factory.protocol.delimiter)
        else:
            log.warning(
                'dispatcher for expired session is no longer online, statistics are lost!'
            )

    def add_session(self, dispatcher):
        self.dispatcher_session_count[
            dispatcher] = self.dispatcher_session_count.get(dispatcher, 0) + 1

    def remove_session(self, dispatcher):
        self.dispatcher_session_count[dispatcher] -= 1
        if self.dispatcher_session_count[dispatcher] == 0:
            del self.dispatcher_session_count[dispatcher]
        if self.graceful_shutdown and not self.dispatcher_session_count:
            self._shutdown()
        elif dispatcher in self.old_connectors:
            self._check_disconnect(dispatcher)

    def _check_disconnect(self, dispatcher):
        connector = self.old_connectors[dispatcher]
        if self.dispatcher_session_count.get(dispatcher, 0) == 0:
            old_state = connector.state
            connector.factory.cancel_delayed()
            connector.disconnect()
            if old_state == "disconnected":
                del self.old_connectors[dispatcher]
                if self.shutting_down and len(
                        self.dispatcher_connectors) + len(
                            self.old_connectors) == 0:
                    self._shutdown_done()

    def connector_needs_reconnect(self, connector):
        if connector in self.dispatcher_connectors.values():
            return True
        else:
            for dispatcher, old_connector in self.old_connectors.items():
                if old_connector is connector:
                    if self.dispatcher_session_count.get(dispatcher, 0) > 0:
                        return True
                    else:
                        del self.old_connectors[dispatcher]
                        break
            if self.shutting_down:
                if len(self.old_connectors) == 0:
                    self._shutdown_done()
            return False

    def _shutdown(self, graceful=False):
        if graceful:
            self.graceful_shutdown = True
            if self.dispatcher_session_count:
                return
        if not self.shutting_down:
            self.shutting_down = True
            self.srv_monitor.cancel()
            self.session_manager.cleanup()
            if len(self.dispatcher_connectors) + len(self.old_connectors) == 0:
                self._shutdown_done()
            else:
                self.update_dispatchers([])