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; } } }
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; } }