/// <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();
                        dialog.Init(m_pStack, transaction, response);
                        dialog.StateChanged += delegate
                        {
                            if (dialog.State == SIP_DialogState.Terminated)
                            {
                                m_pDialogs.Remove(dialog.ID);
                            }
                        };
                        m_pDialogs.Add(dialog.ID, dialog);
                    }
                    else
                    {
                        throw new ArgumentException("Method '" + response.CSeq.RequestMethod +
                                                    "' has no dialog handler.");
                    }
                }

                return(dialog);
            }
        }
            /// <summary>
            /// Cleans up any resources being used.
            /// </summary>
            public void Dispose()
            {
                lock (m_pLock)
                {
                    if (m_IsDisposed)
                    {
                        return;
                    }
                    m_IsDisposed = true;

                    m_pDialog.m_pUacInvite2xxRetransmitWaits.Remove(this);

                    m_pDialog = null;
                    m_pInvite = null;
                    if (m_pTimer != null)
                    {
                        m_pTimer.Dispose();
                        m_pTimer = null;
                    }
                }
            }
            /// <summary>
            /// Default constructor.
            /// </summary>
            /// <param name="dialog">Owner INVITE dialog.</param>
            /// <param name="invite">INVITE request which 2xx retransmission to wait.</param>
            /// <exception cref="ArgumentNullException">Is raised when <b>dialog</b> or <b>invite</b> is null reference.</exception>
            public UacInvite2xxRetransmissionWaiter(SIP_Dialog_Invite dialog, SIP_Request invite)
            {
                if (dialog == null)
                {
                    throw new ArgumentNullException("dialog");
                }
                if (invite == null)
                {
                    throw new ArgumentNullException("invite");
                }

                m_pDialog = dialog;
                m_pInvite = invite;

                /* RFC 3261 13.2.2.4.
                    The UAC core considers the INVITE transaction completed 64*T1 seconds
                    after the reception of the first 2xx response.
                */
                m_pTimer = new TimerEx(64*SIP_TimerConstants.T1, false);
                m_pTimer.Elapsed += m_pTimer_Elapsed;
                m_pTimer.Enabled = true;
            }
            /// <summary>
            /// Default constructor.
            /// </summary>
            /// <param name="dialog">Owner INVITE dialog.</param>
            /// <param name="invite">INVITE request which 2xx retransmission to wait.</param>
            /// <exception cref="ArgumentNullException">Is raised when <b>dialog</b> or <b>invite</b> is null reference.</exception>
            public UacInvite2xxRetransmissionWaiter(SIP_Dialog_Invite dialog, SIP_Request invite)
            {
                if (dialog == null)
                {
                    throw new ArgumentNullException("dialog");
                }
                if (invite == null)
                {
                    throw new ArgumentNullException("invite");
                }

                m_pDialog = dialog;
                m_pInvite = invite;

                /* RFC 3261 13.2.2.4.
                 *  The UAC core considers the INVITE transaction completed 64*T1 seconds
                 *  after the reception of the first 2xx response.
                 */
                m_pTimer          = new TimerEx(64 * SIP_TimerConstants.T1, false);
                m_pTimer.Elapsed += m_pTimer_Elapsed;
                m_pTimer.Enabled  = true;
            }
            /// <summary>
            /// Default constructor.
            /// </summary>
            /// <param name="dialog">Owner INVITE dialog.</param>
            /// <param name="response">INVITE 2xx response.</param>
            /// <exception cref="ArgumentNullException">Is raised when <b>dialog</b> or <b>response</b> is null reference.</exception>
            public UasInvite2xxRetransmit(SIP_Dialog_Invite dialog, SIP_Response response)
            {
                if (dialog == null)
                {
                    throw new ArgumentNullException("dialog");
                }
                if (response == null)
                {
                    throw new ArgumentNullException("response");
                }

                m_pDialog   = dialog;
                m_pResponse = response;

                /* RFC 3261 13.3.1.4.
                 *  Once the response has been constructed, it is passed to the INVITE
                 *  server transaction.  Note, however, that the INVITE server
                 *  transaction will be destroyed as soon as it receives this final
                 *  response and passes it to the transport.  Therefore, it is necessary
                 *  to periodically pass the response directly to the transport until the
                 *  ACK arrives.  The 2xx response is passed to the transport with an
                 *  interval that starts at T1 seconds and doubles for each
                 *  retransmission until it reaches T2 seconds (T1 and T2 are defined in
                 *  Section 17).  Response retransmissions cease when an ACK request for
                 *  the response is received.  This is independent of whatever transport
                 *  protocols are used to send the response.
                 *
                 *      Since 2xx is retransmitted end-to-end, there may be hops between
                 *      UAS and UAC that are UDP.  To ensure reliable delivery across
                 *      these hops, the response is retransmitted periodically even if the
                 *      transport at the UAS is reliable.
                 */

                m_pTimer          = new TimerEx(SIP_TimerConstants.T1, false);
                m_pTimer.Elapsed += m_pTimer_Elapsed;
                m_pTimer.Enabled  = true;
            }
            /// <summary>
            /// Cleans up any resources being used.
            /// </summary>
            public void Dispose()
            {
                lock (m_pLock)
                {
                    if (m_IsDisposed)
                    {
                        return;
                    }
                    m_IsDisposed = true;

                    m_pDialog.m_pUacInvite2xxRetransmitWaits.Remove(this);

                    m_pDialog = null;
                    m_pInvite = null;
                    if (m_pTimer != null)
                    {
                        m_pTimer.Dispose();
                        m_pTimer = null;
                    }
                }
            }
            /// <summary>
            /// Default constructor.
            /// </summary>
            /// <param name="dialog">Owner INVITE dialog.</param>
            /// <param name="response">INVITE 2xx response.</param>
            /// <exception cref="ArgumentNullException">Is raised when <b>dialog</b> or <b>response</b> is null reference.</exception>
            public UasInvite2xxRetransmit(SIP_Dialog_Invite dialog, SIP_Response response)
            {
                if (dialog == null)
                {
                    throw new ArgumentNullException("dialog");
                }
                if (response == null)
                {
                    throw new ArgumentNullException("response");
                }

                m_pDialog = dialog;
                m_pResponse = response;

                /* RFC 3261 13.3.1.4.
                    Once the response has been constructed, it is passed to the INVITE
                    server transaction.  Note, however, that the INVITE server
                    transaction will be destroyed as soon as it receives this final
                    response and passes it to the transport.  Therefore, it is necessary
                    to periodically pass the response directly to the transport until the
                    ACK arrives.  The 2xx response is passed to the transport with an
                    interval that starts at T1 seconds and doubles for each
                    retransmission until it reaches T2 seconds (T1 and T2 are defined in
                    Section 17).  Response retransmissions cease when an ACK request for
                    the response is received.  This is independent of whatever transport
                    protocols are used to send the response.
                 
                        Since 2xx is retransmitted end-to-end, there may be hops between
                        UAS and UAC that are UDP.  To ensure reliable delivery across
                        these hops, the response is retransmitted periodically even if the
                        transport at the UAS is reliable.                    
                */

                m_pTimer = new TimerEx(SIP_TimerConstants.T1, false);
                m_pTimer.Elapsed += m_pTimer_Elapsed;
                m_pTimer.Enabled = true;
            }
        /// <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();
                        dialog.Init(m_pStack, transaction, response);
                        dialog.StateChanged += delegate
                                                   {
                                                       if (dialog.State == SIP_DialogState.Terminated)
                                                       {
                                                           m_pDialogs.Remove(dialog.ID);
                                                       }
                                                   };
                        m_pDialogs.Add(dialog.ID, dialog);
                    }
                    else
                    {
                        throw new ArgumentException("Method '" + response.CSeq.RequestMethod +
                                                    "' has no dialog handler.");
                    }
                }

                return dialog;
            }
        }