public override bool SignalInputData(InputStream inputStream, IPEndPoint address) { var reader = inputStream.Reader; var id = reader.ReadUInt32() ^ reader.ReadUInt32() ^ reader.ReadUInt32(); reader.BaseStream.Position = 4; lock (Session.OutputBuffer) { Session.Decode(reader); Session.SetEndPoint(address); Session.PacketHandler(reader); } inputStream.Recycle(true); 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; } } }
bool PerformHandshake(InputStream buffer, bool encrypted) { if (!ValidateClient(buffer)) { if (encrypted || _pProtocolHandler.ValidateHandshake) { Logger.FATAL("Unable to validate client"); return false; } else { Logger.WARN("Client not validated"); _validationScheme = 0; } } _pOutputBuffer = Utils.GenerateRandomBytes(3072); _pOutputBuffer.Write(0, (uint)DateTime.Now.SecondsFrom1970()); _pOutputBuffer.Write(0, (uint)0); var serverBytes = Encoding.ASCII.GetBytes(Defines.HTTP_HEADERS_SERVER_US); for (var i = 0; i < 10; i++) { var index = Utils.Random.Next(0, 3072 - Defines.HTTP_HEADERS_SERVER_US_LEN); Buffer.BlockCopy(serverBytes, 0, _pOutputBuffer, index, serverBytes.Length); } var _pOutputBufferWithOffset = new BufferWithOffset(_pOutputBuffer); var pInputBuffer = new BufferWithOffset(buffer); var serverDHOffset = GetDHOffset(_pOutputBufferWithOffset, _validationScheme); var clientDHOffset = GetDHOffset(pInputBuffer, _validationScheme); var dhWrapper = new DHWrapper(); var pubKeyIn = new byte[128]; Buffer.BlockCopy(buffer.GetBuffer(), (int)(buffer.Position + clientDHOffset), pubKeyIn, 0, 128); var sharedkey = dhWrapper.CreateSharedKey(pubKeyIn); var pubKeyOut = dhWrapper.PublicKey; Buffer.BlockCopy(pubKeyOut, 0, _pOutputBuffer, (int)serverDHOffset, 128); if (encrypted) { _pKeyIn = new RC4_KEY(); _pKeyOut = new RC4_KEY(); Utils.InitRC4Encryption(sharedkey, pubKeyIn, pubKeyOut, _pKeyIn, _pKeyOut); var data = new byte[1536]; Utils.RC4(data, _pKeyIn, 1536); Utils.RC4(data, _pKeyOut, 1536); } var serverDigestOffset = GetDigestOffset(_pOutputBufferWithOffset, _validationScheme); var pTempBuffer = new byte[1536 - 32]; Buffer.BlockCopy(_pOutputBuffer, 0, pTempBuffer, 0, (int)serverDigestOffset); Buffer.BlockCopy(_pOutputBuffer, (int)serverDigestOffset + 32, pTempBuffer, (int)serverDigestOffset, (int)(1536 - serverDigestOffset - 32)); var pTempHash = HMACsha256(pTempBuffer, 1536 - 32, GenuineFmsKey, 36); Buffer.BlockCopy(pTempHash, 0, _pOutputBuffer, (int)serverDigestOffset, 32); var keyChallengeIndex = GetDigestOffset(pInputBuffer, _validationScheme); pInputBuffer.Offset += (int)keyChallengeIndex; pTempHash = HMACsha256(pInputBuffer, 32, GenuineFmsKey, 68); Buffer.BlockCopy(_pOutputBuffer, 1536, pTempBuffer, 0, 1536 - 32); pTempBuffer = new HMACSHA256(pTempHash).ComputeHash(pTempBuffer, 0, 1536 - 32); Buffer.BlockCopy(pTempBuffer, 0, _pOutputBuffer, 1536 * 2 - 32, 32); OutputBuffer.WriteByte((byte)(encrypted ? 6 : 3)); OutputBuffer.Write(_pOutputBuffer, 0, 3072); buffer.Recycle(true); if (!EnqueueForOutbound(OutputBuffer)) { Logger.FATAL("Unable to signal outbound data"); return false; } _rtmpState = RTMPState.RTMP_STATE_SERVER_RESPONSE_SENT; return true; }