/// <summary> /// Handles the response to a setup message. /// </summary> /// <param name="message">A response message.</param> private void HandleResponseToSetup(RtspResponse message) { RtspRequest original = message.OriginalRequest; string setupKey = original.SourcePort.RemoteAdress + "SEQ" + message.CSeq.ToString(CultureInfo.InvariantCulture); if (message.IsOk) { Forwarder forwarder = ConfigureTransportAndForwarder(message, _setupForwarder[setupKey]); RtspSession newSession; string sessionKey = RtspSession.GetSessionName(original.RtspUri, message.Session); if (_activesSession.ContainsKey(sessionKey)) { newSession = _activesSession[sessionKey]; _logger.Info("There was an already a session with ths ID {0}", newSession.Name); } else { _logger.Info("Create a new session with the ID {0}", sessionKey); newSession = new RtspSession(); newSession.Name = message.Session; newSession.Destination = original.RtspUri.Authority; _activesSession.Add(sessionKey, newSession); } newSession.AddForwarder(original.RtspUri, forwarder); newSession.Timeout = message.Timeout; } // No needed here anymore. _setupForwarder.Remove(setupKey); }
/// <summary> /// Handles one message. /// </summary> /// <param name="message">The message.</param> private void HandleOneMessage(RtspMessage message) { Contract.Requires(message != null); RtspListener destination = null; if (message is RtspRequest) { destination = HandleRequest(ref message); _logger.Debug("Dispatch message from {0} to {1}", message.SourcePort != null ? message.SourcePort.RemoteAdress : "UNKNOWN", destination != null ? destination.RemoteAdress : "UNKNOWN"); // HandleRequest can change message type. if (message is RtspRequest) { var context = new OriginContext(); context.OriginCSeq = message.CSeq; context.OriginSourcePort = message.SourcePort; (message as RtspRequest).ContextData = context; } } else if (message is RtspResponse) { RtspResponse response = message as RtspResponse; if (response.OriginalRequest != null) { var context = response.OriginalRequest.ContextData as OriginContext; if (context != null) { destination = context.OriginSourcePort; response.CSeq = context.OriginCSeq; _logger.Debug("Dispatch response back to {0}", destination.RemoteAdress); } } HandleResponse(response); } if (destination != null) { bool isGood = destination.SendMessage(message); if (!isGood) { destination.Stop(); _serverListener.Remove(destination.RemoteAdress); // send back a message because we can't forward. if (message is RtspRequest && message.SourcePort != null) { RtspRequest request = message as RtspRequest; RtspResponse theDirectResponse = request.CreateResponse(); _logger.Warn("Error during forward : {0}. So sending back a direct error response", message.Command); theDirectResponse.ReturnCode = 500; request.SourcePort.SendMessage(theDirectResponse); } } } }
public RtspResponse Options(RtspRequest request) { return(RtspResponse.CreateBuilder() .Status(RtspResponse.Status.Ok) .AddHeader(RtspHeaders.Names.PUBLIC, "OPTIONS, DESCRIBE, GET_PARAMETER, SETUP, PLAY, TEARDOWN") .Build()); }
/// <summary> /// <see cref="IRequestHandler.Describe(RtspRequest)"/> /// </summary> /// <param name="request"></param> /// <returns></returns> public override RtspResponse Describe(RtspRequest request) { return(RtspResponse.CreateBuilder() .Status(RtspResponse.Status.Ok) .Body(CreateSDP(request)) .Build()); }
private static RtspListener HandleRequestWithoutUrl(ref RtspMessage message) { Contract.Requires(message != null); Contract.Requires(message is RtspRequest); Contract.Ensures(Contract.Result <RtspListener>() != null); Contract.Ensures(Contract.ValueAtReturn(out message) != null); RtspListener destination; destination = message.SourcePort; RtspRequest request = message as RtspRequest; RtspResponse theDirectResponse = request.CreateResponse(); if (request.RequestTyped == RtspRequest.RequestType.OPTIONS) { // We know what to do... theDirectResponse.ReturnCode = 200; // But perhaps it is to prevent timeout !! // ARG ..... _logger.Info("I got an OPTION * message, I reply but I do not forward! The end session may timeout."); request.LogMessage(); } else { _logger.Warn("Do not know how to handle : {0}", message.Command); theDirectResponse.ReturnCode = 400; } message = theDirectResponse; return(destination); }
public override RtspResponse SetUp(RtspRequest request) { return RtspResponse.CreateBuilder() .Status(RtspResponse.Status.Ok) .AddHeader(CALLED_METHOD_HEADER, "SETUP") .Build(); }
public override RtspResponse TearDown(RtspRequest request) { return RtspResponse.CreateBuilder() .Status(RtspResponse.Status.Ok) .AddHeader(CALLED_METHOD_HEADER, "TEARDOWN") .Build(); ; }
public override RtspResponse SetUp(RtspRequest request) { var builder = RtspResponse.CreateBuilder().Status(RtspResponse.Status.Ok); var transport = request.Transport; if (transport == null) { return(builder.Status(RtspResponse.Status.BadRequest).Build()); } else if (transport.Type != TransportType.RtspInterleaved) { return(builder.Status(RtspResponse.Status.UnsupportedTransport).Build()); } lock (this) { PortPair channels = new PortPair(_currentChannel, _currentChannel + 1); _currentChannel += 2; var session = new InterleavedTestSession(request.Context, _spy, channels, PAYLOAD_TYPE); _sessionManager.RegisterSession(session); transport = TransportHeader.CreateBuilder() .Type(TransportType.RtspInterleaved) .InterleavedChannels(channels) .Build(); return(builder.AddHeader(RtspHeaders.Names.TRANSPORT, transport.ToString()) .AddHeader(RtspHeaders.Names.SESSION, session.Id) .Build()); } }
private void RTSP_ProcessAuthorization(RtspRequest message, RtspListener listener) { bool authorized = false; if (message.Headers.ContainsKey("Authorization") == true) { // The Header contained Authorization // Check the message has the correct Authorization // If it does not have the correct Authorization then close the RTSP connection authorized = _auth.IsValid(message); if (authorized == false) { // Send a 401 Authentication Failed reply, then close the RTSP Socket Rtsp.Messages.RtspResponse authorization_response = message.CreateResponse(_logger); authorization_response.AddHeader("WWW-Authenticate: " + _auth.GetHeader()); authorization_response.ReturnCode = 401; listener.SendMessage(authorization_response); CloseConnection("unauthorized"); listener.Dispose(); return; } } if ((message.Headers.ContainsKey("Authorization") == false)) { // Send a 401 Authentication Failed with extra info in WWW-Authenticate // to tell the Client if we are using Basic or Digest Authentication Rtsp.Messages.RtspResponse authorization_response = message.CreateResponse(_logger); authorization_response.AddHeader("WWW-Authenticate: " + _auth.GetHeader()); // 'Basic' or 'Digest' authorization_response.ReturnCode = 401; listener.SendMessage(authorization_response); return; } }
public void Initialize() { lock (SourceLock) { if (_state != PlayingState.NONE) { // Already initialized return; } var method = RtspRequest.RtspMethod.OPTIONS; var builder = RtspRequest.CreateBuilder().Uri(_currentUri).Method(method); // TODO(frank.lamar): Add check for supported operations. Otherwise this call // is meaning less. CheckResponse(_client.Send(builder.Build()), method); // Send Describe to server method = RtspRequest.RtspMethod.DESCRIBE; var response = CheckResponse(_client.Send(builder.Method(method).Build()), method); _tracks = MediaTracks.FromSdp(response.GetBodyAsSdp(), _currentUri, _filter); // Initialize our session refresh timmer. _sessionRefreshTimer = new Timer(); _sessionRefreshTimer.AutoReset = true; _sessionRefreshTimer.Elapsed += SessionRefreshTimer_Elapsed; _state = PlayingState.INITIALIZED; } }
public override RtspResponse GetParamater(RtspRequest request) { return RtspResponse.CreateBuilder() .Status(RtspResponse.Status.Ok) .AddHeader(RtspHeaders.Names.SESSION, request.Session) .AddHeader(CALLED_METHOD_HEADER, "GET_PARAMATER") .Build(); }
public override RtspResponse SetUp(RtspRequest request) { var builder = RtspResponse.CreateBuilder(); var queryParams = HttpUtility.ParseQueryString(request.URI.Query); var sourceId = queryParams["sourceId"]; if (sourceId == null || !_sourceMgr.ContainsSource(sourceId)) { return(builder.Status(RtspResponse.Status.NotFound).Build()); } var transport = request.Transport; if (transport == null) { return(builder.Status(RtspResponse.Status.BadRequest).Build()); } if (transport.Type != Pelco.Media.RTSP.TransportType.UdpUnicast) { return(builder.Status(RtspResponse.Status.UnsupportedTransport).Build()); } if (transport.ClientPorts == null || !transport.ClientPorts.IsSet) { return(builder.Status(RtspResponse.Status.BadRequest).Build()); } var rtpPort = transport.ClientPorts.RtpPort; var address = transport.Destination != null?Dns.GetHostAddresses(transport.Destination)[0] : request.RemoteEndpoint.Address; var rtspSession = new RtspSession(_sourceMgr.GetSource(sourceId).GetPipelineSource(), PAYLOAD_TYPE, new IPEndPoint(address, rtpPort)); if (!_sessionMgr.RegisterSession(rtspSession)) { return(builder.Status(RtspResponse.Status.InternalServerError) .AddHeader(RtspHeaders.Names.CONTENT_TYPE, "text/plain") .Body("Unable to register Rtsp session with system") .Build()); } var session = Session.FromParts(rtspSession.Id, RtspSession.RTSP_SESSION_TIMEOUT); transport = TransportHeader.CreateBuilder() .Type(Pelco.Media.RTSP.TransportType.UdpUnicast) .ClientPorts(transport.ClientPorts) .ServerPorts(rtpPort + 3, rtpPort + 4) // Just create dummy ports. .Build(); return(builder.Status(RtspResponse.Status.Ok) .AddHeader(RtspHeaders.Names.TRANSPORT, transport.ToString()) .AddHeader(RtspHeaders.Names.SESSION, session.ToString()) .Build()); }
public void GetRtspMessageRequest(string requestLine, RtspRequest.RequestType requestType) { RtspMessage oneMessage = RtspMessage.GetRtspMessage(requestLine); Assert.IsInstanceOfType(typeof(RtspRequest), oneMessage); RtspRequest oneRequest = oneMessage as RtspRequest; Assert.AreEqual(requestType, oneRequest.RequestTyped); }
private Uri DetermineRealUri() { // The VideoXpert system does some non-standard RTSP redirecting so that it can determine the intent of // the client (intent being live or playback). It stats off by creating a spoofed SDP and then will // redirect on play. What we will do it write a wrapper that does some of the RTSP calls to first // determine what the actual live RTSP uri is. using (RtspClient client = new RtspClient(_uri)) { try { var method = RtspRequest.RtspMethod.OPTIONS; CheckResponse(client.Send(RtspRequest.CreateBuilder() .Method(method) .Uri(_uri) .Build()), method); method = RtspRequest.RtspMethod.DESCRIBE; var res = CheckResponse(client.Send(RtspRequest.CreateBuilder() .Method(method) .Uri(_uri) .Build()), method); var sdp = res.GetBodyAsSdp(); if (!sdp.SessionName.Contains("Spoofed session")) { // We are not working with a spoofed session just return // the current uri. return(_uri); } Uri controlUri = null; var tracks = MediaTracks.FromSdp(sdp, _uri); foreach (var track in tracks) { if (track.Type.Is(MimeType.ANY_VIDEO)) { if (GetRedirectUri(client, track, out controlUri)) { return(controlUri); } } } throw new RtspClientException($"Unable to retrieve usable uri from server at endpoint '{_uri}'"); } catch (Exception e) { LOG.Error(e, $"Failed while communicating with RTSP server at '{_uri}'"); throw e; } } }
/// <summary> /// <see cref="IRequestHandler.Play(RtspRequest)"/> /// </summary> /// <param name="request"></param> /// <returns></returns> public override RtspResponse Play(RtspRequest request) { var builder = RtspResponse.CreateBuilder().Status(RtspResponse.Status.Ok); var sessionId = request.Session; if (string.IsNullOrEmpty(sessionId) || !_sessionManager.PlaySession(sessionId)) { return(builder.Status(RtspResponse.Status.SessionNotFound).Build()); } return(builder.Build());; }
internal void TearDown() { //TODO vérifier ce bout de code.... // Je suis vraiement pas sur là. foreach (var destinationUri in _listOfForwarder.Keys) { RtspRequest tearDownMessage = new RtspRequest(); tearDownMessage.RequestTyped = RtspRequest.RequestType.TEARDOWN; tearDownMessage.RtspUri = destinationUri; RTSPDispatcher.Instance.Enqueue(tearDownMessage); } Stop(); }
private static String GetValidationDetails(RtspRequest request, RtspResponse response) { //rtsp request validation does not exist var sb = new StringBuilder(); if (null != response && response.Validated) { sb.AppendLine(String.Format("Second-level validation:")); sb.AppendLine(String.Format("\tResponse code of unit:{0}", response.GetStatusString())); } return(sb.ToString()); }
private async void HandleRequest(RtspRequest request) { RtspListener listener = null; if (_listeners.TryGetValue(request.RemoteEndpoint.ToString(), out listener)) { await Task.Run(() => { try { int receivedCseq = request.CSeq; request.Context = new RequestContext(listener); var response = _dispatcher.Dispatch(request); if (response != null) { if (response.HasBody) { response.Headers[RtspHeaders.Names.CONTENT_LENGTH] = response.Body.Length.ToString(); } response.Headers[RtspHeaders.Names.CSEQ] = receivedCseq.ToString(); listener.SendResponse(response); // Remove listener on teardown. // VLC will terminate the connection and the listener will stop itself properly. // Some clients will send Teardown but keep the connection open, in this type scenario we'll close it. if (request.Method == RtspRequest.RtspMethod.TEARDOWN) { listener.Stop(); _listeners.Remove(listener.Endpoint.ToString()); } } } catch (Exception e) { LOG.Error(e, $"Caught exception while procesing RTSP request from {request.URI}"); listener.SendResponse(RtspResponse.CreateBuilder() .Status(RtspResponse.Status.InternalServerError) .Build()); } }); } else { LOG.Error($"Unable to process request because no active connection was found for {request.URI}"); } }
private RtspListener HandleRequestPull(ref RtspMessage message) { Contract.Requires(message != null); Contract.Requires(message is RtspRequest); Contract.Ensures(Contract.Result <RtspListener>() != null); Contract.Ensures(Contract.ValueAtReturn(out message) != null); RtspListener destination; destination = message.SourcePort; RtspRequest request = message as RtspRequest; RtspResponse theDirectResponse; switch (request.RequestTyped) { case RtspRequest.RequestType.OPTIONS: theDirectResponse = pushManager.HandleOptions(message as RtspRequestOptions); break; case RtspRequest.RequestType.DESCRIBE: theDirectResponse = pushManager.HandlePullDescribe(message as RtspRequestDescribe); break; case RtspRequest.RequestType.SETUP: theDirectResponse = pushManager.HandlePullSetup(message as RtspRequestSetup); break; case RtspRequest.RequestType.PLAY: theDirectResponse = pushManager.HandlePullPlay(message as RtspRequestPlay); break; case RtspRequest.RequestType.GET_PARAMETER: theDirectResponse = pushManager.HandlePullGetParameter(message as RtspRequestGetParameter); break; default: _logger.Warn("Do not know how to handle : {0}", message.Command); theDirectResponse = request.CreateResponse(); theDirectResponse.ReturnCode = 400; break; } message = theDirectResponse; return(destination); }
private RtspListener HandleRequestPush(ref RtspMessage message) { Contract.Requires(message != null); Contract.Requires(message is RtspRequest); Contract.Ensures(Contract.Result <RtspListener>() != null); Contract.Ensures(Contract.ValueAtReturn(out message) != null); RtspListener destination; destination = message.SourcePort; RtspRequest request = message as RtspRequest; RtspResponse theDirectResponse; switch (request.RequestTyped) { case RtspRequest.RequestType.OPTIONS: theDirectResponse = pushManager.HandleOptions(message as RtspRequestOptions); break; case RtspRequest.RequestType.ANNOUNCE: theDirectResponse = pushManager.HandleAnnounce(message as RtspRequestAnnounce); break; case RtspRequest.RequestType.SETUP: theDirectResponse = pushManager.HandleSetup(message as RtspRequestSetup); break; case RtspRequest.RequestType.RECORD: theDirectResponse = pushManager.HandleRecord(message as RtspRequestRecord); break; case RtspRequest.RequestType.TEARDOWN: theDirectResponse = pushManager.HandleTeardown(message as RtspRequestTeardown); break; default: _logger.Warn("Do not know how to handle : {0}", message.Command); theDirectResponse = request.CreateResponse(); theDirectResponse.ReturnCode = 400; break; } message = theDirectResponse; return(destination); }
private void PostRequest(RtspRequest request) { try { if (!_rtspChannel.Writer.TryWrite(request)) { Logger.Warn($"Posting {request} failed"); } } catch (ChannelClosedException) { } catch (Exception e) { Logger.Error(e); } }
public override RtspResponse Play(RtspRequest request) { var builder = RtspResponse.CreateBuilder().Status(RtspResponse.Status.SessionNotFound); if (request.Headers.ContainsKey(RtspHeaders.Names.SESSION)) { var session = request.Headers[RtspHeaders.Names.SESSION]; if (_sessionMgr.PlaySession(session)) { builder.Status(RtspResponse.Status.Ok); } } return(builder.Build()); }
private bool GetRedirectUri(RtspClient client, MediaTrack track, out Uri uri) { var transport = TransportHeader.CreateBuilder() .Type(TransportType.RtspInterleaved) .InterleavedChannels(0, 1) .Build(); var method = RtspRequest.RtspMethod.SETUP; var res = CheckResponse(client.Send(RtspRequest.CreateBuilder() .Method(method) .Uri(track.ControlUri) .AddHeader(RtspHeaders.Names.TRANSPORT, transport.ToString()) .Build()), method); if (!res.Headers.ContainsKey(RtspHeaders.Names.SESSION)) { uri = null; return(false); } var rtspSession = Session.Parse(res.Headers[RtspHeaders.Names.SESSION]); method = RtspRequest.RtspMethod.PLAY; res = CheckResponse(client.Send(RtspRequest.CreateBuilder() .Method(method) .Uri(track.ControlUri) .AddHeader(RtspHeaders.Names.SESSION, rtspSession.ID) .Build()), method); var status = res.ResponseStatus; if (status.Is(RtspResponse.Status.MovedPermanently) || status.Is(RtspResponse.Status.MovedTemporarily)) { // We received a redirect lets get the uri and return it. if (res.Headers.ContainsKey(RtspHeaders.Names.LOCATION)) { var value = res.Headers[RtspHeaders.Names.LOCATION]; return(Uri.TryCreate(value, UriKind.RelativeOrAbsolute, out uri)); } } uri = null; return(false); }
public void ReceiveOptionsMessage() { string message = string.Empty; message += "OPTIONS * RTSP/1.0\n"; message += "CSeq: 1\n"; message += "Require: implicit-play\n"; message += "Proxy-Require: gzipped-messages\n"; message += "\n"; MemoryStream stream = new MemoryStream(ASCIIEncoding.UTF8.GetBytes(message)); _mockTransport.GetStream().Returns(stream); // Setup test object. RtspListener testedListener = new RtspListener(_mockTransport); testedListener.MessageReceived += new EventHandler <RtspChunkEventArgs>(MessageReceived); testedListener.DataReceived += new EventHandler <RtspChunkEventArgs>(DataReceived); // Run testedListener.Start(); System.Threading.Thread.Sleep(100); testedListener.Stop(); // Check the transport was closed. _mockTransport.Received().Close(); //Check the message recevied Assert.AreEqual(1, _receivedMessage.Count); RtspChunk theMessage = _receivedMessage[0]; Assert.IsInstanceOf <RtspRequest>(theMessage); Assert.AreEqual(0, theMessage.Data.Length); Assert.AreSame(testedListener, theMessage.SourcePort); RtspRequest theRequest = theMessage as RtspRequest; Assert.AreEqual(RtspRequest.RequestType.OPTIONS, theRequest.RequestTyped); Assert.AreEqual(3, theRequest.Headers.Count); Assert.AreEqual(1, theRequest.CSeq); Assert.Contains("Require", theRequest.Headers.Keys); Assert.Contains("Proxy-Require", theRequest.Headers.Keys); Assert.AreEqual(null, theRequest.RtspUri); Assert.AreEqual(0, _receivedData.Count); }
private void Pause(RtpSession session) { lock (SourceLock) { if (_state == PlayingState.PLAYING) { LOG.Debug($"Sending pause to session '{session.ID}' at {session.Track.ControlUri}"); CheckResponse(_client.Send(RtspRequest.CreateBuilder() .Uri(_currentUri) .Method(RtspRequest.RtspMethod.PAUSE) .AddHeader(RtspHeaders.Names.SESSION, session.ID) .Build()), RtspRequest.RtspMethod.PAUSE); session.Pause(); } } }
public void TestTeardownCall() { var request = RtspRequest.CreateBuilder() .Uri(_fixture.ServerUriEndpoint) .Method(RtspRequest.RtspMethod.TEARDOWN) .Build(); var response = _fixture.Client.Send(request); Assert.True(response.ResponseStatus.Is(RtspResponse.Status.Ok)); Assert.Equal(_fixture.NextCseq().ToString(), response.Headers[RtspHeaders.Names.CSEQ]); Assert.Equal("TEARDOWN", response.Headers[TestRequestHandler.CALLED_METHOD_HEADER]); response = _fixture.Client.Request().TearDown(); Assert.True(response.ResponseStatus.Is(RtspResponse.Status.Ok)); Assert.Equal(_fixture.NextCseq().ToString(), response.Headers[RtspHeaders.Names.CSEQ]); Assert.Equal("TEARDOWN", response.Headers[TestRequestHandler.CALLED_METHOD_HEADER]); }
public override RtspResponse Describe(RtspRequest request) { var queryParams = HttpUtility.ParseQueryString(request.URI.Query); var sourceId = queryParams["sourceId"]; var builder = RtspResponse.CreateBuilder().Status(RtspResponse.Status.Ok); if (sourceId == null && !_sourceMgr.ContainsSource(sourceId)) { builder.Status(RtspResponse.Status.NotFound); } else { builder.Body(CreateSdp(request.URI)); } return(builder.Build()); }
private AsyncResponse DoSend(RtspRequest request, RtspResponseCallback resCallback = null) { int cseq = GetNextCSeq(); request.CSeq = _cseq; AsyncResponse callback = new AsyncResponse(cseq, resCallback); if (!_connection.WriteMessage(request)) { callback.Dispose(); throw new RtspClientException("Unable to send request to client"); } _callbacks[cseq] = callback; return(callback); }
public void TestSetupCall() { var request = RtspRequest.CreateBuilder() .Uri(_fixture.ServerUriEndpoint) .Method(RtspRequest.RtspMethod.SETUP) .Build(); var response = _fixture.Client.Send(request); Assert.True(response.ResponseStatus.Is(RtspResponse.Status.Ok)); Assert.Equal(_fixture.NextCseq().ToString(), response.Headers[RtspHeaders.Names.CSEQ]); Assert.Equal("SETUP", response.Headers[TestRequestHandler.CALLED_METHOD_HEADER]); // Test IRtspInvoker method. response = _fixture.Client.Request().SetUp(); Assert.True(response.ResponseStatus.Is(RtspResponse.Status.Ok)); Assert.Equal(_fixture.NextCseq().ToString(), response.Headers[RtspHeaders.Names.CSEQ]); Assert.Equal("SETUP", response.Headers[TestRequestHandler.CALLED_METHOD_HEADER]); }
public void TestOptionsCall() { var request = RtspRequest.CreateBuilder() .Uri(_fixture.ServerUriEndpoint) .Method(RtspRequest.RtspMethod.OPTIONS) .Build(); var response = _fixture.Client.Send(request); Assert.True(response.ResponseStatus.Is(RtspResponse.Status.Ok)); Assert.Equal(_fixture.NextCseq().ToString(), response.Headers[RtspHeaders.Names.CSEQ]); Assert.Equal("OPTIONS, DESCRIBE, GET_PARAMETER, SETUP, PLAY, TEARDOWN", response.Headers[RtspHeaders.Names.PUBLIC]); // Test IRtspInvoker method response = _fixture.Client.Request().Options(); Assert.True(response.ResponseStatus.Is(RtspResponse.Status.Ok)); Assert.Equal(_fixture.NextCseq().ToString(), response.Headers[RtspHeaders.Names.CSEQ]); Assert.Equal("OPTIONS, DESCRIBE, GET_PARAMETER, SETUP, PLAY, TEARDOWN", response.Headers[RtspHeaders.Names.PUBLIC]); }