Example #1
0
        private void Handle2xx(SIP_Dialog dialog, SIP_ServerTransaction transaction)
        {
            if (dialog == null)
            {
                throw new ArgumentNullException("dialog");
            }
            if (transaction == null)
            {
                throw new ArgumentException("transaction");
            }

            /* RFC 6026 8.1.
                Once the response has been constructed, it is passed to the INVITE
                server transaction.  In order to ensure reliable end-to-end
                transport of the response, 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.
             
                If the server retransmits the 2xx response for 64*T1 seconds without
                receiving an ACK, the dialog is confirmed, but the session SHOULD be
                terminated.  This is accomplished with a BYE, as described in Section
                15.
              
                 T1 - 500
                 T2 - 4000
            */

            TimerEx timer = null;

            EventHandler<SIP_RequestReceivedEventArgs> callback = delegate(object s1, SIP_RequestReceivedEventArgs e)
            {
                try
                {
                    if (e.Request.RequestLine.Method == SIP_Methods.ACK)
                    {
                        // ACK for INVITE 2xx response received, stop retransmitting INVITE 2xx response.
                        if (transaction.Request.CSeq.SequenceNumber == e.Request.CSeq.SequenceNumber)
                        {
                            if (timer != null)
                            {
                                timer.Dispose();
                            }
                        }
                    }
                }
                catch
                {
                    // We don't care about errors here.
                }
            };
            dialog.RequestReceived += callback;

            // Create timer and sart retransmitting INVITE 2xx response.
            timer = new TimerEx(500);
            timer.AutoReset = false;
            timer.Elapsed += delegate(object s, System.Timers.ElapsedEventArgs e)
            {
                try
                {
                    lock (transaction.SyncRoot)
                    {
                        if (transaction.State == SIP_TransactionState.Accpeted)
                        {
                            transaction.SendResponse(transaction.FinalResponse);
                        }
                        else
                        {
                            timer.Dispose();

                            return;
                        }
                    }

                    timer.Interval = Math.Min(timer.Interval * 2, 4000);
                    timer.Enabled = true;
                }
                catch
                {
                    // We don't care about errors here.
                }
            };
            timer.Disposed += delegate(object s1, EventArgs e1)
            {
                try
                {
                    dialog.RequestReceived -= callback;
                }
                catch
                {
                    // We don't care about errors here.
                }
            };
            timer.Enabled = true;
        }