/// <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();
                        }
                    }
                }));
            }
        }