/// <summary> /// Raises event <b>Completed</b>. /// </summary> private void OnCompleted() { m_State = SIP_RequestSenderState.Completed; if (Completed != null) { Completed(this, new EventArgs()); } }
/// <summary> /// Cleans up any resources being used. /// </summary> public void Dispose() { lock(m_pLock){ if(m_State == SIP_RequestSenderState.Disposed){ return; } m_State = SIP_RequestSenderState.Disposed; OnDisposed(); this.ResponseReceived = null; this.Completed = null; this.Disposed = null; m_pStack = null; m_pRequest = null; m_pCredentials = null; m_pHops = null; m_pTransaction = null; m_pLock = null; } }
/// <summary> /// Cleans up any resources being used. /// </summary> public void Dispose() { lock (m_pLock){ if (m_State == SIP_RequestSenderState.Disposed) { return; } m_State = SIP_RequestSenderState.Disposed; OnDisposed(); this.ResponseReceived = null; this.Completed = null; this.Disposed = null; m_pStack = null; m_pRequest = null; m_pCredentials = null; m_pHops = null; m_pTransaction = null; m_pLock = null; } }
/// <summary> /// Starts sending request. /// </summary> /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this method is accessed.</exception> /// <exception cref="InvalidOperationException">Is raised when <b>Start</b> method has alredy called.</exception> /// <exception cref="SIP_TransportException">Is raised when no transport hop(s) for request.</exception> public void Start() { lock (m_pLock) { if (m_State == SIP_RequestSenderState.Disposed) { throw new ObjectDisposedException(GetType().Name); } if (m_IsStarted) { throw new InvalidOperationException("Start method has been already called."); } m_IsStarted = true; m_State = SIP_RequestSenderState.Starting; // Start may take so, process it on thread pool. ThreadPool.QueueUserWorkItem(delegate { lock (m_pLock) { if (m_State == SIP_RequestSenderState.Disposed) { return; } /* RFC 3261 8.1.2 Sending the Request * The destination for the request is then computed. Unless there is * local policy specifying otherwise, the destination MUST be determined * by applying the DNS procedures described in [4] as follows. If the * first element in the route set indicated a strict router (resulting * in forming the request as described in Section 12.2.1.1), the * procedures MUST be applied to the Request-URI of the request. * Otherwise, the procedures are applied to the first Route header field * value in the request (if one exists), or to the request's Request-URI * if there is no Route header field present. These procedures yield an * ordered set of address, port, and transports to attempt. Independent * of which URI is used as input to the procedures of [4], if the * Request-URI specifies a SIPS resource, the UAC MUST follow the * procedures of [4] as if the input URI were a SIPS URI. * * The UAC SHOULD follow the procedures defined in [4] for stateful * elements, trying each address until a server is contacted. Each try * constitutes a new transaction, and therefore each carries a different * topmost Via header field value with a new branch parameter. * Furthermore, the transport value in the Via header field is set to * whatever transport was determined for the target server. */ // We never use strict, only loose route. bool isStrictRoute = false; SIP_Uri uri = null; if (isStrictRoute) { uri = (SIP_Uri)m_pRequest.RequestLine.Uri; } else if (m_pRequest.Route.GetTopMostValue() != null) { uri = (SIP_Uri) m_pRequest.Route.GetTopMostValue().Address. Uri; } else { uri = (SIP_Uri)m_pRequest.RequestLine.Uri; } //uri.Param_Transport = "TCP"; // Queue hops. foreach (SIP_Hop hop in m_pStack.GetHops(uri, m_pRequest.ToByteData().Length, ((SIP_Uri) m_pRequest.RequestLine.Uri). IsSecure)) { m_pHops.Enqueue(hop); } if (m_pHops.Count == 0) { OnTransportError( new SIP_TransportException("No hops for '" + uri + "'.")); OnCompleted(); } else { m_State = SIP_RequestSenderState.Started; try { if (m_pFlow != null) { SendToFlow(m_pFlow, m_pRequest.Copy()); return; } } catch { // Sending to specified flow failed, probably disposed, just try send to first hop. } SendToNextHop(); } } }); } }
/// <summary> /// Raises event <b>Completed</b>. /// </summary> private void OnCompleted() { m_State = SIP_RequestSenderState.Completed; if(this.Completed != null){ this.Completed(this,new EventArgs()); } }
/// <summary> /// Starts sending request. /// </summary> /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this method is accessed.</exception> /// <exception cref="InvalidOperationException">Is raised when <b>Start</b> method has alredy called.</exception> /// <exception cref="SIP_TransportException">Is raised when no transport hop(s) for request.</exception> public void Start() { lock(m_pLock){ if(m_State == SIP_RequestSenderState.Disposed){ throw new ObjectDisposedException(this.GetType().Name); } if(m_IsStarted){ throw new InvalidOperationException("Start method has been already called."); } m_IsStarted = true; m_State = SIP_RequestSenderState.Starting; // Start may take so, process it on thread pool. ThreadPool.QueueUserWorkItem(new WaitCallback(delegate(object state){ lock(m_pLock){ if(m_State == SIP_RequestSenderState.Disposed){ return; } /* RFC 3261 8.1.2 Sending the Request The destination for the request is then computed. Unless there is local policy specifying otherwise, the destination MUST be determined by applying the DNS procedures described in [4] as follows. If the first element in the route set indicated a strict router (resulting in forming the request as described in Section 12.2.1.1), the procedures MUST be applied to the Request-URI of the request. Otherwise, the procedures are applied to the first Route header field value in the request (if one exists), or to the request's Request-URI if there is no Route header field present. These procedures yield an ordered set of address, port, and transports to attempt. Independent of which URI is used as input to the procedures of [4], if the Request-URI specifies a SIPS resource, the UAC MUST follow the procedures of [4] as if the input URI were a SIPS URI. The UAC SHOULD follow the procedures defined in [4] for stateful elements, trying each address until a server is contacted. Each try constitutes a new transaction, and therefore each carries a different topmost Via header field value with a new branch parameter. Furthermore, the transport value in the Via header field is set to whatever transport was determined for the target server. */ // We never use strict, only loose route. bool isStrictRoute = false; SIP_Uri uri = null; if(isStrictRoute){ uri = (SIP_Uri)m_pRequest.RequestLine.Uri; } else if(m_pRequest.Route.GetTopMostValue() != null){ uri = (SIP_Uri)m_pRequest.Route.GetTopMostValue().Address.Uri; } else{ uri = (SIP_Uri)m_pRequest.RequestLine.Uri; } try{ // Queue hops. foreach(SIP_Hop hop in m_pStack.GetHops(uri,m_pRequest.ToByteData().Length,((SIP_Uri)m_pRequest.RequestLine.Uri).IsSecure)){ m_pHops.Enqueue(hop); } } catch(Exception x){ OnTransportError(new SIP_TransportException("SIP hops resolving failed '" + x.Message + "'.")); OnCompleted(); return; } if(m_pHops.Count == 0){ OnTransportError(new SIP_TransportException("No target hops resolved for '" + uri + "'.")); OnCompleted(); } else{ m_State = SIP_RequestSenderState.Started; try{ if(m_pFlow != null){ SendToFlow(m_pFlow,m_pRequest.Copy()); return; } } catch{ // Sending to specified flow failed, probably disposed, just try send to first hop. } SendToNextHop(); } } })); } }