Exemple #1
0
    class _BackRelay(protocol.ProcessProtocol):
        def __init__(self, deferred):
            self.deferred = deferred
            self.s = BufferedByteStream()

        def errReceived(self, text):
            self.deferred.errback(failure.Failure(IOError()))
            self.deferred = None
            self.transport.loseConnection()

        def outReceived(self, text):
            self.s.write(text)

        def processEnded(self, reason):
            if self.deferred is not None:
                result = self.s.getvalue()
                self.deferred.callback(result)
Exemple #2
0
    class _BackRelay(protocol.ProcessProtocol):
        def __init__(self, deferred):
            self.deferred = deferred
            self.s = BufferedByteStream()

        def errReceived(self, text):
            self.deferred.errback(failure.Failure(IOError()))
            self.deferred = None
            self.transport.loseConnection()

        def outReceived(self, text):
            self.s.write(text)

        def processEnded(self, reason):
            if self.deferred is not None:
                result = self.s.getvalue()
                self.deferred.callback(result)
Exemple #3
0
class RTMPBaseProtocol(protocol.Protocol):
    """
    Basis RTMP protocol implementation.

    @ivar state: internal state of protocol
    @ivar input: input packet disassebmbler 
    @type input: L{RTMPDisassembler}
    @ivar output: output packet assembler
    @type output: L{RTMPAssembler}
    @ivar handshakeBuf: buffer, holding input data during handshake
    @type handshakeBuf: C{BufferedByteStream}
    """
    class State:
        CONNECTING = 'connecting'
        """
        Connection in progress
        """
        HANDSHAKE_SEND = 'handshake-send'
        """
        Handshake, 1st phase.
        """
        HANDSHAKE_VERIFY = 'handshake-verify'
        """
        Handshake, 2nd phase.
        """
        RUNNING = 'running'
        """
        Usual state of protocol: receiving-sending RTMP packets.
        """

    def __init__(self):
        """
        Constructor.
        """
        self.state = self.State.CONNECTING
        self.handshakeTimeout = None

    def connectionMade(self):
        """
        Successfully connected to peer.
        """
        self.input = RTMPDisassembler(constants.DEFAULT_CHUNK_SIZE)
        self.output = RTMPAssembler(constants.DEFAULT_CHUNK_SIZE,
                                    self.transport)

        self.state = self.State.HANDSHAKE_SEND
        self.handshakeTimeout = reactor.callLater(
            config.getint('RTMP', 'handshakeTimeout'), self._handshakeTimedout)
        self.handshakeBuf = BufferedByteStream()
        self._beginHandshake()

    def _beginHandshake(self):
        """
        Begin handshake procedures.

        Implemented in descendants.
        """
        raise NotImplementedError

    def _handshakeSendReceived(self):
        """
        Data received in HANDSHAKE_SEND state.

        Implemented in descendants.
        """
        raise NotImplementedError

    def _handshakeVerifyReceived(self):
        """
        Data received in HANDSHAKE_VERIFY state.

        Implemented in descendants.
        """
        raise NotImplementedError

    def _handshakeComplete(self):
        """
        Handshake complete, clear timeouts.
        """
        if self.handshakeTimeout is not None:
            self.handshakeTimeout.cancel()
            self.handshakeTimeout = None
        self.state = self.State.RUNNING
        self._regularInput(self.handshakeBuf.read())
        del self.handshakeBuf

    def _handshakeTimedout(self):
        """
        Handshake not completed in timeout.
        """
        self.handshakeTimeout = None
        self.transport.loseConnection()

    def connectionLost(self, reason):
        """
        Connection with peer was lost for some reason.
        """
        if self.handshakeTimeout is not None:
            self.handshakeTimeout.cancel()
            self.handshakeTimeout = None

    def _regularInput(self, data):
        """
        Regular RTMP dataflow: stream of RTMP packets.

        Some bytes (L{data}) was received.

        @param data: bytes received
        @type data: C{str}
        """
        self.input.push_data(data)

        while True:
            packet = self.input.disassemble()
            if packet is None:
                return

            self._handlePacket(packet)

    def dataReceived(self, data):
        """
        Some data was received from peer.

        @param data: bytes received
        @type data: C{str}
        """
        if self.state == self.State.RUNNING:
            self._regularInput(data)
        else:  # handshake
            self.handshakeBuf.seek(0, 2)
            self.handshakeBuf.write(data)
            if self.state == self.State.HANDSHAKE_SEND:
                self._handshakeSendReceived()
            elif self.state == self.State.HANDSHAKE_VERIFY:
                self._handshakeVerifyReceived()

    def _handlePacket(self, packet):
        """
        Dispatch received packet to some handler.

        @param packet: packet
        @type packet: L{Packet}
        """
        log.msg("<- %r" % packet)
        handler = 'handle' + packet.__class__.__name__
        try:
            getattr(self, handler)(packet)
        except AttributeError:
            log.msg("Unhandled packet: %r" % packet)

    def pushPacket(self, packet):
        """
        Push outgoing RTMP packet.

        @param packet: outgoing packet
        @type packet: L{Packet}.
        """
        log.msg("-> %r" % packet)
        self.output.push_packet(packet)
Exemple #4
0
class RTMPBaseProtocol(protocol.Protocol):
    """
    Basis RTMP protocol implementation.

    @ivar state: internal state of protocol
    @ivar input: input packet disassebmbler 
    @type input: L{RTMPDisassembler}
    @ivar output: output packet assembler
    @type output: L{RTMPAssembler}
    @ivar handshakeBuf: buffer, holding input data during handshake
    @type handshakeBuf: C{BufferedByteStream}
    """

    class State:
        CONNECTING = 'connecting'
        """
        Connection in progress
        """
        HANDSHAKE_SEND = 'handshake-send'
        """
        Handshake, 1st phase.
        """
        HANDSHAKE_VERIFY = 'handshake-verify'
        """
        Handshake, 2nd phase.
        """
        RUNNING = 'running'
        """
        Usual state of protocol: receiving-sending RTMP packets.
        """

    def __init__(self):
        """
        Constructor.
        """
        self.state = self.State.CONNECTING
        self.handshakeTimeout = None

    def connectionMade(self):
        """
        Successfully connected to peer.
        """
        self.input = RTMPDisassembler(constants.DEFAULT_CHUNK_SIZE)
        self.output = RTMPAssembler(constants.DEFAULT_CHUNK_SIZE, self.transport)

        self.state = self.State.HANDSHAKE_SEND
        self.handshakeTimeout = reactor.callLater(config.getint('RTMP', 'handshakeTimeout'), self._handshakeTimedout)
        self.handshakeBuf = BufferedByteStream()
        self._beginHandshake()

    def _beginHandshake(self):
        """
        Begin handshake procedures.

        Implemented in descendants.
        """
        raise NotImplementedError

    def _handshakeSendReceived(self):
        """
        Data received in HANDSHAKE_SEND state.

        Implemented in descendants.
        """
        raise NotImplementedError

    def _handshakeVerifyReceived(self):
        """
        Data received in HANDSHAKE_VERIFY state.

        Implemented in descendants.
        """
        raise NotImplementedError

    def _handshakeComplete(self):
        """
        Handshake complete, clear timeouts.
        """
        if self.handshakeTimeout is not None:
            self.handshakeTimeout.cancel()
            self.handshakeTimeout = None
        self.state = self.State.RUNNING
        self._regularInput(self.handshakeBuf.read())
        del self.handshakeBuf

    def _handshakeTimedout(self):
        """
        Handshake not completed in timeout.
        """
        self.handshakeTimeout = None
        self.transport.loseConnection()

    def connectionLost(self, reason):
        """
        Connection with peer was lost for some reason.
        """
        if self.handshakeTimeout is not None:
            self.handshakeTimeout.cancel()
            self.handshakeTimeout = None

    def _regularInput(self, data):
        """
        Regular RTMP dataflow: stream of RTMP packets.

        Some bytes (L{data}) was received.

        @param data: bytes received
        @type data: C{str}
        """
        self.input.push_data(data)

        while True:
            packet = self.input.disassemble()
            if packet is None:
                return

            self._handlePacket(packet)

    def dataReceived(self, data):
        """
        Some data was received from peer.

        @param data: bytes received
        @type data: C{str}
        """
        if self.state == self.State.RUNNING:
            self._regularInput(data)
        else: # handshake
            self.handshakeBuf.seek(0, 2)
            self.handshakeBuf.write(data)
            if self.state == self.State.HANDSHAKE_SEND:
                self._handshakeSendReceived()
            elif self.state == self.State.HANDSHAKE_VERIFY:
                self._handshakeVerifyReceived()

    def _handlePacket(self, packet):
        """
        Dispatch received packet to some handler.

        @param packet: packet
        @type packet: L{Packet}
        """
        log.msg("<- %r" % packet)
        handler = 'handle' + packet.__class__.__name__
        try:
            getattr(self, handler)(packet)
        except AttributeError:
            log.msg("Unhandled packet: %r" % packet)

    def pushPacket(self, packet):
        """
        Push outgoing RTMP packet.

        @param packet: outgoing packet
        @type packet: L{Packet}.
        """
        log.msg("-> %r" % packet)
        self.output.push_packet(packet)
Exemple #5
0
class StreamingChannel(object):
    """
    """


    def __init__(self, channel, streamId, output):
        self.type = None
        self.channel = channel
        self.streamId = streamId
        self.output = output
        self.stream = BufferedByteStream()

        self._lastHeader = None
        self._oldStream = channel.stream
        channel.stream = self.stream

        h = header.Header(channel.channelId)

        # encode a continuation header for speed
        header.encode(self.stream, h, h)

        self._continuationHeader = self.stream.getvalue()
        self.stream.consume()


    def __del__(self):
        try:
            self.channel.stream = self._oldStream
        except:
            pass


    def setType(self, type):
        self.type = type


    def sendData(self, data, timestamp):
        c = self.channel

        if timestamp < c.timestamp:
            relTimestamp = timestamp
        else:
            relTimestamp = timestamp - c.timestamp

        h = header.Header(c.channelId, relTimestamp, self.type, len(data), self.streamId)

        if self._lastHeader is None:
            h.full = True

        c.setHeader(h)
        c.append(data)

        header.encode(self.stream, h, self._lastHeader)
        self._lastHeader = h

        c.marshallOneFrame()

        while not c.complete():
            self.stream.write(self._continuationHeader)
            c.marshallOneFrame()

        c.reset()
        self.output.write(self.stream.getvalue())
        self.stream.consume()
Exemple #6
0
class RTMPDisassembler(object):
    """
    Disassembling bytestream into RTMP packets.

    RTMP stream slices packets into chunks of L{chunkSize}. This class
    processes incoming stream of RTMP protocol data (after initial handshake)
    and decodes RTMP packets.

    Communication goes independently for each object_id. Last received
    headers are stored for each object_id in L{lastHeaders}. L{pool} holds
    incomplete packet contents also for each object_id.

    @ivar lastHeaders: last received header for object_id
    @type lastHeaders: C{dict}, object_id -> L{RTMPHeader}
    @ivar pool: incomplete packet data for object_id
    @type pool: C{dict}, object_id -> L{BufferedByteStream}
    @ivar chunkSize: size of chunk for this stream
    @type chunkSize: C{int}
    @ivar buffer: incoming buffer with data received from protocol
    @type buffer: L{BufferedByteStream}
    """

    def __init__(self, chunkSize):
        """
        Constructor.

        @param chunkSize: initial size of chunk
        @type chunkSize: C{int}
        """
        self.lastHeaders = {}
        self.pool = {}
        self.chunkSize = chunkSize
        self.buffer = BufferedByteStream()

    def push_data(self, data):
        """
        Push more incoming data.

        @param data: data received
        @type data: C{str}
        """
        self.buffer.seek(0, 2)
        self.buffer.write(data)

        return self

    def disassemble(self):
        """
        Disassemble L{buffer} into packets.

        Returns first decoded packet or None, if no packet could
        be decoded at the moment.

        @return: decoded packet
        @rtype: L{Packet}
        """
        self.buffer.seek(0)

        while self.buffer.remaining() > 0:
            try:
                # try to parse header from stream
                header = RTMPHeader.read(self.buffer)
            except NeedBytes, (bytes,):
                # not enough bytes, return what we've already parsed
                return None

            # fill header with extra data from previous headers received
            # with same object_id
            header.fill(self.lastHeaders.get(header.object_id, RTMPHeader()))

            # get buffer for data of this packet
            buf = self.pool.get(header.object_id, BufferedByteStream())

            # this chunk size is minimum of regular chunk size in this
            # disassembler and what we have left here
            thisChunk = min(header.length - len(buf), self.chunkSize)
            if self.buffer.remaining() < thisChunk:
                # we have not enough bytes to read this chunk of data
                return None

            # we got complete chunk
            buf.write(self.buffer.read(thisChunk))

            # store packet header for this object_id
            self.lastHeaders[header.object_id] = header

            # skip data left in input buffer
            self.buffer.consume()

            # this chunk completes full packet?
            if len(buf) < header.length:
                # no, store buffer for further chunks
                self.pool[header.object_id] = buf
            else:
                # parse packet from header and data
                buf.seek(0, 0)

                # delete stored data for this packet
                if header.object_id in self.pool:
                    del self.pool[header.object_id]

                return self._decode_packet(header, buf)

        return None
Exemple #7
0
class StreamingChannel(object):
    """
    """


    def __init__(self, encoder, streamId, output):
        self.encoder = encoder

        self.channel = self.encoder.acquireChannel()

        if self.channel is None:
            # todo: make this better
            raise RuntimeError('No streaming channel available')


        self.type = None
        self.streamId = streamId
        self.output = output
        self.stream = BufferedByteStream()

        self._lastHeader = None
        self._oldStream = self.channel.stream
        self.channel.stream = self.stream

        h = header.Header(self.channel.channelId)

        # encode a continuation header for speed
        header.encode(self.stream, h, h)

        self._continuationHeader = self.stream.getvalue()
        self.stream.consume()


    def __del__(self):
        try:
            self.channel.stream = self._oldStream
        except:
            pass


    def setType(self, type):
        self.type = type


    def sendData(self, data, timestamp):
        c = self.channel

        if timestamp < c.timestamp:
            relTimestamp = timestamp
        else:
            relTimestamp = timestamp - c.timestamp

        h = header.Header(c.channelId, relTimestamp, self.type, len(data), self.streamId)

        if self._lastHeader is None:
            h.full = True

        c.setHeader(h)
        c.append(data)

        header.encode(self.stream, h, self._lastHeader)
        self._lastHeader = h

        c.marshallOneFrame()

        while not c.complete():
            self.stream.write(self._continuationHeader)
            c.marshallOneFrame()

        c.reset()
        s = self.stream.getvalue()
        self.output.write(s)
        self.encoder.bytes += len(s)

        self.stream.consume()
Exemple #8
0
class RTMPDisassembler(object):
    """
    Disassembling bytestream into RTMP packets.

    RTMP stream slices packets into chunks of L{chunkSize}. This class
    processes incoming stream of RTMP protocol data (after initial handshake)
    and decodes RTMP packets.

    Communication goes independently for each object_id. Last received
    headers are stored for each object_id in L{lastHeaders}. L{pool} holds
    incomplete packet contents also for each object_id.

    @ivar lastHeaders: last received header for object_id
    @type lastHeaders: C{dict}, object_id -> L{RTMPHeader}
    @ivar pool: incomplete packet data for object_id
    @type pool: C{dict}, object_id -> L{BufferedByteStream}
    @ivar chunkSize: size of chunk for this stream
    @type chunkSize: C{int}
    @ivar buffer: incoming buffer with data received from protocol
    @type buffer: L{BufferedByteStream}
    """
    def __init__(self, chunkSize):
        """
        Constructor.

        @param chunkSize: initial size of chunk
        @type chunkSize: C{int}
        """
        self.lastHeaders = {}
        self.pool = {}
        self.chunkSize = chunkSize
        self.buffer = BufferedByteStream()

    def push_data(self, data):
        """
        Push more incoming data.

        @param data: data received
        @type data: C{str}
        """
        self.buffer.seek(0, 2)
        self.buffer.write(data)

        return self

    def disassemble(self):
        """
        Disassemble L{buffer} into packets.

        Returns first decoded packet or None, if no packet could
        be decoded at the moment.

        @return: decoded packet
        @rtype: L{Packet}
        """
        self.buffer.seek(0)

        while self.buffer.remaining() > 0:
            try:
                # try to parse header from stream
                header = RTMPHeader.read(self.buffer)
            except NeedBytes, (bytes, ):
                # not enough bytes, return what we've already parsed
                return None

            # fill header with extra data from previous headers received
            # with same object_id
            header.fill(self.lastHeaders.get(header.object_id, RTMPHeader()))

            # get buffer for data of this packet
            buf = self.pool.get(header.object_id, BufferedByteStream())

            # this chunk size is minimum of regular chunk size in this
            # disassembler and what we have left here
            thisChunk = min(header.length - len(buf), self.chunkSize)
            if self.buffer.remaining() < thisChunk:
                # we have not enough bytes to read this chunk of data
                return None

            # we got complete chunk
            buf.write(self.buffer.read(thisChunk))

            # store packet header for this object_id
            self.lastHeaders[header.object_id] = header

            # skip data left in input buffer
            self.buffer.consume()

            # this chunk completes full packet?
            if len(buf) < header.length:
                # no, store buffer for further chunks
                self.pool[header.object_id] = buf
            else:
                # parse packet from header and data
                buf.seek(0, 0)

                # delete stored data for this packet
                if header.object_id in self.pool:
                    del self.pool[header.object_id]

                return self._decode_packet(header, buf)

        return None