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; }
protected override bool PerformHandshake(InputStream buffer) { switch (_rtmpState) { case RTMPState.RTMP_STATE_NOT_INITIALIZED: return PerformHandshakeStage1((string)CustomParameters[Defines.CONF_PROTOCOL] == Defines.CONF_PROTOCOL_OUTBOUND_RTMPE); case RTMPState.RTMP_STATE_CLIENT_REQUEST_SENT: if (buffer.AvaliableByteCounts < 3073) return true; _usedScheme = (byte) ((string) CustomParameters[Defines.CONF_PROTOCOL] == Defines.CONF_PROTOCOL_OUTBOUND_RTMPE? 1: 0); if (!PerformHandshakeStage2(buffer, _usedScheme==1)) { Logger.FATAL("Unable to handshake"); return false; } if (!EnqueueForOutbound(OutputBuffer)) { Logger.FATAL("Unable to signal output data"); return false; } if (_pKeyIn != null && _pKeyOut != null) { var pRTMPE = new RTMPEProtocol(_pKeyIn, _pKeyOut, (uint)OutputBuffer.Length); ResetFarProtocol(); _farProtocol.NearProtocol = pRTMPE; pRTMPE.NearProtocol = this; this.Log().Info("New protocol chain:{0}",_farProtocol); } buffer.Ignore(3073); _handshakeCompleted = true; return true; default: Logger.FATAL("Invalid RTMP state:{0}",_rtmpState); return false; } }
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; } } }