Exemplo n.º 1
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);
			}
		}
Exemplo n.º 2
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
			}
		}
Exemplo n.º 3
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);
		}
Exemplo n.º 4
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);
		}
Exemplo n.º 5
0
		protected override void OnInvoke(RtmpConnection connection, RtmpChannel channel, RtmpHeader header, Notify invoke) {
			IServiceCall serviceCall = invoke.ServiceCall;

			// If it's a callback for server remote call then pass it over to callbacks handler
			// and return
			if (serviceCall.ServiceMethodName.Equals("_result") || serviceCall.ServiceMethodName.Equals("_error")) {
				HandlePendingCallResult(connection, invoke);
				return;
			}

			bool disconnectOnReturn = false;
			string action = null;
			if (serviceCall.ServiceName == null) {
				action = serviceCall.ServiceMethodName;
				switch (action) {
					case ACTION_CONNECT: {
							if (!connection.IsConnected) {
								IDictionary parameters = invoke.ConnectionParameters;
								string host = null;
								if (parameters.Contains("tcUrl"))
									host = GetHostname(parameters["tcUrl"] as string);
								if (host != null && host.IndexOf(":") != -1) {
									// Remove default port from connection string
									host = host.Substring(0, host.IndexOf(":"));
								}
								string app = parameters["app"] as string;
								string path = parameters["app"] as string;
								// App name as path, but without query string if there is one
								if (path != null && path.IndexOf("?") != -1) {
									int idx = path.IndexOf("?");
									parameters["queryString"] = path.Substring(idx);
									path = path.Substring(0, idx);
								}
								parameters["path"] = path;

								connection.Setup(host, path, parameters);
								try {
									//IGlobalScope global = this.Endpoint.LookupGlobal(host, path);
									IGlobalScope global = this.Endpoint.GetMessageBroker().GlobalScope;
									if (global == null) {
										serviceCall.Status = Call.STATUS_SERVICE_NOT_FOUND;
										if (serviceCall is IPendingServiceCall) {
											StatusASO status = StatusASO.GetStatusObject(StatusASO.NC_CONNECT_INVALID_APPLICATION, connection.ObjectEncoding);
											status.description = "No global scope on this server.";
											(serviceCall as IPendingServiceCall).Result = status;
										}
										log.Info(string.Format("No application scope found for {0} on host {1}. Misspelled or missing application folder?", path, host));
										disconnectOnReturn = true;
									} else {
										IScopeContext context = global.Context;
										IScope scope = null;
										try {
											scope = context.ResolveScope(global, path);
										} catch (ScopeNotFoundException /*exception*/) {
											if (log.IsErrorEnabled)
												log.Error(__Res.GetString(__Res.Scope_NotFound, path));

											serviceCall.Status = Call.STATUS_SERVICE_NOT_FOUND;
											if (serviceCall is IPendingServiceCall) {
												StatusASO status = StatusASO.GetStatusObject(StatusASO.NC_CONNECT_REJECTED, connection.ObjectEncoding);
												status.description = "No scope \"" + path + "\" on this server.";
												(serviceCall as IPendingServiceCall).Result = status;
											}
											disconnectOnReturn = true;
										} catch (ScopeShuttingDownException) {
											serviceCall.Status = Call.STATUS_APP_SHUTTING_DOWN;
											if (serviceCall is IPendingServiceCall) {
												StatusASO status = StatusASO.GetStatusObject(StatusASO.NC_CONNECT_APPSHUTDOWN, connection.ObjectEncoding);
												status.description = "Application at \"" + path + "\" is currently shutting down.";
												(serviceCall as IPendingServiceCall).Result = status;
											}
											log.Info(string.Format("Application at {0} currently shutting down on {1}", path, host));
											disconnectOnReturn = true;
										}
										if (scope != null) {
											if (log.IsInfoEnabled)
												log.Info(__Res.GetString(__Res.Scope_Connect, scope.Name));
											bool okayToConnect;
											try {
												//The only way to differentiate NetConnection.connect() and Consumer.subscribe() seems to be the app name
												if (app == string.Empty) {
													connection.SetIsFlexClient(true);
													okayToConnect = connection.Connect(scope, serviceCall.Arguments);
													if (okayToConnect) {
														if (serviceCall.Arguments != null && serviceCall.Arguments.Length >= 3) {
															string credentials = serviceCall.Arguments[2] as string;
															if (credentials != null && credentials != string.Empty) {
																MessageBroker messageBroker = this.Endpoint.GetMessageBroker();
																AuthenticationService authenticationService = messageBroker.GetService(AuthenticationService.ServiceId) as AuthenticationService;
																authenticationService.Authenticate(credentials);
															}
														}
														//FDS 2.0.1 fds.swc
														if (serviceCall.Arguments != null && serviceCall.Arguments.Length == 1) {
															string credentials = serviceCall.Arguments[0] as string;
															if (credentials != null && credentials != string.Empty) {
																MessageBroker messageBroker = this.Endpoint.GetMessageBroker();
																AuthenticationService authenticationService = messageBroker.GetService(AuthenticationService.ServiceId) as AuthenticationService;
																authenticationService.Authenticate(credentials);
															}
														}
													}
												} else {
													connection.SetIsFlexClient(false);
													okayToConnect = connection.Connect(scope, serviceCall.Arguments);
												}
												if (okayToConnect) {
													if (log.IsDebugEnabled)
														log.Debug("Connected RtmpClient: " + connection.Client.Id);
													serviceCall.Status = Call.STATUS_SUCCESS_RESULT;
													if (serviceCall is IPendingServiceCall) {
														StatusASO statusASO = StatusASO.GetStatusObject(StatusASO.NC_CONNECT_SUCCESS, connection.ObjectEncoding);
														statusASO.Add("id", connection.Client.Id);
														(serviceCall as IPendingServiceCall).Result = statusASO;
													}
													// Measure initial roundtrip time after connecting
													connection.GetChannel((byte)2).Write(new Ping(Ping.StreamBegin, 0, -1));
													connection.StartRoundTripMeasurement();
												} else {
													if (log.IsDebugEnabled)
														log.Debug("Connect failed");
													serviceCall.Status = Call.STATUS_ACCESS_DENIED;
													if (serviceCall is IPendingServiceCall)
														(serviceCall as IPendingServiceCall).Result = StatusASO.GetStatusObject(StatusASO.NC_CONNECT_REJECTED, connection.ObjectEncoding);
													disconnectOnReturn = true;
												}
											} catch (ClientRejectedException rejected) {
												if (log.IsDebugEnabled)
													log.Debug("Connect rejected");
												serviceCall.Status = Call.STATUS_ACCESS_DENIED;
												if (serviceCall is IPendingServiceCall) {
													StatusASO statusASO = StatusASO.GetStatusObject(StatusASO.NC_CONNECT_REJECTED, connection.ObjectEncoding);
													statusASO.Application = rejected.Reason;
													(serviceCall as IPendingServiceCall).Result = statusASO;
												}
												disconnectOnReturn = true;
											}
										}
									}
								} catch (Exception ex) {
									if (log.IsErrorEnabled)
										log.Error("Error connecting", ex);

									serviceCall.Status = Call.STATUS_GENERAL_EXCEPTION;
									if (serviceCall is IPendingServiceCall)
										(serviceCall as IPendingServiceCall).Result = StatusASO.GetStatusObject(StatusASO.NC_CONNECT_FAILED, connection.ObjectEncoding);
									disconnectOnReturn = true;
								}
							} else {
								// Service calls, must be connected.
								InvokeCall(connection, serviceCall);
							}
						}
						break;
					case ACTION_DISCONNECT:
						connection.Close();
						break;
					case ACTION_CREATE_STREAM:
					case ACTION_DELETE_STREAM:
					case ACTION_RELEASE_STREAM:
					case ACTION_PUBLISH:
					case ACTION_PLAY:
					case ACTION_SEEK:
					case ACTION_PAUSE:
					case ACTION_CLOSE_STREAM:
					case ACTION_RECEIVE_VIDEO:
					case ACTION_RECEIVE_AUDIO: {
							IStreamService streamService = ScopeUtils.GetScopeService(connection.Scope, typeof(IStreamService)) as IStreamService;
							StatusASO status = null;
							try {
								if (!InvokeCall(connection, serviceCall, streamService)) {
									status = StatusASO.GetStatusObject(StatusASO.NS_INVALID_ARGUMENT, connection.ObjectEncoding);
									status.description = "Failed to " + action + " (stream ID: " + header.StreamId + ")";
								}
							} catch (Exception ex) {
								log.Error("Error while invoking " + action + " on stream service.", ex);
								status = StatusASO.GetStatusObject(StatusASO.NS_FAILED, connection.ObjectEncoding);
								status.description = "Error while invoking " + action + " (stream ID: " + header.StreamId + ")";
								status.details = ex.Message;
							}
							if (status != null)
								channel.SendStatus(status);
						}
						break;
					default:
						if (connection.IsConnected)
							InvokeCall(connection, serviceCall);
						else {
							// Warn user attemps to call service without being connected
							if (log.IsWarnEnabled)
								log.Warn("Not connected, closing connection");
							connection.Close();
						}
						break;
				}
			}
			/*
			if(invoke is FlexInvoke) 
			{
				FlexInvoke reply = new FlexInvoke();
				reply.InvokeId = invoke.InvokeId;
				reply.SetResponseSuccess();
				//TODO
				if( serviceCall is IPendingServiceCall )
				{
					IPendingServiceCall pendingCall = (IPendingServiceCall)serviceCall;
					reply.Response = pendingCall.Result;
				}
				channel.Write(reply);
			}
			else if(invoke is Invoke) 
			*/
			if (invoke is Invoke) {
				if ((header.StreamId != 0)
					&& (serviceCall.Status == Call.STATUS_SUCCESS_VOID || serviceCall.Status == Call.STATUS_SUCCESS_NULL)) {
					if (log.IsDebugEnabled)
						log.Debug("Method does not have return value, do not reply");
					return;
				}

				// The client expects a result for the method call.
				Invoke reply = new Invoke();
				reply.ServiceCall = serviceCall;
				reply.InvokeId = invoke.InvokeId;
				//sending reply
				channel.Write(reply);
			}
			if (disconnectOnReturn) {
				connection.Close();
			}
			if (action == ACTION_CONNECT) {
				connection.Context.ObjectEncoding = connection.ObjectEncoding;
			}
		}