Example #1
0
        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"}
     }));
 }
Example #3
0
 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" }
     })));
 }
Example #4
0
 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);
 }
Example #13
0
        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);
        }
Example #14
0
 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;
        }
Example #21
0
 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;
        }