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; } }