protected override bool PerformHandshake(InputStream buffer)
        {
            switch (_rtmpState)
            {
                case RTMPState.RTMP_STATE_NOT_INITIALIZED:
                    if (buffer.AvaliableByteCounts < 1537) return true;
                    var handshakeType = buffer.ReadByte();
                    var temp = new byte[4];
                    _currentFPVersion = (uint)IPAddress.NetworkToHostOrder(BitConverter.ToInt32(buffer.GetBuffer(), (int)(buffer.Position + 4)));
                    switch (handshakeType)
                    {
                        case 3: //plain

                            return PerformHandshake(buffer, false);

                        case 6: //encrypted

                            return PerformHandshake(buffer, true);

                        default:

                            Logger.FATAL("Handshake type not implemented: {0}", handshakeType);
                            return false;

                    }
                case RTMPState.RTMP_STATE_SERVER_RESPONSE_SENT:
                    if (buffer.AvaliableByteCounts < 1537) return true;
                    buffer.Ignore(1536);
                    _handshakeCompleted = true;
                    _rtmpState = RTMPState.RTMP_STATE_DONE;
                    if (_pKeyIn != null && _pKeyOut != null)
                    {
                        //insert the RTMPE protocol in the current protocol stack
                        BaseProtocol pFarProtocol = FarProtocol;
                        var pRTMPE = new RTMPEProtocol(_pKeyIn, _pKeyOut);
                        ResetFarProtocol();
                        pFarProtocol.NearProtocol = pRTMPE;
                        pRTMPE.NearProtocol = this;
                        this.Log().Info("New protocol chain: {0}", pFarProtocol);
                        //decrypt the leftovers
                        Utils.RC4(new BufferWithOffset(buffer), _pKeyIn, buffer.AvaliableByteCounts);
                    }
                    return true;
                default:

                    Logger.FATAL("Invalid RTMP state: {0}", _rtmpState);
                    return false;

            }
            return true;
        }
        private bool ProcessBytes(InputStream buffer)
        {
            while (true)
            {
                var availableBytesCount = buffer.AvaliableByteCounts;
                if (_selectedChannel < 0)
                {
                    if (availableBytesCount < 1) return true;
                    var temp = buffer.ReadByte();
                    switch (temp & 0x3f)
                    {
                        case 0:
                            if (availableBytesCount < 2)
                            {
                                FINEST("Not enough data");
                                return true;
                            }
                            _selectedChannel = 64 + buffer.ReadByte();
                            GetChannel((uint)_selectedChannel).lastInHeaderType = (byte) (temp >> 6);
                            availableBytesCount -= 2;
                            break;
                        case 1:
                            FATAL("The server doesn't support channel ids bigger than 319");
                            return false;
                        default:
                            _selectedChannel = temp & 0x3f;
                            GetChannel((uint)_selectedChannel).lastInHeaderType = (byte) (temp >> 6);
                            availableBytesCount -= 1;
                            break;
                    }
                }
                if (_selectedChannel >= MAX_CHANNELS_COUNT)
                {
                    FATAL("Bogus connection. Drop it like is hot");
                    return false;
                }
                var channel = GetChannel((uint)_selectedChannel);
                switch (channel.state)
                {
                    case Channel.CS_HEADER:
                        if (!channel.lastInHeader.Read((uint)_selectedChannel, channel.lastInHeaderType, buffer, availableBytesCount))
                        {
                            FATAL("Unable to read header");
                            return false;
                        }
                        if (!channel.lastInHeader.ReadCompleted) return true;
                   
                        var ts = channel.lastInHeader.TimeStramp;
                        switch (channel.lastInHeaderType)
                        {
                            case HT_FULL:
                                channel.lastInAbsTs = ts;
                                break;
                            case HT_SAME_STREAM:
                            case HT_SAME_LENGTH_AND_STREAM:
                                channel.lastInAbsTs += ts;
                                break;
                            case HT_CONTINUATION:
                                if (channel.lastInProcBytes == 0)
                                    channel.lastInAbsTs += ts;
                                break;
                        }
                        channel.state = Channel.CS_PAYLOAD;
                        goto case Channel.CS_PAYLOAD;
               
                    case Channel.CS_PAYLOAD:
                        var ml = channel.lastInHeader.MessageLength;
                        var si = channel.lastInHeader.StreamId;
                        var tempSize = ml - channel.lastInProcBytes;
                        tempSize = tempSize >= _inboundChunkSize ? _inboundChunkSize : tempSize;
                        if (tempSize > buffer.AvaliableByteCounts) return true;
                        channel.state = Channel.CS_HEADER;
                        _selectedChannel = -1;
                        var msgType = channel.lastInHeader.MessageType;
                        switch (msgType)
                        {
                            case RM_HEADER_MESSAGETYPE_VIDEODATA:
                                if (si >= MAX_STREAMS_COUNT)
                                {
                                    FATAL("The server doesn't support stream ids bigger than {0}", MAX_STREAMS_COUNT);
                                    return false;
                                }
                                if (_streams[si]?.Type == ST_IN_NET_RTMP)
                                {
                                    if (!_streams[si].FeedData(buffer,
                                        tempSize, channel.lastInProcBytes, ml, channel.lastInAbsTs, false))
                                    {
                                        FATAL("Unable to feed video");
                                        return false;
                                    }
                                }
                                channel.lastInProcBytes += tempSize;
                                if (ml == channel.lastInProcBytes)channel.lastInProcBytes = 0;
                                buffer.Ignore(tempSize);
                                break;
                            case RM_HEADER_MESSAGETYPE_AUDIODATA:
                                if (si >= MAX_STREAMS_COUNT)
                                {
                                    FATAL("The server doesn't support stream ids bigger than {0}",MAX_STREAMS_COUNT);
                                    return false;
                                }

                                if (_streams[si]?.Type == ST_IN_NET_RTMP)
                                {
                                    if (!_streams[si].FeedData(buffer,
                                        tempSize, channel.lastInProcBytes, ml, channel.lastInAbsTs, true))
                                    {
                                        FATAL("Unable to feed video");
                                        return false;
                                    }
                                }
                                channel.lastInProcBytes += tempSize;
                                if (ml == channel.lastInProcBytes)
                                {
                                    channel.lastInProcBytes = 0;
                                }
                                buffer.Ignore(tempSize);
                                break;
                            default:
                                buffer.CopyPartTo(channel.inputData.BaseStream, (int)tempSize);
                                buffer.Recycle();
                                channel.lastInProcBytes += tempSize;

                                if (ml == channel.lastInProcBytes)
                                {
                                    channel.lastInProcBytes = 0;
                                    if (_pProtocolHandler == null)
                                    {
                                        FATAL("RTMP connection no longer associated with an application");
                                        return false;
                                    }
                                    channel.inputData.BaseStream.Position = 0;
                                   
                                    if (msgType != 0)
                                    {
                                        var messageBody = _rtmpProtocolSerializer.Deserialize(msgType, channel.inputData);
                                        bool recycleBody;
                                        if (!_pProtocolHandler.InboundMessageAvailable(this, messageBody, channel, out recycleBody))
                                        {
                                            if (recycleBody) messageBody.Recycle();
                                            FATAL("Unable to send rtmp message to application");
                                            return false;
                                        }

                                        if (recycleBody) messageBody.Recycle();
                                        _rxInvokes++;
                                        if (channel.inputData.BaseStream.Position < channel.inputData.BaseStream.Length)
                                        {
                                            FATAL("Invalid message!!! We have leftovers:{0} bytes",
                                                channel.inputData.BaseStream.Position < channel.inputData.BaseStream.Length);
                                            return false;
                                        }
                                    }
                                    channel.inputData.BaseStream.Recycle();
                                }
                                break;
                        }
                        break;
                }
            }
        }
Exemple #3
0
        public bool Read(uint channelId, byte type, InputStream buffer, uint availableBytes)
        {
            HeaderType = type;
            ChannelId = channelId;
            var reader = buffer.Reader;
            //var temp = hf.datac;
            switch (HeaderType)
            {
                case HT_FULL:
                    IsAbsolute = true;
                    if (availableBytes < 11)
                    {
                        ReadCompleted = false;
                        return true;
                    }
                    TimeStramp = reader.ReadU24();
                    MessageLength = reader.ReadU24();
                    MessageType = (byte) buffer.ReadByte();
                    //StreamId = ((uint)buffer.ReadByte()) | ((uint)buffer.ReadByte() << 8) | ((uint)buffer.ReadByte() << 16) | ((uint)buffer.ReadByte() << 24);
                    StreamId = reader._ReadUInt32();
                    if (TimeStramp == 0x00ffffff)
                    {
                        Skip4Bytes = true;
                        if (availableBytes < 15)
                        {
                            ReadCompleted = false;
                            return true;
                        }
                        TimeStramp = reader.ReadUInt32();
                        ReadCompleted = true;
                        return true;
                    }
                    Skip4Bytes = false;
                    ReadCompleted = true;
                    return true;
                case HT_SAME_STREAM:
                    IsAbsolute = false;
                    if (availableBytes < 7)
                    {
                        ReadCompleted = false;
                        return true;
                    }
                    TimeStramp = reader.ReadU24();
                    MessageLength = reader.ReadU24();
                    MessageType = (byte) buffer.ReadByte();
                    //buffer.Read(temp, 1, 7);
                    //hf.datac = temp;
                    //ts = (uint)IPAddress.NetworkToHostOrder((int)ts) & 0x00ffffff;
                    //ml = (uint)IPAddress.NetworkToHostOrder((int)ml) >>8;
                    if (TimeStramp == 0x00ffffff)
                    {
                        Skip4Bytes = true;
                        if (availableBytes < 11)
                        {
                            ReadCompleted = false;
                            return true;
                        }
                        TimeStramp = reader.ReadUInt32();
                        ReadCompleted = true;
                        return true;
                    }
                    Skip4Bytes = false;
                    ReadCompleted = true;
                    return true;
                case HT_SAME_LENGTH_AND_STREAM:
                    IsAbsolute = false;
                    if (availableBytes < 3)
                    {
                        ReadCompleted = false;
                        return true;
                    }
                    TimeStramp = reader.ReadU24();
                    //buffer.Read(temp, 1, 3);
                    //hf.datac = temp;
                    //ts = (uint)IPAddress.NetworkToHostOrder((int)ts) & 0x00ffffff;

                    if (TimeStramp == 0x00ffffff)
                    {
                        Skip4Bytes = true;
                        if (availableBytes < 7)
                        {
                            ReadCompleted = false;
                            return true;
                        }
                        TimeStramp = reader.ReadUInt32();
                        ReadCompleted = true;
                        return true;
                    }
                    Skip4Bytes = false;
                    ReadCompleted = true;
                    return true;
                case HT_CONTINUATION:
                    IsAbsolute = false;
                    ReadCompleted = !Skip4Bytes || availableBytes >= 4;
                    return true;
                default:
                    Logger.FATAL("Invalid header type");
                    return false;
            }
        }