/// <summary>
        /// Matches specified SIP response to SIP dialog. If no matching dialog found, returns null.
        /// </summary>
        /// <param name="response">SIP response.</param>
        /// <returns>Returns matched SIP dialog or null in no match found.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>response</b> is null.</exception>
        internal SIP_Dialog MatchDialog(SIP_Response response)
        {
            if (response == null)
            {
                throw new ArgumentNullException("response");
            }

            SIP_Dialog dialog = null;

            try{
                string callID  = response.CallID;
                string fromTag = response.From.Tag;
                string toTag   = response.To.Tag;
                if (callID != null && fromTag != null && toTag != null)
                {
                    string dialogID = callID + "-" + fromTag + "-" + toTag;
                    lock (m_pDialogs){
                        m_pDialogs.TryGetValue(dialogID, out dialog);
                    }
                }
            }
            catch {
            }

            return(dialog);
        }
        /// <summary>
        /// Matches specified SIP request to SIP dialog. If no matching dialog found, returns null.
        /// </summary>
        /// <param name="request">SIP request.</param>
        /// <returns>Returns matched SIP dialog or null in no match found.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>request</b> is null.</exception>
        internal SIP_Dialog MatchDialog(SIP_Request request)
        {
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }

            SIP_Dialog dialog = null;

            try{
                string callID    = request.CallID;
                string localTag  = request.To.Tag;
                string remoteTag = request.From.Tag;
                if (callID != null && localTag != null && remoteTag != null)
                {
                    string dialogID = callID + "-" + localTag + "-" + remoteTag;
                    lock (m_pDialogs){
                        m_pDialogs.TryGetValue(dialogID, out dialog);
                    }
                }
            }
            catch {
            }

            return(dialog);
        }
        /// <summary>
        /// Gets existing or creates new dialog.
        /// </summary>
        /// <param name="transaction">Owner transaction what forces to create dialog.</param>
        /// <param name="response">Response what forces to create dialog.</param>
        /// <returns>Returns dialog.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>transaction</b> or <b>response</b> is null.</exception>
        public SIP_Dialog GetOrCreateDialog(SIP_Transaction transaction, SIP_Response response)
        {
            if (transaction == null)
            {
                throw new ArgumentNullException("transaction");
            }
            if (response == null)
            {
                throw new ArgumentNullException("response");
            }

            string dialogID = "";

            if (transaction is SIP_ServerTransaction)
            {
                dialogID = response.CallID + "-" + response.To.Tag + "-" + response.From.Tag;
            }
            else
            {
                dialogID = response.CallID + "-" + response.From.Tag + "-" + response.To.Tag;
            }

            lock (m_pDialogs){
                SIP_Dialog dialog = null;
                m_pDialogs.TryGetValue(dialogID, out dialog);
                // Dialog doesn't exist, create it.
                if (dialog == null)
                {
                    if (response.CSeq.RequestMethod.ToUpper() == SIP_Methods.INVITE)
                    {
                        dialog = new SIP_Dialog_Invite();
                    }
                    else if (response.CSeq.RequestMethod.ToUpper() == SIP_Methods.REFER)
                    {
                        dialog = new SIP_Dialog_Refer();
                    }
                    else
                    {
                        throw new ArgumentException("Method '" + response.CSeq.RequestMethod + "' has no dialog handler.");
                    }

                    dialog.Init(m_pStack, transaction, response);
                    dialog.StateChanged += delegate(object s, EventArgs a){
                        if (dialog.State == SIP_DialogState.Terminated)
                        {
                            m_pDialogs.Remove(dialog.ID);
                        }
                    };
                    m_pDialogs.Add(dialog.ID, dialog);
                }

                return(dialog);
            }
        }
        /// <summary>
        /// Creates new client transaction.
        /// </summary>
        /// <param name="flow">SIP data flow which is used to send request.</param>
        /// <param name="request">SIP request that transaction will handle.</param>
        /// <param name="addVia">If true, transaction will add <b>Via:</b> header, otherwise it's user responsibility.</param>
        /// <exception cref="ObjectDisposedException">Is raised when this class is Disposed and this method is accessed.</exception>
        /// <exception cref="ArgumentNullException">Is raised when <b>flow</b> or <b>request</b> is null reference.</exception>
        /// <returns>Returns created transaction.</returns>
        public SIP_ClientTransaction CreateClientTransaction(SIP_Flow flow, SIP_Request request, bool addVia)
        {
            if (m_IsDisposed)
            {
                throw new ObjectDisposedException(this.GetType().Name);
            }
            if (flow == null)
            {
                throw new ArgumentNullException("flow");
            }
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }

            // Add Via:
            if (addVia)
            {
                SIP_t_ViaParm via = new SIP_t_ViaParm();
                via.ProtocolName      = "SIP";
                via.ProtocolVersion   = "2.0";
                via.ProtocolTransport = flow.Transport;
                via.SentBy            = new HostEndPoint("transport_layer_will_replace_it", -1);
                via.Branch            = SIP_t_ViaParm.CreateBranch();
                via.RPort             = 0;
                request.Via.AddToTop(via.ToStringValue());
            }

            lock (m_pClientTransactions){
                SIP_ClientTransaction transaction = new SIP_ClientTransaction(m_pStack, flow, request);
                m_pClientTransactions.Add(transaction.Key, transaction);
                transaction.StateChanged += new EventHandler(delegate(object s, EventArgs e){
                    if (transaction.State == SIP_TransactionState.Terminated)
                    {
                        lock (m_pClientTransactions){
                            m_pClientTransactions.Remove(transaction.Key);
                        }
                    }
                });

                SIP_Dialog dialog = MatchDialog(request);
                if (dialog != null)
                {
                    dialog.AddTransaction(transaction);
                }

                return(transaction);
            }
        }
        /// <summary>
        /// Creates new SIP server transaction for specified request.
        /// </summary>
        /// <param name="flow">SIP data flow which is used to receive request.</param>
        /// <param name="request">SIP request.</param>
        /// <returns>Returns added server transaction.</returns>
        /// <exception cref="ObjectDisposedException">Is raised when this class is Disposed and this method is accessed.</exception>
        /// <exception cref="ArgumentNullException">Is raised when <b>flow</b> or <b>request</b> is null reference.</exception>
        public SIP_ServerTransaction CreateServerTransaction(SIP_Flow flow, SIP_Request request)
        {
            if (m_IsDisposed)
            {
                throw new ObjectDisposedException(this.GetType().Name);
            }
            if (flow == null)
            {
                throw new ArgumentNullException("flow");
            }
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }

            lock (m_pServerTransactions){
                SIP_ServerTransaction transaction = new SIP_ServerTransaction(m_pStack, flow, request);
                m_pServerTransactions.Add(transaction.Key, transaction);
                transaction.StateChanged += new EventHandler(delegate(object s, EventArgs e){
                    if (transaction.State == SIP_TransactionState.Terminated)
                    {
                        lock (m_pClientTransactions){
                            m_pServerTransactions.Remove(transaction.Key);
                        }
                    }
                });

                SIP_Dialog dialog = MatchDialog(request);
                if (dialog != null)
                {
                    dialog.AddTransaction(transaction);
                }

                return(transaction);
            }
        }
 /// <summary>
 /// Removes specified dialog from dialogs collection.
 /// </summary>
 /// <param name="dialog">SIP dialog to remove.</param>
 internal void RemoveDialog(SIP_Dialog dialog)
 {
     lock (m_pDialogs){
         m_pDialogs.Remove(dialog.ID);
     }
 }