Ejemplo n.º 1
0
 public void EnqueueForDelete()
 {
     Cleanup();
     _rtsp.EnqueueForDelete();
 }
 private bool HandleRTSPResponse200Options(RtspProtocol rtspProtocol, Variant requestHeaders, ref string requestContent, Variant responseHeaders, ref string responseContent)
 {
     if (rtspProtocol.HasConnectivity) return true;
     if (rtspProtocol.CustomParameters["connectionType"] == null)
     {
         FATAL("Bogus connection");
         rtspProtocol.EnqueueForDelete();
         return false;
     }
     //1. Sanitize
     if (responseHeaders[RTSP_HEADERS, RTSP_HEADERS_PUBLIC] == null)
     {
         FATAL("Invalid response:\n{0}", (responseHeaders.ToString()));
         return false;
     }
     //2. get the raw options
     string raw = responseHeaders[RTSP_HEADERS, RTSP_HEADERS_PUBLIC];
     //3. split and normalize the options
     var parts = raw.Split(',').Select(x => x.Split(':')).ToDictionary(x => x[0], x => x[1]);
     string url = requestHeaders[RTSP_FIRST_LINE, RTSP_URL];
     switch ((string)rtspProtocol.CustomParameters["connectionType"])
     {
         case "pull":
             //4. Test the presence of the wanted methods
             if (!parts.ContainsKey(RTSP_METHOD_DESCRIBE) || !parts.ContainsKey(RTSP_METHOD_SETUP) ||
                 !parts.ContainsKey(RTSP_METHOD_PLAY))
             {
                 FATAL("Some of the supported methods are missing: {0}", (raw));
                 return false;
             }
             rtspProtocol.PushRequestFirstLine(RTSP_METHOD_DESCRIBE, url, RTSP_VERSION_1_0);
             rtspProtocol.PushRequestHeader(RTSP_HEADERS_ACCEPT, RTSP_HEADERS_ACCEPT_APPLICATIONSDP);
             return rtspProtocol.SendRequestMessage();
         case "push":
             //4. Test the presence of the wanted methods
             if (!parts.ContainsKey(RTSP_METHOD_ANNOUNCE) || !parts.ContainsKey(RTSP_METHOD_SETUP) ||
                 !parts.ContainsKey(RTSP_METHOD_RECORD))
             {
                 FATAL("Some of the supported methods are missing: {0}", (raw));
                 return false;
             }
             var parameters = rtspProtocol.CustomParameters;
             rtspProtocol.PushRequestFirstLine(RTSP_METHOD_ANNOUNCE,url,RTSP_VERSION_1_0);
             var sdp = ComputeSDP(rtspProtocol,
                 parameters["customParameters","localStreamConfig","localStreamName"],
                 parameters["customParameters","localStreamConfig","targetStreamName"],
                 parameters["customParameters","localStreamConfig","targetUri","host"]);
             if (sdp == "")
             {
                 FATAL("Unable to compute sdp");
                 return false;
             }
             rtspProtocol.PushRequestHeader(RTSP_HEADERS_CONTENT_TYPE, RTSP_HEADERS_ACCEPT_APPLICATIONSDP);
             rtspProtocol.PushRequestContent(sdp,false);
             return rtspProtocol.SendRequestMessage();
         default:
             FATAL("Bogus connection");
             rtspProtocol.EnqueueForDelete();
             return false;
     }
 }
        public bool HandleRTSPRequest(RtspProtocol from,Variant requestHeaders,string requestContent)
        {
            string method = requestHeaders[RTSP_FIRST_LINE, RTSP_METHOD];
            //1. we need a CSeq
            if (requestHeaders[RTSP_HEADERS, RTSP_HEADERS_CSEQ] == null)
            {
                FATAL("Request doesn't have {0}:\n{1}", RTSP_HEADERS_CSEQ, requestHeaders);
                return false;
            }
            //2. Validate session id
            string wantedSessionId = from.SessionId;
            if (!string.IsNullOrEmpty(wantedSessionId))
            {
                var requestSessionId = "";
                if (requestHeaders[RTSP_HEADERS, RTSP_HEADERS_SESSION] == null)
                {
                    FATAL("No session id");
                    return false;
                }
                requestSessionId = requestHeaders[RTSP_HEADERS, RTSP_HEADERS_SESSION];
                var parts = requestSessionId.Split(';');
                if (parts.Length >= 1)
                {
                    requestSessionId = parts[0];
                }
                if (requestSessionId != wantedSessionId)
                {
                    FATAL("Invalid session ID. Wanted: `{0}`; Got: `{1}`",
                            (wantedSessionId),
                            (requestSessionId));
                    return false;
                }
            }
            //4. Prepare a fresh new response. Add the sequence number
            from.ClearResponseMessage();
            from.PushResponseHeader(RTSP_HEADERS_CSEQ, requestHeaders[RTSP_HEADERS, RTSP_HEADERS_CSEQ]);
            //5. Do we have authentication? We will authenticate everything except "OPTIONS"
            if ( !string.IsNullOrEmpty(_usersFile) && NeedAuthentication(from,requestHeaders,requestContent))
            {
                //6. Re-parse authentication file if necessary
                if (!ParseUsersFile())
                {
                    FATAL("Unable to parse authentication file");
                    return false;
                }
                //7. Get the real name to use it further in authentication process
                string realmName = GetAuthenticationRealm(from, requestHeaders,
                        requestContent);
                //8. Do we have that realm?
                if (_realms[realmName]==null)
                {
                    FATAL("Realm `{0}` not found", (realmName));
                    return false;
                }
                Variant realm = _realms[realmName];
                //9. Is the user even trying to authenticate?
                if (requestHeaders[RTSP_HEADERS, RTSP_HEADERS_AUTHORIZATION] == null)
                {
                    return SendAuthenticationChallenge(from, realm);
                }
                else
                {
                    //14. The client sent us some response. Validate it now
                    //Did we ever sent him an authorization challange?
                    if (from.CustomParameters["wwwAuthenticate"] ==null)
                    {
                        FATAL("Client tried to authenticate and the server didn't required that");
                        return false;
                    }

                    //15. Get the server challenge
                    string wwwAuthenticate = from.CustomParameters["wwwAuthenticate"];

                    //16. Get the client response
                    string authorization = requestHeaders[RTSP_HEADERS, RTSP_HEADERS_AUTHORIZATION];

                    //17. Try to authenticate
                    if (!HTTPAuthHelper.ValidateAuthRequest(wwwAuthenticate,
                            authorization,
                            method,
                            (string)requestHeaders[RTSP_FIRST_LINE,RTSP_URL],
                            realm))
                    {
                        WARN("Authorization failed: challenge: {0}; response: {1}",
                                wwwAuthenticate, authorization);
                        return SendAuthenticationChallenge(from, realm);
                    }

                    //18. Success. User authenticated
                    //INFO("User authenticated: %s", (authorization));
                }
            }
            switch (method)
            {
                case RTSP_METHOD_OPTIONS:
                    from.PushResponseFirstLine(RTSP_VERSION_1_0, 200, "OK");
                    from.PushResponseHeader(RTSP_HEADERS_PUBLIC, "DESCRIBE, OPTIONS, PAUSE, PLAY, SETUP, TEARDOWN, ANNOUNCE, RECORD");
                    return from.SendResponseMessage();
                case RTSP_METHOD_DESCRIBE:
                    //1. get the stream name
                    Uri uri = new Uri(requestHeaders[RTSP_FIRST_LINE,RTSP_URL]);
                    
                    string streamName = (uri.Segments.LastOrDefault(x=>!x.EndsWith("/"))??"")+uri.Query;
                    if (streamName == "")
                    {
                        FATAL("Invalid stream name");
                        return false;
                    }

                    //2. Get the inbound stream capabilities
                    IInNetStream pInStream = GetInboundStream(streamName);

                    //3. Prepare the body of the response
                    string outboundContent = ComputeSDP(from, streamName, "", "0.0.0.0");
                    if (outboundContent == "")
                    {
                        FATAL("Unable to compute SDP");
                        return false;
                    }

                    //4. Save the stream id for later usage
                    from.CustomParameters["streamId"] = pInStream.UniqueId;

                    //5. Mark this connection as outbound connection
                    from.CustomParameters["isInbound"] = false;

                    //6. prepare the response
                    from.PushResponseFirstLine(RTSP_VERSION_1_0, 200, "OK");
                    from.PushResponseHeader(RTSP_HEADERS_CONTENT_TYPE, RTSP_HEADERS_ACCEPT_APPLICATIONSDP);
                    from.PushResponseContent(outboundContent, false);

                    //7. Done
                    return from.SendResponseMessage();
                case RTSP_METHOD_SETUP:
                    if (from.CustomParameters["isInbound"] != VariantType.Boolean)
                    {
                        FATAL("Invalid state");
                        return false;
                    }

                    return @from.CustomParameters["isInbound"] ? HandleRTSPRequestSetupInbound(@from, requestHeaders, requestContent) : HandleRTSPRequestSetupOutbound(@from, requestHeaders, requestContent);
                case RTSP_METHOD_PLAY:
                    return HandleRTSPRequestPlay(from, requestHeaders, requestContent);
                case RTSP_METHOD_TEARDOWN:
                    from.EnqueueForDelete();
                    return true;
                case RTSP_METHOD_ANNOUNCE:
                    return HandleRTSPRequestAnnounce(from, requestHeaders, requestContent);
                case RTSP_METHOD_RECORD:
                    //1. Make sure we have everything and we are in the proper state
                    if ((from.CustomParameters["isInbound"] != VariantType.Boolean)
                            || ((bool)from.CustomParameters["isInbound"] != true))
                    {
                        FATAL("Invalid state");
                        return false;
                    }

                    if (from.CustomParameters["pendingTracks"] != VariantType.Map)
                    {
                        FATAL("Invalid state");
                        return false;
                    }

                    //3. Get the inbound connectivity
                    InboundConnectivity pConnectivity = from.InboundConnectivity;
                    if (pConnectivity == null)
                    {
                        FATAL("Unable to get inbound connectivity");
                        return false;
                    }
                    if (!pConnectivity.Initialize())
                    {
                        FATAL("Unable to initialize inbound connectivity");
                        return false;
                    }

                    //4. Send back the response
                    from.PushResponseFirstLine(RTSP_VERSION_1_0, 200, "OK");
                    return from.SendResponseMessage();
                case RTSP_METHOD_PAUSE:
                    from.PushResponseFirstLine(RTSP_VERSION_1_0, 200, "OK");
                    return from.SendResponseMessage();
                default:
                    return false;
            }
        }
        private bool HandleRTSPResponse200Announce(RtspProtocol rtspProtocol, Variant requestHeaders, ref string requestContent, Variant responseHeaders, ref string responseContent)
        {
            bool forceTcp = rtspProtocol.CustomParameters["forceTcp"];

            //3. Get the outbound connectivity
            var pConnectivity = GetOutboundConnectivity(rtspProtocol,forceTcp);
            if (pConnectivity == null)
            {
                FATAL("Unable to get the outbound connectivity");
                return false;
            }
            var param = rtspProtocol.CustomParameters;
            string trackId = "";
            bool isAudio = false;
            if (param["audioTrackId"] != null)
            {
                trackId = param["audioTrackId"];
                param["audioTrackId"] = null;
                param["lastSetup"] = "audio";
                isAudio = true;
                pConnectivity.HasAudio = true;
            }
            else
            {
                if (param["videoTrackId"] != null)
                {
                    trackId = param["videoTrackId"];
                    param["videoTrackId"] = null;
                    param["lastSetup"] = "video";
                    pConnectivity.HasVideo = true;
                }
            }
            if (trackId != "")
            {
                var variantUri = param["uri"];
                var uri = variantUri["fullUri"] + "/trackID=" + trackId;
                rtspProtocol.PushRequestFirstLine(RTSP_METHOD_SETUP, uri, RTSP_VERSION_1_0);

                var transport = forceTcp ? $"RTP/AVP/TCP;unicast;interleaved={(isAudio ? pConnectivity.AudioChannels : pConnectivity.VideoChannels)};mode=record" : $"RTP/AVP;unicast;client_port={(isAudio ? pConnectivity.AudioChannels : pConnectivity.VideoChannels)};mode=record";
                rtspProtocol.PushRequestHeader(RTSP_HEADERS_TRANSPORT, transport);
                return rtspProtocol.SendRequestMessage();
            }
            else
            {
                FATAL("Bogus RTSP connection");
               rtspProtocol.EnqueueForDelete();
                return false;
            }
        }