public bool Serialize(Channel channel, AmfMessage message, Stream stream, uint chuckSize) { Serialize(ref message); var header = message.Header; long available; InternalBuffer.Position = 0; while ((available = InternalBuffer.Length - InternalBuffer.Position) != 0) { header.Write(channel, stream); if (available >= chuckSize) { InternalBuffer.CopyPartTo(stream, (int)chuckSize); channel.lastOutProcBytes += chuckSize; } else { InternalBuffer.CopyPartTo(stream, (int)available); channel.lastOutProcBytes += (uint)available; } } //Debug.WriteLine(channel.lastOutProcBytes); channel.lastOutProcBytes = 0; InternalBuffer.Recycle(); return(true); }
public static AmfMessage GetInvokeCallFailedError(AmfMessage request) { return GetInvokeError(request.ChannelId, request.StreamId, request.InvokeId, Variant.Get(), Variant.GetMap(new VariantMapHelper { {Defines.RM_INVOKE_PARAMS_RESULT_LEVEL,Defines.RM_INVOKE_PARAMS_RESULT_LEVEL_ERROR}, {Defines.RM_INVOKE_PARAMS_RESULT_CODE,"NetConnection.Call.Failed"}, {Defines.RM_INVOKE_PARAMS_RESULT_DESCRIPTION,"call to function "+request.InvokeFunction+" failed"} })); }
public static AmfMessage GetInvokeCallFailedError(AmfMessage request) { return(GetInvokeError(request.ChannelId, request.StreamId, request.InvokeId, Variant.Get(), Variant.GetMap(new VariantMapHelper { { Defines.RM_INVOKE_PARAMS_RESULT_LEVEL, Defines.RM_INVOKE_PARAMS_RESULT_LEVEL_ERROR }, { Defines.RM_INVOKE_PARAMS_RESULT_CODE, "NetConnection.Call.Failed" }, { Defines.RM_INVOKE_PARAMS_RESULT_DESCRIPTION, "call to function " + request.InvokeFunction + " failed" } }))); }
public bool SendMessage(AmfMessage message, bool enqueueForOutbound = false, bool recycleMessageBody = true) { //SendMessagesBlock.Post(new Tuple<AmfMessage,bool>(message, recycleMessageBody)); //if(enqueueForOutbound)SendMessagesBlock.TriggerBatch(); //return true; lock (_rtmpProtocolSerializer) { if (!_rtmpProtocolSerializer.Serialize(GetChannel(message.ChannelId), message, OutputBuffer, _outboundChunkSize)) { FATAL("Unable to serialize RTMP message"); return(false); } if (recycleMessageBody) { message.Body.Recycle(); } _txInvokes++; return(!enqueueForOutbound || EnqueueForOutbound(OutputBuffer)); } }
public BaseRTMPAppProtocolHandler(Variant configuration) : base(configuration) { ValidateHandshake = configuration[Defines.CONF_APPLICATION_VALIDATEHANDSHAKE]; //_keyframeSeek = configuration[Defines.CONF_APPLICATION_KEYFRAMESEEK]; //_clientSideBuffer = configuration[Defines.CONF_APPLICATION_CLIENTSIDEBUFFER]; //_seekGranularity = (uint)((double)configuration[Defines.CONF_APPLICATION_SEEKGRANULARITY] * 1000); //_renameBadFiles = configuration[Defines.CONF_APPLICATION_RENAMEBADFILES]; //_externSeekGenerator = configuration[Defines.CONF_APPLICATION_EXTERNSEEKGENERATOR]; // _enableCheckBandwidth = configuration["enableCheckBandwidth"] != null && configuration["enableCheckBandwidth"]; _enableCheckBandwidth = true; if (_enableCheckBandwidth) { _onBWCheckMessage = GenericMessageFactory.GetInvoke(3, 0, 0, false, 0, Defines.RM_INVOKE_FUNCTION_ONBWCHECK, Variant.GetList(Variant.Get(), Utils.GenerateRandomString(ONBWCHECK_SIZE))); _onBWCheckStrippedMessage = new AmfMessage { Header = GenericMessageFactory.VH(HeaderType.HT_FULL, 3, 0, 0, Defines.RM_HEADER_MESSAGETYPE_INVOKE, 0, false), Body = Variant.GetMap(new VariantMapHelper { { Defines.RM_INVOKE, Variant.GetMap(new VariantMapHelper { {Defines.RM_INVOKE_FUNCTION, Defines.RM_INVOKE_FUNCTION_ONBWCHECK} }) } }) }; } if (configuration[Defines.CONF_APPLICATION_GENERATE_META_FILES]) { GenerateMetaFiles(); } }
public static AmfMessage GetInvokeOnStatusStreamPublishBadName(AmfMessage request, string streamName) { return GetInvokeOnStatusStreamPublishBadName(request.ChannelId, request.StreamId,request.InvokeId, streamName); }
public static AmfMessage GetInvokeReleaseStreamErrorNotFound(AmfMessage request) { return GenericMessageFactory.GetInvokeError(request.ChannelId, request.StreamId, request.InvokeId, Variant.Get(), Variant.GetMap(new VariantMapHelper { {Defines.RM_INVOKE_PARAMS_RESULT_LEVEL,Defines.RM_INVOKE_PARAMS_RESULT_LEVEL_ERROR}, {Defines.RM_INVOKE_PARAMS_RESULT_CODE,"NetConnection.Call.Failed"}, {Defines.RM_INVOKE_PARAMS_RESULT_DESCRIPTION,"Specified stream not found in call to releaseStream"} })); }
internal static AmfMessage GetInvokeConnectError(AmfMessage message, string description, string level = Defines.RM_INVOKE_PARAMS_RESULT_LEVEL_ERROR, string code = Defines.RM_INVOKE_PARAMS_RESULT_CODE_NETCONNECTIONCONNECTREJECTED) { return GetInvokeConnectError(message.ChannelId,message.StreamId, message.InvokeId, level, code, description); }
public static AmfMessage GetInvokeConnectResult(AmfMessage request, string level = Defines.RM_INVOKE_PARAMS_RESULT_LEVEL_STATUS, string code = Defines.RM_INVOKE_PARAMS_RESULT_CODE_NETCONNECTIONCONNECTSUCCESS, string description = Defines.RM_INVOKE_PARAMS_RESULT_DESCRIPTION_CONNECTIONSUCCEEDED) { double objectEncoding = (int)request.InvokeParam[0][Defines.RM_INVOKE_PARAMS_RESULT_OBJECTENCODING]; return GetInvokeConnectResult(request.ChannelId,request.StreamId,request.InvokeId,level,code,description,objectEncoding); }
public bool Serialize(ref AmfMessage message) { //var result = false; var messageBody = message.Body; switch ((uint) message.MessageType) { case Defines.RM_HEADER_MESSAGETYPE_INVOKE: writer.WriteShortString(message.InvokeFunction, true); writer.WriteDouble(messageBody[Defines.RM_INVOKE, Defines.RM_INVOKE_ID], true); foreach (var item in messageBody[Defines.RM_INVOKE, Defines.RM_INVOKE_PARAMS].Children) writer.WriteVariant(item.Value); break; case Defines.RM_HEADER_MESSAGETYPE_NOTIFY: foreach (var item in messageBody[Defines.RM_NOTIFY, Defines.RM_NOTIFY_PARAMS].Children) writer.WriteVariant(item.Value); break; case Defines.RM_HEADER_MESSAGETYPE_FLEXSTREAMSEND: InternalBuffer.WriteByte( messageBody[Defines.RM_FLEXSTREAMSEND, Defines.RM_FLEXSTREAMSEND_UNKNOWNBYTE]); foreach ( var item in messageBody[Defines.RM_FLEXSTREAMSEND, Defines.RM_FLEXSTREAMSEND_PARAMS].Children) writer.WriteVariant(item.Value); break; case Defines.RM_HEADER_MESSAGETYPE_SHAREDOBJECT: writer.WriteShortString(messageBody[Defines.RM_SHAREDOBJECT, Defines.RM_SHAREDOBJECT_NAME]); writer.Write((uint)messageBody[Defines.RM_SHAREDOBJECT, Defines.RM_SHAREDOBJECT_VERSION]); writer.Write(messageBody[Defines.RM_SHAREDOBJECT, Defines.RM_SHAREDOBJECT_PERSISTENCE] ? 2U : 0U); writer.Write(0); foreach ( var primitive in messageBody[Defines.RM_SHAREDOBJECT, Defines.RM_SHAREDOBJECT_PRIMITIVES].Children.Values) { byte type = primitive[Defines.RM_SHAREDOBJECTPRIMITIVE_TYPE]; InternalBuffer.WriteByte(type); long rawLengthPosition; long length; switch (type) { case Defines.SOT_SC_UPDATE_DATA: case Defines.SOT_SC_INITIAL_DATA: rawLengthPosition = InternalBuffer.Position; writer.Write(0); if (primitive[Defines.RM_SHAREDOBJECTPRIMITIVE_PAYLOAD] == null) break; foreach (var item in primitive[Defines.RM_SHAREDOBJECTPRIMITIVE_PAYLOAD].Children) { writer.WriteShortString(item.Key); writer.WriteVariant(item.Value); } length = InternalBuffer.Position - rawLengthPosition - 4; InternalBuffer.Seek(rawLengthPosition, SeekOrigin.Begin); writer.Write((uint) length); InternalBuffer.Seek(0, SeekOrigin.End); break; case Defines.SOT_SC_CLEAR_DATA: writer.Write(0); break; case Defines.SOT_SC_DELETE_DATA: case Defines.SOT_SC_UPDATE_DATA_ACK: rawLengthPosition = InternalBuffer.Position; writer.Write(0); foreach (var item in primitive[Defines.RM_SHAREDOBJECTPRIMITIVE_PAYLOAD].Children) writer.WriteShortString(item.Value); length = InternalBuffer.Position - rawLengthPosition - 4; InternalBuffer.Seek(rawLengthPosition, SeekOrigin.Begin); writer.Write((uint) length); InternalBuffer.Seek(0, SeekOrigin.End); break; case Defines.SOT_BW_SEND_MESSAGE: rawLengthPosition = InternalBuffer.Position; writer.Write(0); if (primitive[Defines.RM_SHAREDOBJECTPRIMITIVE_PAYLOAD] == null) break; foreach (var item in primitive[Defines.RM_SHAREDOBJECTPRIMITIVE_PAYLOAD].Children) { writer.WriteVariant(item.Value); } length = InternalBuffer.Position - rawLengthPosition - 4; InternalBuffer.Seek(rawLengthPosition, SeekOrigin.Begin); writer.Write((uint)length); InternalBuffer.Seek(0, SeekOrigin.End); break; } } break; case Defines.RM_HEADER_MESSAGETYPE_ACK: writer.Write((uint)messageBody[Defines.RM_ACK]); break; case Defines.RM_HEADER_MESSAGETYPE_USRCTRL: writer.Write((short)messageBody[Defines.RM_USRCTRL, Defines.RM_USRCTRL_TYPE]); switch ((short)messageBody[Defines.RM_USRCTRL, Defines.RM_USRCTRL_TYPE]) { case Defines.RM_USRCTRL_TYPE_STREAM_BEGIN: case Defines.RM_USRCTRL_TYPE_STREAM_EOF: case Defines.RM_USRCTRL_TYPE_STREAM_DRY: case Defines.RM_USRCTRL_TYPE_STREAM_IS_RECORDED: writer.Write((int)messageBody[Defines.RM_USRCTRL, Defines.RM_USRCTRL_STREAMID]); break; case Defines.RM_USRCTRL_TYPE_PING_RESPONSE: writer.Write((int)messageBody[Defines.RM_USRCTRL, Defines.RM_USRCTRL_PONG]); break; default: Logger.FATAL("Invalid user control message"); break; } break; case Defines.RM_HEADER_MESSAGETYPE_CHUNKSIZE: writer.Write((uint)messageBody[Defines.RM_CHUNKSIZE]); break; case Defines.RM_HEADER_MESSAGETYPE_WINACKSIZE: writer.Write((uint)messageBody[Defines.RM_WINACKSIZE]); break; case Defines.RM_HEADER_MESSAGETYPE_ABORTMESSAGE: writer.Write((uint)messageBody[Defines.RM_ABORTMESSAGE]); break; case Defines.RM_HEADER_MESSAGETYPE_PEERBW: writer.Write((uint)messageBody[Defines.RM_PEERBW, Defines.RM_PEERBW_VALUE]); writer.Write((byte)messageBody[Defines.RM_PEERBW, Defines.RM_PEERBW_TYPE]); break; default: Logger.FATAL("Invalid message type:{0}", message); return false; } message.MessageLength = (uint)InternalBuffer.Length; InternalBuffer.Position = 0; return true; }
private bool ProcessInvokeConnectResult(BaseRTMPProtocol pFrom, AmfMessage request, AmfMessage response) { //1. Do we need to push/pull a stream? if ((!NeedsToPullExternalStream(pFrom)) && (!NeedsToPushLocalStream(pFrom))) { Logger.WARN("Default implementation of ProcessInvokeConnectResult: Request:\n{0}\nResponse:\n{1}", request.ToString(), response.ToString()); return true; } //2. See if the result is OK or not if (response.InvokeFunction != Defines.RM_INVOKE_FUNCTION_RESULT) { if (response.InvokeFunction != Defines.RM_INVOKE_FUNCTION_ERROR || response.InvokeParam != VariantType.Map || response.InvokeParam.ArrayLength < 2 || response.InvokeParam[1] != VariantType.Map || response.InvokeParam[1]["level"] != "error" || response.InvokeParam[1]["code"] != "NetConnection.Connect.Rejected" || response.InvokeParam[1]["description"] == "" ) { Logger.FATAL("Connect failed:\n{0}", response.ToString()); return false; } string description = response.InvokeParam[1]["description"]; var parts = description.Split('?'); if (parts.Length != 2) { Logger.FATAL("Connect failed:\n{0}", response.ToString()); return false; } description = parts[1]; var _params = description.GetURLParam(); if (!_params.ContainsKey("reason") || !_params.ContainsKey("user") || !_params.ContainsKey("salt") || !_params.ContainsKey("challenge") || !_params.ContainsKey("opaque") || _params["reason"] != "needauth") { Logger.FATAL("Connect failed:\n{0}", response.ToString()); return false; } var customParameters = pFrom.CustomParameters; var streamConfig = NeedsToPullExternalStream(pFrom) ? customParameters["customParameters", "externalStreamConfig"] : customParameters["customParameters", "localStreamConfig"]; foreach (var param in _params) { streamConfig["auth"].Add(param.Key, param.Value); } return false; } if (response.InvokeParam[1] != VariantType.Map || response.InvokeParam[1]["code"] != "NetConnection.Connect.Success") { Logger.FATAL("Connect failed:\n{0}", response.ToString()); return false; } if (NeedsToPullExternalStream(pFrom)) { var parameters = pFrom.CustomParameters["customParameters","externalStreamConfig"]; if (!SendRTMPMessage(pFrom, StreamMessageFactory.GetInvokeFCSubscribe(parameters["localStreamName"]), true)) { return false; } } //3. Create the createStream request //4. Send it if (!SendRTMPMessage(pFrom, StreamMessageFactory.GetInvokeCreateStream(), true)) { return false; } //5. Done return true; }
internal static AmfMessage GetInvokeResult(AmfMessage request, Variant parameters) { return GetInvoke(request.ChannelId, request.StreamId, 0, false, request.InvokeId, Defines.RM_INVOKE_FUNCTION_RESULT, parameters); }
public bool Serialize(ref AmfMessage message) { //var result = false; var messageBody = message.Body; switch ((uint)message.MessageType) { case Defines.RM_HEADER_MESSAGETYPE_INVOKE: writer.WriteShortString(message.InvokeFunction, true); writer.WriteDouble(messageBody[Defines.RM_INVOKE, Defines.RM_INVOKE_ID], true); foreach (var item in messageBody[Defines.RM_INVOKE, Defines.RM_INVOKE_PARAMS].Children) { writer.WriteVariant(item.Value); } break; case Defines.RM_HEADER_MESSAGETYPE_NOTIFY: foreach (var item in messageBody[Defines.RM_NOTIFY, Defines.RM_NOTIFY_PARAMS].Children) { writer.WriteVariant(item.Value); } break; case Defines.RM_HEADER_MESSAGETYPE_FLEXSTREAMSEND: InternalBuffer.WriteByte( messageBody[Defines.RM_FLEXSTREAMSEND, Defines.RM_FLEXSTREAMSEND_UNKNOWNBYTE]); foreach ( var item in messageBody[Defines.RM_FLEXSTREAMSEND, Defines.RM_FLEXSTREAMSEND_PARAMS].Children) { writer.WriteVariant(item.Value); } break; case Defines.RM_HEADER_MESSAGETYPE_SHAREDOBJECT: writer.WriteShortString(messageBody[Defines.RM_SHAREDOBJECT, Defines.RM_SHAREDOBJECT_NAME]); writer.Write((uint)messageBody[Defines.RM_SHAREDOBJECT, Defines.RM_SHAREDOBJECT_VERSION]); writer.Write(messageBody[Defines.RM_SHAREDOBJECT, Defines.RM_SHAREDOBJECT_PERSISTENCE] ? 2U : 0U); writer.Write(0); foreach ( var primitive in messageBody[Defines.RM_SHAREDOBJECT, Defines.RM_SHAREDOBJECT_PRIMITIVES].Children.Values) { byte type = primitive[Defines.RM_SHAREDOBJECTPRIMITIVE_TYPE]; InternalBuffer.WriteByte(type); long rawLengthPosition; long length; switch (type) { case Defines.SOT_SC_UPDATE_DATA: case Defines.SOT_SC_INITIAL_DATA: rawLengthPosition = InternalBuffer.Position; writer.Write(0); if (primitive[Defines.RM_SHAREDOBJECTPRIMITIVE_PAYLOAD] == null) { break; } foreach (var item in primitive[Defines.RM_SHAREDOBJECTPRIMITIVE_PAYLOAD].Children) { writer.WriteShortString(item.Key); writer.WriteVariant(item.Value); } length = InternalBuffer.Position - rawLengthPosition - 4; InternalBuffer.Seek(rawLengthPosition, SeekOrigin.Begin); writer.Write((uint)length); InternalBuffer.Seek(0, SeekOrigin.End); break; case Defines.SOT_SC_CLEAR_DATA: writer.Write(0); break; case Defines.SOT_SC_DELETE_DATA: case Defines.SOT_SC_UPDATE_DATA_ACK: rawLengthPosition = InternalBuffer.Position; writer.Write(0); foreach (var item in primitive[Defines.RM_SHAREDOBJECTPRIMITIVE_PAYLOAD].Children) { writer.WriteShortString(item.Value); } length = InternalBuffer.Position - rawLengthPosition - 4; InternalBuffer.Seek(rawLengthPosition, SeekOrigin.Begin); writer.Write((uint)length); InternalBuffer.Seek(0, SeekOrigin.End); break; case Defines.SOT_BW_SEND_MESSAGE: rawLengthPosition = InternalBuffer.Position; writer.Write(0); if (primitive[Defines.RM_SHAREDOBJECTPRIMITIVE_PAYLOAD] == null) { break; } foreach (var item in primitive[Defines.RM_SHAREDOBJECTPRIMITIVE_PAYLOAD].Children) { writer.WriteVariant(item.Value); } length = InternalBuffer.Position - rawLengthPosition - 4; InternalBuffer.Seek(rawLengthPosition, SeekOrigin.Begin); writer.Write((uint)length); InternalBuffer.Seek(0, SeekOrigin.End); break; } } break; case Defines.RM_HEADER_MESSAGETYPE_ACK: writer.Write((uint)messageBody[Defines.RM_ACK]); break; case Defines.RM_HEADER_MESSAGETYPE_USRCTRL: writer.Write((short)messageBody[Defines.RM_USRCTRL, Defines.RM_USRCTRL_TYPE]); switch ((short)messageBody[Defines.RM_USRCTRL, Defines.RM_USRCTRL_TYPE]) { case Defines.RM_USRCTRL_TYPE_STREAM_BEGIN: case Defines.RM_USRCTRL_TYPE_STREAM_EOF: case Defines.RM_USRCTRL_TYPE_STREAM_DRY: case Defines.RM_USRCTRL_TYPE_STREAM_IS_RECORDED: writer.Write((int)messageBody[Defines.RM_USRCTRL, Defines.RM_USRCTRL_STREAMID]); break; case Defines.RM_USRCTRL_TYPE_PING_RESPONSE: writer.Write((int)messageBody[Defines.RM_USRCTRL, Defines.RM_USRCTRL_PONG]); break; default: Logger.FATAL("Invalid user control message"); break; } break; case Defines.RM_HEADER_MESSAGETYPE_CHUNKSIZE: writer.Write((uint)messageBody[Defines.RM_CHUNKSIZE]); break; case Defines.RM_HEADER_MESSAGETYPE_WINACKSIZE: writer.Write((uint)messageBody[Defines.RM_WINACKSIZE]); break; case Defines.RM_HEADER_MESSAGETYPE_ABORTMESSAGE: writer.Write((uint)messageBody[Defines.RM_ABORTMESSAGE]); break; case Defines.RM_HEADER_MESSAGETYPE_PEERBW: writer.Write((uint)messageBody[Defines.RM_PEERBW, Defines.RM_PEERBW_VALUE]); writer.Write((byte)messageBody[Defines.RM_PEERBW, Defines.RM_PEERBW_TYPE]); break; default: Logger.FATAL("Invalid message type:{0}", message); return(false); } message.MessageLength = (uint)InternalBuffer.Length; InternalBuffer.Position = 0; return(true); }
internal static AmfMessage GetInvokeResult(AmfMessage request, Variant parameters) { return(GetInvoke(request.ChannelId, request.StreamId, 0, false, request.InvokeId, Defines.RM_INVOKE_FUNCTION_RESULT, parameters)); }
private bool AuthenticateInboundAdobe(BaseRTMPProtocol pFrom, AmfMessage request, Variant authState) { if (authState["stage"] == null) authState["stage"] = "inProgress"; else if (authState["stage"] == "authenticated") return true; if (authState["stage"] != "inProgress") { Logger.FATAL("This protocol in not in the authenticating mode"); return false; } //1. Validate the type of request if (request.MessageType != Defines.RM_HEADER_MESSAGETYPE_INVOKE) { this.Log().Info("This is not an invoke. Wait for it..."); return true; } //2. Validate the invoke function name if (request.InvokeFunction != Defines.RM_INVOKE_FUNCTION_CONNECT) { Logger.FATAL("This is not a connect invoke"); return false; } //3. Pick up the first param in the invoke Variant connectParams = request.InvokeParam[0]; if (connectParams != VariantType.Map) { Logger.FATAL("first invoke param must be a map"); return false; } //4. pick up the agent name if ((connectParams[Defines.RM_INVOKE_PARAMS_CONNECT_FLASHVER] == null) || (connectParams[Defines.RM_INVOKE_PARAMS_CONNECT_FLASHVER] != VariantType.String)) { Logger.WARN("Incorrect user agent"); authState["stage"] = "authenticated"; authState["canPublish"] = false; authState["canOverrideStreamName"] = false; return true; } string flashVer = connectParams[Defines.RM_INVOKE_PARAMS_CONNECT_FLASHVER]; //6. test the flash ver against the allowed encoder agents if (_adobeAuthSettings[Defines.CONF_APPLICATION_AUTH_ENCODER_AGENTS, flashVer] == null) { Logger.WARN("This agent is not on the list of allowed encoders: `{0}`", flashVer); authState["stage"] = "authenticated"; authState["canPublish"] = false; authState["canOverrideStreamName"] = false; return true; } //7. pick up the tcUrl from the first param if ((connectParams[Defines.RM_INVOKE_PARAMS_CONNECT_APP] == null) || (connectParams[Defines.RM_INVOKE_PARAMS_CONNECT_APP] != VariantType.String)) { Logger.WARN("Incorrect app url"); authState["stage"] = "authenticated"; authState["canPublish"] = (bool)false; authState["canOverrideStreamName"] = (bool)false; return true; } string appUrl = connectParams[Defines.RM_INVOKE_PARAMS_CONNECT_APP]; //8. Split the URI into parts var appUrlParts = appUrl.Split('?'); if (appUrlParts.Length == 1) { //bare request. We need to tell him that he needs auth if (!pFrom.SendMessage( ConnectionMessageFactory.GetInvokeConnectError(request, "[ AccessManager.Reject ] : [ code=403 need auth; authmod=adobe ] : "))) { Logger.FATAL("Unable to send message"); return false; } if (!pFrom.SendMessage( ConnectionMessageFactory.GetInvokeClose())) { Logger.FATAL("Unable to send message"); return false; } //pFrom.SendMessagesBlock.TriggerBatch(); pFrom.EnqueueForOutbound(pFrom.OutputBuffer); pFrom.GracefullyEnqueueForDelete(); return true; } else if (appUrlParts.Length == 2) { var _params = appUrlParts[1].GetURLParam(); if ((!_params.ContainsKey("authmod")) || (!_params.ContainsKey("user"))) { Logger.WARN("Invalid appUrl: {0}", appUrl); authState["stage"] = "authenticated"; authState["canPublish"] = false; authState["canOverrideStreamName"] = false; return true; } string user = _params["user"]; if (_params.ContainsKey("challenge") && _params.ContainsKey("response") && _params.ContainsKey("opaque")) { string challenge = _params["challenge"]; string response = _params["response"]; string opaque = _params["opaque"]; string password = GetAuthPassword(user); if (password == "") { Logger.WARN("No such user: `{0}`", user); if (!pFrom.SendMessage( ConnectionMessageFactory.GetInvokeConnectError(request, "[ AccessManager.Reject ] : [ authmod=adobe ] : ?reason=authfailed&opaque=vgoAAA=="))) { Logger.FATAL("Unable to send message"); return false; } if (!pFrom.SendMessage( ConnectionMessageFactory.GetInvokeClose())) { Logger.FATAL("Unable to send message"); return false; } //pFrom.SendMessagesBlock.TriggerBatch(); pFrom.EnqueueForOutbound(pFrom.OutputBuffer); pFrom.GracefullyEnqueueForDelete(); return true; } var md5 = MD5.Create(); string str1 = user + _adobeAuthSalt + password; string hash1 = Convert.ToBase64String(md5.ComputeHash(Encoding.ASCII.GetBytes(str1))); string str2 = hash1 + opaque + challenge; string wanted = Convert.ToBase64String(md5.ComputeHash(Encoding.ASCII.GetBytes(str2))); if (response == wanted) { authState["stage"] = "authenticated"; authState["canPublish"] = true; authState["canOverrideStreamName"] = true; Logger.WARN("User `{0}` authenticated", user); return true; } else { Logger.WARN("Invalid password for user `{0}`", user); if (!pFrom.SendMessage( ConnectionMessageFactory.GetInvokeConnectError(request, "[ AccessManager.Reject ] : [ authmod=adobe ] : ?reason=authfailed&opaque=vgoAAA=="))) { Logger.FATAL("Unable to send message"); return false; } if (!pFrom.SendMessage( ConnectionMessageFactory.GetInvokeClose())) { Logger.FATAL("Unable to send message"); return false; } //pFrom.SendMessagesBlock.TriggerBatch(); pFrom.EnqueueForOutbound(pFrom.OutputBuffer); pFrom.GracefullyEnqueueForDelete(); return true; } } else { string challenge = Utils.GenerateRandomString(6) + "=="; string opaque = challenge; string description = "[ AccessManager.Reject ] : [ authmod=adobe ] : ?reason=needauth&user={0}&salt={1}&challenge={2}&opaque={3}"; description = string.Format(description, user, _adobeAuthSalt, challenge, opaque); if (!pFrom.SendMessage(ConnectionMessageFactory.GetInvokeConnectError(request, description))) { Logger.FATAL("Unable to send message"); return false; } if (!pFrom.SendMessage(ConnectionMessageFactory.GetInvokeClose())) { Logger.FATAL("Unable to send message"); return false; } //pFrom.SendMessagesBlock.TriggerBatch(); pFrom.EnqueueForOutbound(pFrom.OutputBuffer); pFrom.GracefullyEnqueueForDelete(); return true; } } else { Logger.FATAL("Invalid appUrl: {0}", appUrl); return false; } }
//private bool PlayAnotherStream(BaseRTMPProtocol pFrom,string streamName) //{ // var FCSubscribeRequest = StreamMessageFactory.GetInvokeFCSubscribe(streamName); // if (!SendRTMPMessage(pFrom, FCSubscribeRequest, true)) // { // Logger.FATAL("Unable to send request:\n{0}", FCSubscribeRequest.ToString()); // return false; // } // var createStreamRequest = StreamMessageFactory.GetInvokeCreateStream(); // if (!SendRTMPMessage(pFrom, createStreamRequest, true)) // { // Logger.FATAL("Unable to send request:\n{0}", createStreamRequest.ToString()); // return false; // } // return true; //} private bool AuthenticateInbound(BaseRTMPProtocol pFrom, AmfMessage request, Variant authState) { if (_authMethod == Defines.CONF_APPLICATION_AUTH_TYPE_ADOBE) return AuthenticateInboundAdobe(pFrom, request, authState); Logger.FATAL("Auth scheme not supported: {0}", _authMethod); return false; }
virtual protected bool ProcessInvokeGeneric(BaseRTMPProtocol pFrom, AmfMessage request) { //Logger.WARN("Default implementation of ProcessInvokeGeneric: Request: {0}", request.InvokeFunction); try { var result = Application.CallCustomFunction(pFrom, request.InvokeFunction,request.InvokeParam); return SendRTMPMessage(pFrom, GenericMessageFactory.GetInvokeResult(request.ChannelId, request.StreamId, request.InvokeId, Variant.Get(), result)); } catch (CallErrorException ex) { return SendRTMPMessage(pFrom, GenericMessageFactory.GetInvokeError(request.ChannelId, request.StreamId, request.InvokeId, Variant.Get(), Variant.Get(ex.Message))); } catch (Exception ex) { return SendRTMPMessage(pFrom, GenericMessageFactory.GetInvokeCallFailedError(request)); } }
protected virtual bool ProcessInvokeConnect(BaseRTMPProtocol pFrom,AmfMessage message) { string appName = message.InvokeParam[0][Defines.RM_INVOKE_PARAMS_CONNECT_APP]; //var parameters = pFrom.CustomParameters; //var instanceName = index == -1?"_default_": appName.Substring(index + 1); var oldApplication = pFrom.Application; var newApp = ClientApplicationManager.SwitchRoom(pFrom, appName, Configuration); if (newApp != null && newApp != oldApplication) { var handler = newApp.GetProtocolHandler<BaseRTMPAppProtocolHandler>(pFrom); return handler.ProcessInvokeConnect(pFrom, message); } if (newApp == null || (newApp == oldApplication && !Application.OnConnect(pFrom, message.InvokeParam))) { if (!pFrom.SendMessage(ConnectionMessageFactory.GetInvokeConnectError(message, ""))) { return false; } if (!pFrom.SendMessage(ConnectionMessageFactory.GetInvokeClose())) { return false; } // pFrom.EnqueueForOutbound(); return true; } //1. Send the channel specific messages if (!SendRTMPMessage(pFrom, GenericMessageFactory.GetWinAckSize(2500000))) return false; if (!SendRTMPMessage(pFrom, GenericMessageFactory.GetPeerBW(2500000, Defines.RM_PEERBW_TYPE_DYNAMIC))) return false; //2. Initialize stream 0 //if (!SendRTMPMessage(pFrom, StreamMessageFactory.GetUserControlStreamBegin(0))) //{ // return false; //} if (!pFrom.SendMessage(GenericMessageFactory.GetChunkSize(pFrom._outboundChunkSize))) return false; //3. Send the connect result if (!SendRTMPMessage(pFrom, ConnectionMessageFactory.GetInvokeConnectResult(message))) return false; //4. Send onBWDone if (!SendRTMPMessage(pFrom, GenericMessageFactory.GetInvokeOnBWDone(1024 * 8))) return false; return true; }
public static AmfMessage GetInvokeCreateStreamResult(AmfMessage request, double createdStreamId) { return GetInvokeCreateStreamResult(request.ChannelId, request.StreamId, request.Body[Defines.RM_INVOKE,Defines.RM_INVOKE_ID], createdStreamId); }
private bool ProcessInvokeOnStatus(BaseRTMPProtocol pFrom, AmfMessage request) { if ((!NeedsToPullExternalStream(pFrom)) && (!NeedsToPushLocalStream(pFrom))) { Logger.WARN("Default implementation of ProcessInvokeOnStatus in application {0}: Request:\n{1}", Application.Name, request.ToString()); return true; } //1. Test and see if this connection is an outbound RTMP connection //and get a pointer to it if (pFrom.Type != ProtocolTypes.PT_OUTBOUND_RTMP) { Logger.FATAL("This is not an outbound connection"); return false; } var pProtocol = (OutboundRTMPProtocol)pFrom; //2. Validate the request if (request.InvokeParam[1]["code"] != VariantType.String) { Logger.FATAL("invalid onStatus:\n{0}", request.Body.ToString()); return false; } //6. Get our hands on streaming parameters var path = NeedsToPullExternalStream(pFrom) ? "externalStreamConfig" : "localStreamConfig"; Variant parameters = pFrom.CustomParameters["customParameters"][path]; if (NeedsToPullExternalStream(pFrom)) { if (request.InvokeParam[1]["code"] != "NetStream.Play.Start") { Logger.WARN("onStatus message ignored:\n{0}", request.Body.ToString()); return true; } if (!Application.StreamNameAvailable(parameters["localStreamName"],pProtocol)) { Logger.WARN("Stream name {0} already occupied and application doesn't allow duplicated inbound network streams", parameters["localStreamName"]); return false; } var pStream = pProtocol.CreateINS(request.ChannelId,request.StreamId, parameters["localStreamName"]); if (pStream == null) { Logger.FATAL("Unable to create stream"); return false; } var waitingSubscribers = Application.StreamsManager.GetWaitingSubscribers(pStream.Name, pStream.Type); foreach (var waitingSubscriber in waitingSubscribers) { pStream.Link(waitingSubscriber); } } else { if (request.InvokeParam[1]["code"] != "NetStream.Publish.Start") { Logger.WARN("onStatus message ignored:\n{0}", request.ToString()); return true; } var pBaseInStream = (IInStream)Application.StreamsManager.FindByUniqueId(parameters["localUniqueStreamId"]); if (pBaseInStream == null) { Logger.FATAL("Unable to find the inbound stream with id {0}", parameters["localUniqueStreamId"]); return false; } //5. Create the network outbound stream var pBaseOutNetRTMPStream = pProtocol.CreateONS( request.StreamId, pBaseInStream.Name, pBaseInStream.Type); if (pBaseOutNetRTMPStream == null) { Logger.FATAL("Unable to create outbound stream"); return false; } pBaseOutNetRTMPStream.SendOnStatusPlayMessages = false; //6. Link and return if (!pBaseInStream.Link(pBaseOutNetRTMPStream)) { Logger.FATAL("Unable to link streams"); return false; } } return true; }
public bool SendMessage(AmfMessage message, bool enqueueForOutbound = false, bool recycleMessageBody = true) { //SendMessagesBlock.Post(new Tuple<AmfMessage,bool>(message, recycleMessageBody)); //if(enqueueForOutbound)SendMessagesBlock.TriggerBatch(); //return true; lock (_rtmpProtocolSerializer) { if (!_rtmpProtocolSerializer.Serialize(GetChannel(message.ChannelId), message, OutputBuffer, _outboundChunkSize)) { FATAL("Unable to serialize RTMP message"); return false; } if (recycleMessageBody) message.Body.Recycle(); _txInvokes++; return !enqueueForOutbound || EnqueueForOutbound(OutputBuffer); } }
public bool Serialize(Channel channel, AmfMessage message, Stream stream, uint chuckSize) { Serialize(ref message); var header = message.Header; long available; InternalBuffer.Position = 0; while ((available = InternalBuffer.Length - InternalBuffer.Position) != 0) { header.Write(channel, stream); if (available >= chuckSize) { InternalBuffer.CopyPartTo(stream, (int)chuckSize); channel.lastOutProcBytes += chuckSize; } else { InternalBuffer.CopyPartTo(stream, (int)available); channel.lastOutProcBytes += (uint)available; } } //Debug.WriteLine(channel.lastOutProcBytes); channel.lastOutProcBytes = 0; InternalBuffer.Recycle(); return true; }
protected bool SendRTMPMessage(BaseRTMPProtocol pTo, AmfMessage message, bool trackResponse = false, bool recycleMessageBody = true) { switch (message.MessageType) { case Defines.RM_HEADER_MESSAGETYPE_INVOKE: if (message.InvokeFunction != Defines.RM_INVOKE_FUNCTION_RESULT) { if (!_nextInvokeId.ContainsKey(pTo.Id)) { Logger.FATAL("Unable to get next invoke ID"); return false; } if (trackResponse) { uint invokeId = _nextInvokeId[pTo.Id]; _nextInvokeId[pTo.Id] = invokeId + 1; message.InvokeId = invokeId; if (!_resultMessageTracking.ContainsKey(pTo.Id)) _resultMessageTracking[pTo.Id] = new Dictionary<uint, AmfMessage>(); //do not store stupid useless amount of data needed by onbwcheck if (message.InvokeFunction == Defines.RM_INVOKE_FUNCTION_ONBWCHECK) _resultMessageTracking[pTo.Id][invokeId] = _onBWCheckStrippedMessage; else _resultMessageTracking[pTo.Id][invokeId] = message; recycleMessageBody = false; } else { message.InvokeId = 0; } //return pTo.SendMessage(message,true); } return pTo.SendMessage( message, true, recycleMessageBody); case Defines.RM_HEADER_MESSAGETYPE_FLEXSTREAMSEND: case Defines.RM_HEADER_MESSAGETYPE_WINACKSIZE: case Defines.RM_HEADER_MESSAGETYPE_PEERBW: case Defines.RM_HEADER_MESSAGETYPE_USRCTRL: case Defines.RM_HEADER_MESSAGETYPE_ABORTMESSAGE: return pTo.SendMessage( message, true, recycleMessageBody); default: Logger.FATAL("Unable to send message:\n{0}", message.ToString()); return false; } }
private bool ProcessInvokeCreateStreamResult(BaseRTMPProtocol pFrom,AmfMessage request, AmfMessage response) { //1. Do we need to push/pull a stream? if ((!NeedsToPullExternalStream(pFrom)) && (!NeedsToPushLocalStream(pFrom))) { Logger.WARN("Default implementation of ProcessInvokeCreateStreamResult: Request:\n{0}\nResponse:\n{1}", request.ToString(), response.ToString()); return true; } //2. Test and see if this connection is an outbound RTMP connection //and get a pointer to it if (pFrom.Type != ProtocolTypes.PT_OUTBOUND_RTMP) { Logger.FATAL("This is not an outbound connection"); return false; } var pProtocol = (OutboundRTMPProtocol)pFrom; //3. Test the response if (response.InvokeFunction != Defines.RM_INVOKE_FUNCTION_RESULT || response.InvokeParam[1] != VariantType.Numberic) { Logger.FATAL("createStream failed:\n{0}", response.ToString()); return false; } //4. Get the assigned stream ID uint rtmpStreamId = response.InvokeParam[1]; //5. Create the neutral stream var pStream = pProtocol.CreateNeutralStream(ref rtmpStreamId); if (pStream == null) { Logger.FATAL("Unable to create neutral stream"); return false; } //6. Get our hands on streaming parameters var path = NeedsToPullExternalStream(pFrom) ? "externalStreamConfig" : "localStreamConfig"; var parameters = pFrom.CustomParameters["customParameters"][path]; //7. Create publish/play request AmfMessage publishPlayRequest; if (NeedsToPullExternalStream(pFrom)) { publishPlayRequest = StreamMessageFactory.GetInvokePlay(3, rtmpStreamId, parameters["localStreamName"], -2, -1); } else { string targetStreamType = parameters["targetStreamType"]; if ((targetStreamType != "live") && (targetStreamType != "record") && (targetStreamType != "append")) { targetStreamType = "live"; } publishPlayRequest = StreamMessageFactory.GetInvokePublish(3, rtmpStreamId, parameters["targetStreamName"], targetStreamType); } //8. Send it if (!SendRTMPMessage(pFrom, publishPlayRequest, true)) { Logger.FATAL("Unable to send request:\n{0}", publishPlayRequest.ToString()); return false; } //9. Done return true; }