Exemple #1
0
        /// <summary>
        /// Decodes a RTMP packet.
        /// </summary>
        /// <param name="context">RTMP protocol state.</param>
        /// <param name="stream">Buffer to be decoded.</param>
        /// <returns>The decoded RTMP packet.</returns>
        public static RtmpPacket DecodePacket(RtmpContext context, ByteBuffer stream)
        {
            int remaining = stream.Remaining;

            // We need at least one byte
            if (remaining < 1)
            {
#if !SILVERLIGHT
                if (log.IsDebugEnabled)
                {
                    log.Debug(__Res.GetString(__Res.Rtmp_DataBuffering, remaining, 1));
                }
#endif
                context.SetBufferDecoding(1);
                return(null);
            }
            int  position   = (int)stream.Position;
            byte headerByte = stream.Get();
            int  headerValue;
            int  byteCount;
            if ((headerByte & 0x3f) == 0)
            {
                // Two byte header
                if (remaining < 2)
                {
                    stream.Position = position;
#if !SILVERLIGHT
                    if (log.IsDebugEnabled)
                    {
                        log.Debug(__Res.GetString(__Res.Rtmp_DataBuffering, remaining, 2));
                    }
#endif
                    context.SetBufferDecoding(2);
                    return(null);
                }
                headerValue = ((int)headerByte & 0xff) << 8 | ((int)stream.Get() & 0xff);
                byteCount   = 2;
            }
            else if ((headerByte & 0x3f) == 1)
            {
                // Three byte header
                if (remaining < 3)
                {
                    stream.Position = position;
#if !SILVERLIGHT
                    if (log.IsDebugEnabled)
                    {
                        log.Debug(__Res.GetString(__Res.Rtmp_DataBuffering, remaining, 3));
                    }
#endif
                    context.SetBufferDecoding(3);
                    return(null);
                }
                headerValue = ((int)headerByte & 0xff) << 16 | ((int)stream.Get() & 0xff) << 8 | ((int)stream.Get() & 0xff);
                byteCount   = 3;
            }
            else
            {
                // Single byte header
                headerValue = (int)headerByte & 0xff;
                byteCount   = 1;
            }
            byte channelId = DecodeChannelId(headerValue, byteCount);
            if (channelId < 0)
            {
                throw new ProtocolException("Bad channel id: " + channelId);
            }
            byte headerSize   = DecodeHeaderSize(headerValue, byteCount);
            int  headerLength = GetHeaderLength(headerSize);
            headerLength += byteCount - 1;

            //if(headerLength > remaining)
            if (headerLength + byteCount - 1 > remaining)
            {
#if !SILVERLIGHT
                if (log.IsDebugEnabled)
                {
                    log.Debug(__Res.GetString(__Res.Rtmp_HeaderBuffering, remaining));
                }
#endif
                stream.Position = position;
                //context.SetBufferDecoding(headerLength);
                context.SetBufferDecoding(headerLength + byteCount - 1);
                return(null);
            }
            // Move the position back to the start
            stream.Position = position;

            RtmpHeader header = DecodeHeader(context, context.GetLastReadHeader(channelId), stream);
#if !SILVERLIGHT
            log.Debug("Decoded " + header);
#endif

            if (header == null)
            {
                throw new ProtocolException("Header is null, check for error");
            }

            // Save the header
            context.SetLastReadHeader(channelId, header);
            // Check to see if this is a new packet or continue decoding an existing one.
            RtmpPacket packet = context.GetLastReadPacket(channelId);
            if (packet == null)
            {
                packet = new RtmpPacket(header);
                context.SetLastReadPacket(channelId, packet);
            }

            ByteBuffer buf     = packet.Data;
            int        addSize = (header.Timer == 0xffffff ? 4 : 0);
            //int addSize = 0;
            int readRemaining = header.Size + addSize - (int)buf.Position;
            int chunkSize     = context.GetReadChunkSize();
            int readAmount    = (readRemaining > chunkSize) ? chunkSize : readRemaining;
            if (stream.Remaining < readAmount)
            {
#if !SILVERLIGHT
                if (log.IsDebugEnabled)
                {
                    log.Debug(__Res.GetString(__Res.Rtmp_ChunkSmall, stream.Remaining, readAmount));
                }
#endif
                //Skip the position back to the start
                stream.Position = position;
                context.SetBufferDecoding(headerLength + readAmount);

                //string path = GodLesZ.Library.Amf.Context.FluorineContext.Current.GetFullPath(@"log\chunk.bin");
                //stream.Dump(path);
                return(null);
            }

            //http://osflash.org/pipermail/free_osflash.org/2005-September/000261.html
            //http://www.acmewebworks.com/Downloads/openCS/091305-initialMeeting.txt
            ByteBuffer.Put(buf, stream, readAmount);
            if (buf.Position < header.Size + addSize)
            {
                context.ContinueDecoding();
                return(null);
            }
            if (buf.Position > header.Size + addSize)
            {
#if !SILVERLIGHT
                log.Warn(string.Format("Packet size expanded from {0} to {1} ({2})", header.Size + addSize, buf.Position, header));
#endif
            }

            buf.Flip();

            try {
                IRtmpEvent message = DecodeMessage(context, packet.Header, buf);
                packet.Message = message;

                if (message is ChunkSize)
                {
                    ChunkSize chunkSizeMsg = message as ChunkSize;
                    context.SetReadChunkSize(chunkSizeMsg.Size);
                }
            } finally {
                context.SetLastReadPacket(channelId, null);
            }
#if !SILVERLIGHT
            if (log.IsDebugEnabled)
            {
                log.Debug("Decoded " + packet.ToString());
            }
#endif
            return(packet);
        }
		/// <summary>
		/// Decodes a RTMP packet.
		/// </summary>
		/// <param name="context">RTMP protocol state.</param>
		/// <param name="stream">Buffer to be decoded.</param>
		/// <returns>The decoded RTMP packet.</returns>
		public static RtmpPacket DecodePacket(RtmpContext context, ByteBuffer stream) {
			int remaining = stream.Remaining;
			// We need at least one byte
			if (remaining < 1) {
#if !SILVERLIGHT
				if (log.IsDebugEnabled)
					log.Debug(__Res.GetString(__Res.Rtmp_DataBuffering, remaining, 1));
#endif
				context.SetBufferDecoding(1);
				return null;
			}
			int position = (int)stream.Position;
			byte headerByte = stream.Get();
			int headerValue;
			int byteCount;
			if ((headerByte & 0x3f) == 0) {
				// Two byte header
				if (remaining < 2) {
					stream.Position = position;
#if !SILVERLIGHT
					if (log.IsDebugEnabled)
						log.Debug(__Res.GetString(__Res.Rtmp_DataBuffering, remaining, 2));
#endif
					context.SetBufferDecoding(2);
					return null;
				}
				headerValue = ((int)headerByte & 0xff) << 8 | ((int)stream.Get() & 0xff);
				byteCount = 2;
			} else if ((headerByte & 0x3f) == 1) {
				// Three byte header
				if (remaining < 3) {
					stream.Position = position;
#if !SILVERLIGHT
					if (log.IsDebugEnabled)
						log.Debug(__Res.GetString(__Res.Rtmp_DataBuffering, remaining, 3));
#endif
					context.SetBufferDecoding(3);
					return null;
				}
				headerValue = ((int)headerByte & 0xff) << 16 | ((int)stream.Get() & 0xff) << 8 | ((int)stream.Get() & 0xff);
				byteCount = 3;
			} else {
				// Single byte header
				headerValue = (int)headerByte & 0xff;
				byteCount = 1;
			}
			byte channelId = DecodeChannelId(headerValue, byteCount);
			if (channelId < 0)
				throw new ProtocolException("Bad channel id: " + channelId);
			byte headerSize = DecodeHeaderSize(headerValue, byteCount);
			int headerLength = GetHeaderLength(headerSize);
			headerLength += byteCount - 1;

			//if(headerLength > remaining) 
			if (headerLength + byteCount - 1 > remaining) {
#if !SILVERLIGHT
				if (log.IsDebugEnabled)
					log.Debug(__Res.GetString(__Res.Rtmp_HeaderBuffering, remaining));
#endif
				stream.Position = position;
				//context.SetBufferDecoding(headerLength);
				context.SetBufferDecoding(headerLength + byteCount - 1);
				return null;
			}
			// Move the position back to the start
			stream.Position = position;

			RtmpHeader header = DecodeHeader(context, context.GetLastReadHeader(channelId), stream);
#if !SILVERLIGHT
			log.Debug("Decoded " + header);
#endif

			if (header == null)
				throw new ProtocolException("Header is null, check for error");

			// Save the header
			context.SetLastReadHeader(channelId, header);
			// Check to see if this is a new packet or continue decoding an existing one.
			RtmpPacket packet = context.GetLastReadPacket(channelId);
			if (packet == null) {
				packet = new RtmpPacket(header);
				context.SetLastReadPacket(channelId, packet);
			}

			ByteBuffer buf = packet.Data;
			int addSize = (header.Timer == 0xffffff ? 4 : 0);
			//int addSize = 0;
			int readRemaining = header.Size + addSize - (int)buf.Position;
			int chunkSize = context.GetReadChunkSize();
			int readAmount = (readRemaining > chunkSize) ? chunkSize : readRemaining;
			if (stream.Remaining < readAmount) {
#if !SILVERLIGHT
				if (log.IsDebugEnabled)
					log.Debug(__Res.GetString(__Res.Rtmp_ChunkSmall, stream.Remaining, readAmount));
#endif
				//Skip the position back to the start
				stream.Position = position;
				context.SetBufferDecoding(headerLength + readAmount);

				//string path = GodLesZ.Library.Amf.Context.FluorineContext.Current.GetFullPath(@"log\chunk.bin");
				//stream.Dump(path);
				return null;
			}

			//http://osflash.org/pipermail/free_osflash.org/2005-September/000261.html
			//http://www.acmewebworks.com/Downloads/openCS/091305-initialMeeting.txt
			ByteBuffer.Put(buf, stream, readAmount);
			if (buf.Position < header.Size + addSize) {
				context.ContinueDecoding();
				return null;
			}
			if (buf.Position > header.Size + addSize) {
#if !SILVERLIGHT
				log.Warn(string.Format("Packet size expanded from {0} to {1} ({2})", header.Size + addSize, buf.Position, header));
#endif
			}

			buf.Flip();

			try {
				IRtmpEvent message = DecodeMessage(context, packet.Header, buf);
				packet.Message = message;

				if (message is ChunkSize) {
					ChunkSize chunkSizeMsg = message as ChunkSize;
					context.SetReadChunkSize(chunkSizeMsg.Size);
				}
			} finally {
				context.SetLastReadPacket(channelId, null);
			}
#if !SILVERLIGHT
			if (log.IsDebugEnabled) {
				log.Debug("Decoded " + packet.ToString());
			}
#endif
			return packet;
		}
Exemple #3
0
        /// <summary>
        /// Decodes handshake message.
        /// </summary>
        /// <param name="context">RTMP protocol state.</param>
        /// <param name="stream">Buffer to be decoded.</param>
        /// <returns>Buffer with handshake response.</returns>
        public static object DecodeHandshake(RtmpContext context, ByteBuffer stream)
        {
            long remaining = stream.Remaining;

            if (context.Mode == RtmpMode.Server)
            {
                if (context.State == RtmpState.Connect)
                {
                    if (remaining < HandshakeSize + 1)
                    {
#if !SILVERLIGHT
                        if (log.IsDebugEnabled)
                        {
                            log.Debug(__Res.GetString(__Res.Rtmp_HSInitBuffering, remaining));
                        }
#endif
                        context.SetBufferDecoding(HandshakeSize + 1);
                        return(null);
                    }
                    else
                    {
#if !SILVERLIGHT
                        if (log.IsDebugEnabled)
                        {
                            log.Debug("Handshake 1st phase");
                        }
#endif
                        stream.Get();                        // skip the header byte
                        byte[] handshake = RtmpHandshake.GetHandshakeResponse(stream);
                        context.SetHandshake(handshake);
                        context.State = RtmpState.Handshake;
                        return(handshake);
                    }
                }
                if (context.State == RtmpState.Handshake)
                {
                    //if (log.IsDebugEnabled)
                    //    log.Debug("Handshake reply");

                    if (remaining < HandshakeSize)
                    {
#if !SILVERLIGHT
                        if (log.IsDebugEnabled)
                        {
                            log.Debug(__Res.GetString(__Res.Rtmp_HSReplyBuffering, remaining));
                        }
#endif
                        context.SetBufferDecoding(HandshakeSize);
                        return(null);
                    }
                    else
                    {
                        // Skip first 8 bytes when comparing the handshake, they seem to be changed when connecting from a Mac client.
                        if (!context.ValidateHandshakeReply(stream, 8, HandshakeSize - 8))
                        {
#if !SILVERLIGHT
                            if (log.IsDebugEnabled)
                            {
                                log.Debug("Handshake reply validation failed, disconnecting client.");
                            }
#endif
                            stream.Skip(HandshakeSize);
                            context.State = RtmpState.Error;
                            throw new HandshakeFailedException("Handshake validation failed");
                        }
                        stream.Skip(HandshakeSize);
                        context.State = RtmpState.Connected;
                        context.ContinueDecoding();
                        return(null);
                    }
                }
            }
            else
            {
                //Client mode
                if (context.State == RtmpState.Connect)
                {
                    int size = (2 * HandshakeSize) + 1;
                    if (remaining < size)
                    {
#if !SILVERLIGHT
                        if (log.IsDebugEnabled)
                        {
                            log.Debug(__Res.GetString(__Res.Rtmp_HSInitBuffering, remaining));
                        }
#endif
                        context.SetBufferDecoding(size);
                        return(null);
                    }
                    else
                    {
                        ByteBuffer hs = ByteBuffer.Allocate(size);
                        ByteBuffer.Put(hs, stream, size);
                        hs.Flip();
                        context.State = RtmpState.Handshake;
                        return(hs);
                    }
                }
            }
            return(null);
        }
		/// <summary>
		/// Decodes handshake message.
		/// </summary>
		/// <param name="context">RTMP protocol state.</param>
		/// <param name="stream">Buffer to be decoded.</param>
		/// <returns>Buffer with handshake response.</returns>
		public static object DecodeHandshake(RtmpContext context, ByteBuffer stream) {
			long remaining = stream.Remaining;
			if (context.Mode == RtmpMode.Server) {
				if (context.State == RtmpState.Connect) {
					if (remaining < HandshakeSize + 1) {
#if !SILVERLIGHT
						if (log.IsDebugEnabled)
							log.Debug(__Res.GetString(__Res.Rtmp_HSInitBuffering, remaining));
#endif
						context.SetBufferDecoding(HandshakeSize + 1);
						return null;
					} else {
#if !SILVERLIGHT
						if (log.IsDebugEnabled)
							log.Debug("Handshake 1st phase");
#endif
						stream.Get();// skip the header byte
						byte[] handshake = RtmpHandshake.GetHandshakeResponse(stream);
						context.SetHandshake(handshake);
						context.State = RtmpState.Handshake;
						return handshake;
					}
				}
				if (context.State == RtmpState.Handshake) {
					//if (log.IsDebugEnabled)
					//    log.Debug("Handshake reply");

					if (remaining < HandshakeSize) {
#if !SILVERLIGHT
						if (log.IsDebugEnabled)
							log.Debug(__Res.GetString(__Res.Rtmp_HSReplyBuffering, remaining));
#endif
						context.SetBufferDecoding(HandshakeSize);
						return null;
					} else {
						// Skip first 8 bytes when comparing the handshake, they seem to be changed when connecting from a Mac client.
						if (!context.ValidateHandshakeReply(stream, 8, HandshakeSize - 8)) {
#if !SILVERLIGHT
							if (log.IsDebugEnabled)
								log.Debug("Handshake reply validation failed, disconnecting client.");
#endif
							stream.Skip(HandshakeSize);
							context.State = RtmpState.Error;
							throw new HandshakeFailedException("Handshake validation failed");
						}
						stream.Skip(HandshakeSize);
						context.State = RtmpState.Connected;
						context.ContinueDecoding();
						return null;
					}
				}
			} else {
				//Client mode
				if (context.State == RtmpState.Connect) {
					int size = (2 * HandshakeSize) + 1;
					if (remaining < size) {
#if !SILVERLIGHT
						if (log.IsDebugEnabled)
							log.Debug(__Res.GetString(__Res.Rtmp_HSInitBuffering, remaining));
#endif
						context.SetBufferDecoding(size);
						return null;
					} else {
						ByteBuffer hs = ByteBuffer.Allocate(size);
						ByteBuffer.Put(hs, stream, size);
						hs.Flip();
						context.State = RtmpState.Handshake;
						return hs;
					}
				}
			}
			return null;
		}