예제 #1
0
		public RtmptRequest(RtmpConnection connection, string url, string protocol, string httpMethod, Hashtable headers) {
			_connection = connection;
			_url = url;
			_protocol = protocol;
			_httpMethod = httpMethod;
			_headers = headers;
		}
예제 #2
0
		public static RtmptRequest DecodeBuffer(RtmpConnection connection, ByteBuffer stream) {
			RtmpContext context = connection.Context;
			int position = (int)stream.Position;
			try {
				BufferStreamReader sr = new BufferStreamReader(stream);
				string request = sr.ReadLine();
				string[] tokens = request.Split(new char[] { ' ' });
				string method = tokens[0];
				string url = tokens[1];
				// Decode all encoded parts of the URL using the built in URI processing class
				int i = 0;
				while ((i = url.IndexOf("%", i)) != -1) {
					url = url.Substring(0, i) + Uri.HexUnescape(url, ref i) + url.Substring(i);
				}
				// Lets just make sure we are using HTTP, thats about all I care about
				string protocol = tokens[2];// "HTTP/"
				//Read headers
				Hashtable headers = new Hashtable();
				string line;
				string name = null;
				while ((line = sr.ReadLine()) != null && line != string.Empty) {
					// If the value begins with a space or a hard tab then this
					// is an extension of the value of the previous header and
					// should be appended
					if (name != null && Char.IsWhiteSpace(line[0])) {
						headers[name] += line;
						continue;
					}
					// Headers consist of [NAME]: [VALUE] + possible extension lines
					int firstColon = line.IndexOf(":");
					if (firstColon != -1) {
						name = line.Substring(0, firstColon);
						string value = line.Substring(firstColon + 1).Trim();
						headers[name] = value;
					} else {
						//400, "Bad header: " + line
						break;
					}
				}
				RtmptRequest rtmptRequest = new RtmptRequest(connection, url, protocol, method, headers);
				if (stream.Remaining == rtmptRequest.ContentLength) {
					stream.Compact();
					rtmptRequest.Data = ByteBuffer.Wrap(stream.ToArray());
					stream.Flip();
					return rtmptRequest;
				} else {
					// Move the position back to the start
					stream.Position = position;
				}
			} catch {
				// Move the position back to the start
				stream.Position = position;
				throw;
			}
			return null;
		}
예제 #3
0
		public override void MessageSent(RtmpConnection connection, object message) {
			base.MessageSent(connection, message);
			RtmpPacket sent = message as RtmpPacket;
			int channelId = sent.Header.ChannelId;
			IClientStream stream = null;
			if (connection is IStreamCapableConnection)
				stream = (connection as IStreamCapableConnection).GetStreamByChannelId(channelId);
			// XXX we'd better use new event model for notification
			if (stream != null && (stream is PlaylistSubscriberStream)) {
				(stream as PlaylistSubscriberStream).Written(sent.Message);

			}
		}
예제 #4
0
		/*
		FlexInvoke flexInvoke = new FlexInvoke();
		flexInvoke.Cmd = "onstatus";
		flexInvoke.DataType = DataType.TypeUnknown;
		StatusASO statusASO = StatusASO.GetStatusObject(StatusASO.NC_CONNECT_CLOSED, connection.ObjectEncoding);
		flexInvoke.Parameters = new object[]{ statusASO };
		RtmpChannel channel = connection.GetChannel(3);
		channel.Write(flexInvoke);
		*/


		protected override void OnChunkSize(RtmpConnection connection, RtmpChannel channel, RtmpHeader source, ChunkSize chunkSize) {
			if (connection is IStreamCapableConnection) {
				IStreamCapableConnection streamCapableConnection = connection as IStreamCapableConnection;
				{
					foreach (IClientStream stream in streamCapableConnection.GetStreams()) {
						if (stream is IClientBroadcastStream) {
							IClientBroadcastStream bs = stream as IClientBroadcastStream;
							IBroadcastScope scope = bs.Scope.GetBasicScope(Constants.BroadcastScopeType, bs.PublishedName) as IBroadcastScope;
							if (scope == null)
								continue;

							OOBControlMessage setChunkSize = new OOBControlMessage();
							setChunkSize.Target = "ClientBroadcastStream";
							setChunkSize.ServiceName = "chunkSize";
							setChunkSize.ServiceParameterMap.Add("chunkSize", chunkSize.Size);
							scope.SendOOBControlMessage((IConsumer)null, setChunkSize);
							if (log.IsDebugEnabled) {
								log.Debug("Sending chunksize " + chunkSize + " to " + bs.Provider);
							}
						}
					}
				}
			}
		}
예제 #5
0
		/// <summary>
		/// This method supports the infrastructure and is not intended to be used directly from your code.
		/// </summary>
		/// <param name="connection"></param>
		/// <param name="channel"></param>
		/// <param name="header"></param>
		/// <param name="invoke"></param>
		protected abstract void OnInvoke(RtmpConnection connection, RtmpChannel channel, RtmpHeader header, Notify invoke);
예제 #6
0
		/// <summary>
		/// This method supports the infrastructure and is not intended to be used directly from your code.
		/// </summary>
		/// <param name="connection"></param>
		/// <param name="channel"></param>
		/// <param name="source"></param>
		/// <param name="ping"></param>
		protected abstract void OnPing(RtmpConnection connection, RtmpChannel channel, RtmpHeader source, Ping ping);
예제 #7
0
		private static void SendSOCreationFailed(RtmpConnection connection, string name, bool persistent) {
			SharedObjectMessage msg;
			if (connection.ObjectEncoding == ObjectEncoding.AMF0)
				msg = new SharedObjectMessage(name, 0, persistent);
			else
				msg = new FlexSharedObjectMessage(name, 0, persistent);
			msg.AddEvent(new SharedObjectEvent(SharedObjectEventType.CLIENT_STATUS, StatusASO.SO_CREATION_FAILED, "error"));
			connection.GetChannel((byte)3).Write(msg);
		}
예제 #8
0
		internal RtmpChannel(RtmpConnection connection, int channelId) {
			_connection = connection;
			_channelId = channelId;
		}
예제 #9
0
		/// <summary>
		/// Connection open event.
		/// </summary>
		/// <param name="connection">Connection object.</param>
		public virtual void ConnectionOpened(RtmpConnection connection) {
		}
예제 #10
0
		/// <summary>
		/// Handler for pending call result. Dispatches results to all pending call handlers.
		/// </summary>
		/// <param name="connection">Connection.</param>
		/// <param name="invoke">Pending call result event context.</param>
		protected void HandlePendingCallResult(RtmpConnection connection, Notify invoke) {
			IServiceCall call = invoke.ServiceCall;
			IPendingServiceCall pendingCall = connection.RetrievePendingCall(invoke.InvokeId);
			if (pendingCall != null) {
				pendingCall.Status = call.Status;
				// The client sent a response to a previously made call.
				object[] args = call.Arguments;
				if ((args != null) && (args.Length > 0)) {
					pendingCall.Result = args[0];
				}

				IPendingServiceCallback[] callbacks = pendingCall.GetCallbacks();
				if (callbacks != null && callbacks.Length > 0) {
					foreach (IPendingServiceCallback callback in callbacks) {
						try {
							callback.ResultReceived(pendingCall);
						} catch (Exception ex) {
#if !SILVERLIGHT
							log.Error("Error while executing callback " + callback, ex);
#endif
						}
					}
				}
			}
		}
예제 #11
0
		/// <summary>
		/// This method supports the infrastructure and is not intended to be used directly from your code.
		/// </summary>
		/// <param name="connection"></param>
		/// <param name="channel"></param>
		/// <param name="source"></param>
		/// <param name="serverBW"></param>
		protected abstract void OnServerBW(RtmpConnection connection, RtmpChannel channel, RtmpHeader source, ServerBW serverBW);
예제 #12
0
		protected override void OnPing(RtmpConnection connection, RtmpChannel channel, RtmpHeader source, Ping ping) {
			switch (ping.PingType) {
				case Ping.ClientBuffer:
					IClientStream stream = null;
					// Get the stream id
					int streamId = ping.Value2;
					// Get requested buffer size in milliseconds
					int buffer = ping.Value3;
					if (streamId != 0) {
						// The client wants to set the buffer time
						stream = connection.GetStreamById(streamId);
						if (stream != null) {
							stream.SetClientBufferDuration(buffer);
							if (log.IsDebugEnabled)
								log.Debug(string.Format("Client sent a buffer size: {0} ms for stream id: {1}", buffer, streamId));
						}
					}
					// Catch-all to make sure buffer size is set
					if (stream == null) {
						// Remember buffer time until stream is created
						connection.RememberStreamBufferDuration(streamId, buffer);
						if (log.IsDebugEnabled)
							log.Debug(string.Format("Remembering client buffer size: {0} on stream id: {1} ", buffer, streamId));
					}
					break;
				case Ping.PongServer:
					// This is the response to an IConnection.Ping request
					connection.PingReceived(ping);
					break;
				default:
					log.Warn("Unhandled ping: " + ping);
					break;
			}
		}
예제 #13
0
		/// <summary>
		/// Remoting call invocation handler.
		/// </summary>
		/// <param name="connection">RTMP connection.</param>
		/// <param name="serviceCall">Service call.</param>
		/// <param name="service">Server-side service object.</param>
		/// <returns><code>true</code> if the call was performed, otherwise <code>false</code>.</returns>
		private static bool InvokeCall(RtmpConnection connection, IServiceCall serviceCall, object service) {
			IScope scope = connection.Scope;
			IScopeContext context = scope.Context;
			if (log.IsDebugEnabled) {
				log.Debug("Scope: " + scope);
				log.Debug("Service: " + service);
				log.Debug("Context: " + context);
			}
			return context.ServiceInvoker.Invoke(serviceCall, service);
		}
예제 #14
0
		public static void InvokeCall(RtmpConnection connection, IServiceCall serviceCall) {
			IScope scope = connection.Scope;
			if (scope.HasHandler) {
				IScopeHandler handler = scope.Handler;
				if (!handler.ServiceCall(connection, serviceCall)) {
					// What do do here? Return an error?
					return;
				}
			}
			IScopeContext context = scope.Context;
			context.ServiceInvoker.Invoke(serviceCall, scope);
		}
예제 #15
0
		protected override void OnFlexInvoke(RtmpConnection connection, RtmpChannel channel, RtmpHeader header, FlexInvoke invoke) {
			IMessage message = null;
			if (invoke.ServiceCall.Arguments != null && invoke.ServiceCall.Arguments.Length > 0)
				message = invoke.ServiceCall.Arguments[0] as IMessage;
			if (message != null) {
				MessageBroker messageBroker = this.Endpoint.GetMessageBroker();
				if (message.clientId == null) {
					message.clientId = Guid.NewGuid().ToString("D");
					/*
					if( !(message is CommandMessage) )
					{
						//producer may send messages without subscribing
						CommandMessage commandMessageSubscribe = new CommandMessage(CommandMessage.SubscribeOperation);
						commandMessageSubscribe.messageId = Guid.NewGuid().ToString("D");
						commandMessageSubscribe.headers = message.headers.Clone() as Hashtable;
						commandMessageSubscribe.messageRefType = message.GetType().FullName;//"flex.messaging.messages.AsyncMessage"
						commandMessageSubscribe.destination = message.destination;

						IMessage subscribeResponse = messageBroker.RouteMessage(commandMessageSubscribe, _endpoint, connection);
						message.clientId = subscribeResponse.clientId;
					}
					}
					*/
				}
				IMessage response = messageBroker.RouteMessage(message, this.Endpoint);
				invoke.ServiceCall.Status = response is ErrorMessage ? Call.STATUS_INVOCATION_EXCEPTION : Call.STATUS_SUCCESS_RESULT;
				if (invoke.ServiceCall is IPendingServiceCall)
					(invoke.ServiceCall as IPendingServiceCall).Result = response;

				FlexInvoke reply = new FlexInvoke();
				reply.InvokeId = invoke.InvokeId;
				reply.ServiceCall = invoke.ServiceCall;
				/*
				if( response is ErrorMessage )
					reply.SetResponseFailure();
				else
					reply.SetResponseSuccess();
				reply.Response = response;
				*/
				channel.Write(reply);
			} else {
				// If it's a callback for server remote call then pass it over to callbacks handler and return
				OnInvoke(connection, channel, header, invoke);
			}
		}
예제 #16
0
		private static void SendSOPersistenceMismatch(RtmpConnection connection, string name, bool persistent) {
			SharedObjectMessage msg;
			if (connection.ObjectEncoding == ObjectEncoding.AMF0)
				msg = new SharedObjectMessage(name, 0, persistent);
			else
				msg = new FlexSharedObjectMessage(name, 0, persistent);
			msg.AddEvent(new SharedObjectEvent(SharedObjectEventType.CLIENT_STATUS, StatusASO.SO_PERSISTENCE_MISMATCH, "error"));
			connection.GetChannel((byte)3).Write(msg);
		}
예제 #17
0
		/// <summary>
		/// This method supports the infrastructure and is not intended to be used directly from your code.
		/// </summary>
		/// <param name="connection"></param>
		/// <param name="channel"></param>
		/// <param name="header"></param>
		/// <param name="message"></param>
		protected abstract void OnSharedObject(RtmpConnection connection, RtmpChannel channel, RtmpHeader header, SharedObjectMessage message);
예제 #18
0
		/// <summary>
		/// Message recieved.
		/// </summary>
		/// <param name="connection">Connection object.</param>
		/// <param name="obj">Message object.</param>
		public void MessageReceived(RtmpConnection connection, object obj) {
			IRtmpEvent message = null;
			RtmpPacket packet = null;
			RtmpHeader header = null;
			RtmpChannel channel = null;
			IClientStream stream = null;
			try {
				packet = obj as RtmpPacket;
				message = packet.Message;
				header = packet.Header;
				channel = connection.GetChannel(header.ChannelId);
				if (connection is IStreamCapableConnection)
					stream = (connection as IStreamCapableConnection).GetStreamById(header.StreamId);

				// Support stream ids
#if !SILVERLIGHT
				FluorineContext.ValidateContext();
				FluorineContext.Current.Connection.SetAttribute(FluorineContext.FluorineStreamIdKey, header.StreamId);
#endif
				// Increase number of received messages
				connection.MessageReceived();

#if !SILVERLIGHT
				if (log != null && log.IsDebugEnabled)
					log.Debug("RtmpConnection message received, type = " + header.DataType);
#endif

				if (message != null)
					message.Source = connection;

				switch (header.DataType) {
					case Constants.TypeInvoke:
						OnInvoke(connection, channel, header, message as Invoke);
						if (message.Header.StreamId != 0
							&& (message as Invoke).ServiceCall.ServiceName == null
							&& (message as Invoke).ServiceCall.ServiceMethodName == BaseRtmpHandler.ACTION_PUBLISH) {
							if (stream != null) //Dispatch if stream was created
								(stream as IEventDispatcher).DispatchEvent(message);
						}
						break;
					case Constants.TypeFlexInvoke:
						OnFlexInvoke(connection, channel, header, message as FlexInvoke);
						if (message.Header.StreamId != 0
							&& (message as Invoke).ServiceCall.ServiceName == null
							&& (message as Invoke).ServiceCall.ServiceMethodName == BaseRtmpHandler.ACTION_PUBLISH) {
							if (stream != null) //Dispatch if stream was created
								(stream as IEventDispatcher).DispatchEvent(message);
						}
						break;
					case Constants.TypeNotify:// just like invoke, but does not return
						if ((message as Notify).Data != null && stream != null) {
							// Stream metadata
							(stream as IEventDispatcher).DispatchEvent(message);
						} else
							OnInvoke(connection, channel, header, message as Notify);
						break;
					case Constants.TypePing:
						OnPing(connection, channel, header, message as Ping);
						break;
					case Constants.TypeBytesRead:
						OnStreamBytesRead(connection, channel, header, message as BytesRead);
						break;
					case Constants.TypeSharedObject:
					case Constants.TypeFlexSharedObject:
						OnSharedObject(connection, channel, header, message as SharedObjectMessage);
						break;
					case Constants.TypeFlexStreamEnd:
						if (stream != null)
							(stream as IEventDispatcher).DispatchEvent(message);
						break;
					case Constants.TypeChunkSize:
						OnChunkSize(connection, channel, header, message as ChunkSize);
						break;
					case Constants.TypeAudioData:
					case Constants.TypeVideoData:
						// NOTE: If we respond to "publish" with "NetStream.Publish.BadName",
						// the client sends a few stream packets before stopping. We need to
						// ignore them.
						if (stream != null)
							((IEventDispatcher)stream).DispatchEvent(message);
						break;
					case Constants.TypeServerBandwidth:
						OnServerBW(connection, channel, header, message as ServerBW);
						break;
					case Constants.TypeClientBandwidth:
						OnClientBW(connection, channel, header, message as ClientBW);
						break;
					default:
#if !SILVERLIGHT
						if (log != null && log.IsDebugEnabled)
							log.Debug("RtmpService event not handled: " + header.DataType);
#endif
						break;
				}
			} catch (Exception ex) {
#if !SILVERLIGHT
				if (log.IsErrorEnabled) {
					log.Error(__Res.GetString(__Res.Rtmp_HandlerError), ex);
					log.Error(__Res.GetString(__Res.Error_ContextDump));
					//log.Error(Environment.NewLine);
					log.Error(packet);
				}
#endif
			}
		}
예제 #19
0
		/// <summary>
		/// This method supports the infrastructure and is not intended to be used directly from your code.
		/// </summary>
		/// <param name="connection"></param>
		/// <param name="channel"></param>
		/// <param name="header"></param>
		/// <param name="invoke"></param>
		protected abstract void OnFlexInvoke(RtmpConnection connection, RtmpChannel channel, RtmpHeader header, FlexInvoke invoke);
예제 #20
0
		/// <summary>
		/// Message sent.
		/// </summary>
		/// <param name="connection">Connection object.</param>
		/// <param name="message">Message object.</param>
		public virtual void MessageSent(RtmpConnection connection, object message) {
			if (message is ByteBuffer)
				return;

			// Increase number of sent messages
			connection.MessageSent(message as RtmpPacket);
		}
예제 #21
0
		/// <summary>
		/// This method supports the infrastructure and is not intended to be used directly from your code.
		/// </summary>
		/// <param name="connection"></param>
		/// <param name="channel"></param>
		/// <param name="source"></param>
		/// <param name="clientBW"></param>
		protected abstract void OnClientBW(RtmpConnection connection, RtmpChannel channel, RtmpHeader source, ClientBW clientBW);
예제 #22
0
		/// <summary>
		/// Connection closed.
		/// </summary>
		/// <param name="connection">Connection object.</param>
		public virtual void ConnectionClosed(RtmpConnection connection) {
			connection.Close();
		}
예제 #23
0
		internal static void Push(RtmpConnection connection, IMessage message, IMessageClient messageClient) {
			if (connection != null) {
				object response = message;
				if (message is BinaryMessage) {
					BinaryMessage binaryMessage = message as BinaryMessage;
					binaryMessage.Update(messageClient);
					byte[] binaryContent = binaryMessage.body as byte[];
					//byte[] destClientBinaryId = messageClient.GetBinaryId();
					//Array.Copy(destClientBinaryId, 0, binaryContent, binaryMessage.PatternPosition, destClientBinaryId.Length);

					RawBinary result = new RawBinary(binaryContent);
					response = result;
				} else {
					//This should be a clone of the original message
					message.SetHeader(MessageBase.DestinationClientIdHeader, messageClient.ClientId);
					message.clientId = messageClient.ClientId;
				}

				RtmpChannel channel = connection.GetChannel(3);
				FlexInvoke reply = new FlexInvoke();
				Call call = new Call("receive", new object[] { response });
				reply.ServiceCall = call;
				//reply.Cmd = "receive";
				//reply.Response = response;
				reply.InvokeId = connection.InvokeId;
				channel.Write(reply);
			}
		}
예제 #24
0
			public WaitForHandshakeJob(RtmpConnection connection) {
				_connection = connection;
			}
예제 #25
0
			public CreateStreamCallBack(NetStream stream, RtmpConnection connection, IPendingServiceCallback callback) {
				ValidationUtils.ArgumentNotNull(connection, "connection");
				_stream = stream;
				_connection = connection;
				_callback = callback;
			}
예제 #26
0
		public override void ConnectionOpened(RtmpConnection connection) {
			base.ConnectionOpened(connection);
			if (connection.Context.Mode == RtmpMode.Server) {
				connection.StartWaitForHandshake();
			}
		}
예제 #27
0
		/// <summary>
		/// This method supports the infrastructure and is not intended to be used directly from your code.
		/// </summary>
		/// <param name="connection"></param>
		/// <param name="channel"></param>
		/// <param name="source"></param>
		/// <param name="streamBytesRead"></param>
		protected void OnStreamBytesRead(RtmpConnection connection, RtmpChannel channel, RtmpHeader source, BytesRead streamBytesRead) {
			connection.ReceivedBytesRead(streamBytesRead.Bytes);
		}
예제 #28
0
		protected override void OnSharedObject(RtmpConnection connection, RtmpChannel channel, RtmpHeader header, SharedObjectMessage message) {
			ISharedObject so = null;
			string name = message.Name;
			IScope scope = connection.Scope;
			bool persistent = message.IsPersistent;
			if (scope == null) {
				// The scope already has been deleted.
				SendSOCreationFailed(connection, name, persistent);
				return;
			}
			ISharedObjectService sharedObjectService = ScopeUtils.GetScopeService(scope, typeof(ISharedObjectService)) as ISharedObjectService;
			if (!sharedObjectService.HasSharedObject(scope, name)) {
				ISharedObjectSecurityService securityService = ScopeUtils.GetScopeService(scope, typeof(ISharedObjectSecurityService)) as ISharedObjectSecurityService;
				if (securityService != null) {
					// Check handlers to see if creation is allowed
					IEnumerator enumerator = securityService.GetSharedObjectSecurity();
					while (enumerator.MoveNext()) {
						ISharedObjectSecurity handler = enumerator.Current as ISharedObjectSecurity;
						if (!handler.IsCreationAllowed(scope, name, persistent)) {
							SendSOCreationFailed(connection, name, persistent);
							return;
						}
					}
				}

				if (!sharedObjectService.CreateSharedObject(scope, name, persistent)) {
					SendSOCreationFailed(connection, name, persistent);
					return;
				}
			}
			so = sharedObjectService.GetSharedObject(scope, name);
			if (so.IsPersistentObject != persistent) {
				log.Debug(string.Format("Shared object '{0}' persistence mismatch", name));
				SendSOPersistenceMismatch(connection, name, persistent);
				return;
			}
			so.DispatchEvent(message);
		}
예제 #29
0
			public KeepAliveJob(RtmpConnection connection) {
				_connection = connection;
			}
예제 #30
0
		/// <summary>
		/// This method supports the infrastructure and is not intended to be used directly from your code.
		/// </summary>
		/// <param name="connection"></param>
		/// <param name="channel"></param>
		/// <param name="source"></param>
		/// <param name="chunkSize"></param>
		protected abstract void OnChunkSize(RtmpConnection connection, RtmpChannel channel, RtmpHeader source, ChunkSize chunkSize);