static void EncodeSharedObject(RtmpContext context, ISharedObjectMessage so, ByteBuffer output) {
			RtmpWriter writer = new RtmpWriter(output);
			//Set legacy collection flag from context
			writer.UseLegacyCollection = context.UseLegacyCollection;
			writer.UseLegacyThrowable = context.UseLegacyThrowable;

			writer.WriteUTF(so.Name);
			// SO version
			writer.WriteInt32(so.Version);
			// Encoding (this always seems to be 2 for persistent shared objects)
			writer.WriteInt32(so.IsPersistent ? 2 : 0);
			// unknown field
			writer.WriteInt32(0);

			int mark, len = 0;

			foreach (ISharedObjectEvent sharedObjectEvent in so.Events) {
				byte type = SharedObjectTypeMapping.ToByte(sharedObjectEvent.Type);
				switch (sharedObjectEvent.Type) {
					case SharedObjectEventType.SERVER_CONNECT:
					case SharedObjectEventType.CLIENT_INITIAL_DATA:
					case SharedObjectEventType.CLIENT_CLEAR_DATA:
						writer.WriteByte(type);
						writer.WriteInt32(0);
						break;
					case SharedObjectEventType.SERVER_DELETE_ATTRIBUTE:
					case SharedObjectEventType.CLIENT_DELETE_DATA:
					case SharedObjectEventType.CLIENT_UPDATE_ATTRIBUTE:
						writer.WriteByte(type);
						mark = (int)output.Position;
						output.Skip(4); // we will be back
						writer.WriteUTF(sharedObjectEvent.Key);
						len = (int)output.Position - mark - 4;
						output.PutInt(mark, len);
						break;
					case SharedObjectEventType.SERVER_SET_ATTRIBUTE:
					case SharedObjectEventType.CLIENT_UPDATE_DATA:
						if (sharedObjectEvent.Key == null) {
							// Update multiple attributes in one request
							IDictionary initialData = sharedObjectEvent.Value as IDictionary;
							foreach (DictionaryEntry entry in initialData) {
								writer.WriteByte(type);
								mark = (int)output.Position;
								output.Skip(4); // we will be back
								string key = entry.Key as string;
								object value = entry.Value;
								writer.WriteUTF(key);
								writer.WriteData(context.ObjectEncoding, value);

								len = (int)output.Position - mark - 4;
								output.PutInt(mark, len);
							}
						} else {
							writer.WriteByte(type);
							mark = (int)output.Position;
							output.Skip(4); // we will be back
							writer.WriteUTF(sharedObjectEvent.Key);
							writer.WriteData(context.ObjectEncoding, sharedObjectEvent.Value);
							//writer.WriteData(sharedObjectEvent.Value);

							len = (int)output.Position - mark - 4;
							output.PutInt(mark, len);
						}
						break;
					case SharedObjectEventType.CLIENT_SEND_MESSAGE:
					case SharedObjectEventType.SERVER_SEND_MESSAGE:
						// Send method name and value
						writer.WriteByte(type);
						mark = (int)output.Position;
						output.Skip(4); // we will be back

						// Serialize name of the handler to call
						writer.WriteData(context.ObjectEncoding, sharedObjectEvent.Key);
						//writer.WriteUTF(sharedObjectEvent.Key);
						// Serialize the arguments
						foreach (object arg in sharedObjectEvent.Value as IList) {
							writer.WriteData(context.ObjectEncoding, arg);
						}
						//writer.WriteData(sharedObjectEvent.Value as IList);
						len = (int)output.Position - mark - 4;
						//output.PutInt(mark, len);
						output.PutInt(mark, len);
						break;
					case SharedObjectEventType.CLIENT_STATUS:
						writer.WriteByte(type);
						mark = (int)output.Position;
						output.Skip(4); // we will be back
						writer.WriteUTF(sharedObjectEvent.Key);
						writer.WriteUTF(sharedObjectEvent.Value as string);
						len = (int)output.Position - mark - 4;
						output.PutInt(mark, len);
						break;
					case SharedObjectEventType.SERVER_DISCONNECT:
						writer.WriteByte(type);
						output.PutInt((int)output.Position, 0);
						break;
					default:
#if !SILVERLIGHT
						_log.Error("Unknown event " + sharedObjectEvent.Type.ToString());
#endif
						writer.WriteByte(type);
						mark = (int)output.Position;
						output.Skip(4); // we will be back
						if (sharedObjectEvent.Key != null) {
							writer.WriteUTF(sharedObjectEvent.Key);
							writer.WriteData(context.ObjectEncoding, sharedObjectEvent.Value);
						}
						len = (int)output.Position - mark - 4;
						output.PutInt(mark, len);
						break;
				}
			}
		}
		/// <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;
		}
		static ISharedObjectMessage DecodeFlexSharedObject(ByteBuffer stream) {
			// Unknown byte, always 0?
			stream.Skip(1);
			RtmpReader reader = new RtmpReader(stream);
			string name = reader.ReadString();
			// Read version of SO to modify
			int version = reader.ReadInt32();
			// Read persistence informations
			bool persistent = reader.ReadInt32() == 2;
			// Skip unknown bytes
			reader.ReadInt32();

			SharedObjectMessage so = new FlexSharedObjectMessage(null, name, version, persistent);
			DecodeSharedObject(so, stream, reader);
			return so;
		}
Beispiel #4
0
		public static byte[] GetHandshakeResponse(ByteBuffer input) {
			int position = (int)input.Position;
			if (input[position + 4] == 0) {
				//Using old style handshake
				byte[] output = new byte[2 * RtmpProtocolDecoder.HandshakeSize + 1];
				output[0] = 0x03;
				int tick = System.Environment.TickCount;
				output[1] = (byte)((tick >> 24) & 0xff);
				output[2] = (byte)((tick >> 16) & 0xff);
				output[3] = (byte)((tick >> 8) & 0xff);
				output[4] = (byte)(tick & 0xff);
				HandshakePadBytes.CopyTo(output, 5);
				input.Read(output, RtmpProtocolDecoder.HandshakeSize + 1, RtmpProtocolDecoder.HandshakeSize);
				return output;
			} else {
				//This method is broken by FP 10.0.32.18
				//int index = (input[8] + input[9] + input[10] + input[11]) % 728 + 12;
				int index = 0;
				if (input[position + 5] == 0 && input[position + 6] == 3 && input[position + 7] == 2)
					index = ((input[position + 772] & 0x0ff) + (input[position + 773] & 0x0ff) + (input[position + 774] & 0x0ff) + (input[position + 775] & 0x0ff)) % 728 + 776;
				else
					index = ((input[position + 8] & 0x0ff) + (input[position + 9] & 0x0ff) + (input[position + 10] & 0x0ff) + (input[position + 11] & 0x0ff)) % 728 + 12;
				byte[] part = new byte[32];
				for (int i = 0; i < 32; ++i) {
					part[i] = input[position + index + i];
				}
				HMACSHA256 hmacsha256 = new HMACSHA256();
				hmacsha256.Key = SecretKey;
				byte[] newKey = hmacsha256.ComputeHash(part);
				byte[] randBytes = new byte[RtmpProtocolDecoder.HandshakeSize - 32];
				Random random = new Random();
				random.NextBytes(randBytes);
				hmacsha256.Key = newKey;
				byte[] hashedBytes = hmacsha256.ComputeHash(randBytes);
				byte[] output = new byte[2 * RtmpProtocolDecoder.HandshakeSize + 1];
				output[0] = 0x03;
				HandshakeServerBytes.CopyTo(output, 1);
				//randBytes.CopyTo(output, RtmpProtocolDecoder.HandshakeSize + 1);
				randBytes.CopyTo(output, 1 + HandshakeServerBytes.Length);
				//hashedBytes.CopyTo(output, RtmpProtocolDecoder.HandshakeSize + 1 + randBytes.Length);
				hashedBytes.CopyTo(output, 1 + HandshakeServerBytes.Length + randBytes.Length);
				input.Skip(RtmpProtocolDecoder.HandshakeSize);
				return output;
			}
		}