コード例 #1
0
 /// <summary>
 /// Default constructor.
 /// </summary>
 /// <param name="stack">Reference to SIP stack.</param>
 /// <param name="transaction">Client transaction what response it is. This value can be null if no matching client response.</param>
 /// <param name="response">Received response.</param>
 internal SIP_ResponseReceivedEventArgs(SIP_Stack stack,
                                        SIP_ClientTransaction transaction,
                                        SIP_Response response)
 {
     m_pStack       = stack;
     m_pResponse    = response;
     m_pTransaction = transaction;
 }
コード例 #2
0
 /// <summary>
 /// Default constructor.
 /// </summary>
 /// <param name="stack">Reference to SIP stack.</param>
 /// <param name="transaction">Client transaction what response it is. This value can be null if no matching client response.</param>
 /// <param name="response">Received response.</param>
 internal SIP_ResponseReceivedEventArgs(SIP_Stack stack,
                                        SIP_ClientTransaction transaction,
                                        SIP_Response response)
 {
     m_pStack = stack;
     m_pResponse = response;
     m_pTransaction = transaction;
 }
コード例 #3
0
        /// <summary>
        /// Processes specified response through this dialog.
        /// </summary>
        /// <param name="response">SIP response to process.</param>
        /// <returns>Returns true if this dialog processed specified response, otherwise false.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>response</b> is null.</exception>
        protected internal virtual bool ProcessResponse(SIP_Response response)
        {
            if (response == null)
            {
                throw new ArgumentNullException("response");
            }

            return(false);
        }
コード例 #4
0
            /// <summary>
            /// Processes retransmited INVITE 2xx response.
            /// </summary>
            /// <param name="response">INVITE 2xx response.</param>
            /// <exception cref="ArgumentNullException">Is raised when <b>response</b> is null reference.</exception>
            public void Process(SIP_Response response)
            {
                if (response == null)
                {
                    throw new ArgumentNullException("response");
                }

                lock (m_pLock)
                {
                    SIP_Request ack = CreateAck();

                    try
                    {
                        // Try existing flow.
                        m_pDialog.Flow.Send(ack);

                        // Log
                        if (m_pDialog.Stack.Logger != null)
                        {
                            byte[] ackBytes = ack.ToByteData();

                            m_pDialog.Stack.Logger.AddWrite(m_pDialog.ID,
                                                            null,
                                                            ackBytes.Length,
                                                            "Dialog [id='" + m_pDialog.ID +
                                                            "] ACK sent for 2xx response.",
                                                            m_pDialog.Flow.LocalEP,
                                                            m_pDialog.Flow.RemoteEP,
                                                            ackBytes);
                        }
                    }
                    catch
                    {
                        /* RFC 3261 13.2.2.4.
                         *  Once the ACK has been constructed, the procedures of [4] are used to
                         *  determine the destination address, port and transport.  However, the
                         *  request is passed to the transport layer directly for transmission,
                         *  rather than a client transaction.
                         */
                        try
                        {
                            m_pDialog.Stack.TransportLayer.SendRequest(ack);
                        }
                        catch (Exception x)
                        {
                            // Log
                            if (m_pDialog.Stack.Logger != null)
                            {
                                m_pDialog.Stack.Logger.AddText("Dialog [id='" + m_pDialog.ID +
                                                               "'] ACK send for 2xx response failed: " +
                                                               x.Message + ".");
                            }
                        }
                    }
                }
            }
コード例 #5
0
        /// <summary>
        /// Parses SIP_Response from stream.
        /// </summary>
        /// <param name="stream">Stream what contains valid SIP response.</param>
        /// <returns>Returns parsed SIP_Response obeject.</returns>
        /// <exception cref="ArgumentNullException">Raised when <b>stream</b> is null.</exception>
        /// <exception cref="SIP_ParseException">Raised when invalid SIP message.</exception>
        public static SIP_Response Parse(Stream stream)
        {
            /* Syntax:
             *  SIP-Version SP Status-Code SP Reason-Phrase
             *  SIP-Message
             */

            if (stream == null)
            {
                throw new ArgumentNullException("stream");
            }

            SIP_Response retVal = new SIP_Response();

            // Parse Response-line
            StreamLineReader r = new StreamLineReader(stream);

            r.Encoding = "utf-8";
            string[] version_code_text = r.ReadLineString().Split(new[] { ' ' }, 3);
            if (version_code_text.Length != 3)
            {
                throw new SIP_ParseException(
                          "Invalid SIP Status-Line syntax ! Syntax: {SIP-Version SP Status-Code SP Reason-Phrase}.");
            }
            // SIP-Version
            try
            {
                retVal.SipVersion = Convert.ToDouble(version_code_text[0].Split('/')[1],
                                                     NumberFormatInfo.InvariantInfo);
            }
            catch
            {
                throw new SIP_ParseException("Invalid Status-Line SIP-Version value !");
            }

            // Status-Code
            try
            {
                retVal.StatusCode = Convert.ToInt32(version_code_text[1]);
            }
            catch
            {
                throw new SIP_ParseException("Invalid Status-Line Status-Code value !");
            }

            // Reason-Phrase
            retVal.ReasonPhrase = version_code_text[2];

            // Parse SIP-Message
            retVal.InternalParse(stream);

            return(retVal);
        }
コード例 #6
0
        /// <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);
            }
        }
コード例 #7
0
        /// <summary>
        /// Adds specified response to transaction responses collection.
        /// </summary>
        /// <param name="response">SIP response.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>response</b> is null reference.</exception>
        protected void AddResponse(SIP_Response response)
        {
            if (response == null)
            {
                throw new ArgumentNullException("response");
            }

            // Don't store more than 15 responses, otherwise hacker may try todo buffer overrun with provisional responses.
            if (m_pResponses.Count < 15 || response.StatusCode >= 200)
            {
                m_pResponses.Add(response);
            }
        }
コード例 #8
0
        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="transaction">Server transaction.</param>
        /// <param name="response">SIP response.</param>
        /// <exception cref="ArgumentNullException">Is raised when any of the arguments is null.</exception>
        public SIP_ResponseSentEventArgs(SIP_ServerTransaction transaction, SIP_Response response)
        {
            if (transaction == null)
            {
                throw new ArgumentNullException("transaction");
            }
            if (response == null)
            {
                throw new ArgumentNullException("response");
            }

            m_pTransaction = transaction;
            m_pResponse = response;
        }
コード例 #9
0
        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="transaction">Server transaction.</param>
        /// <param name="response">SIP response.</param>
        /// <exception cref="ArgumentNullException">Is raised when any of the arguments is null.</exception>
        public SIP_ResponseSentEventArgs(SIP_ServerTransaction transaction, SIP_Response response)
        {
            if (transaction == null)
            {
                throw new ArgumentNullException("transaction");
            }
            if (response == null)
            {
                throw new ArgumentNullException("response");
            }

            m_pTransaction = transaction;
            m_pResponse    = response;
        }
コード例 #10
0
        /// <summary>
        /// Sends specified response to flow remote end point.
        /// </summary>
        /// <param name="response">SIP response to send.</param>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this method is accessed.</exception>
        /// <exception cref="ArgumentNullException">Is raised when <b>response</b> is null reference.</exception>
        public void Send(SIP_Response response)
        {
            lock (m_pLock)
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }
                if (response == null)
                {
                    throw new ArgumentNullException("response");
                }

                SendInternal(response.ToByteData());
            }
        }
コード例 #11
0
            /// <summary>
            /// Checks if specified response matches this 2xx response retransmission wait entry.
            /// </summary>
            /// <param name="response">INVITE 2xx response.</param>
            /// <returns>Returns true if response matches, othwerwise false.</returns>
            /// <exception cref="ArgumentNullException">Is raised when <b>response</b> is null reference value.</exception>
            public bool Match(SIP_Response response)
            {
                if (response == null)
                {
                    throw new ArgumentNullException("response");
                }

                if (m_pInvite.CSeq.RequestMethod == response.CSeq.RequestMethod &&
                    m_pInvite.CSeq.SequenceNumber == response.CSeq.SequenceNumber)
                {
                    return(true);
                }
                else
                {
                    return(false);
                }
            }
コード例 #12
0
        /// <summary>
        /// Is raised when INVITE 100 (Trying) response must be sent if no response sent by transaction user.
        /// </summary>
        /// <param name="sender">Sender.</param>
        /// <param name="e">Event data.</param>
        private void m_pTimer100_Elapsed(object sender, ElapsedEventArgs e)
        {
            lock (SyncRoot)
            {
                // RFC 3261 17.2.1. TU didn't generate response in 200 ms, send '100 Trying' to stop request retransmission.
                if (State == SIP_TransactionState.Proceeding && Responses.Length == 0)
                {
                    /* RFC 3261 17.2.1.
                     *  The 100 (Trying) response is constructed according to the procedures in Section 8.2.6, except that the
                     *  insertion of tags in the To header field of the response (when none was present in the request)
                     *  is downgraded from MAY to SHOULD NOT.
                     *
                     * RFC 3261 8.2.6.
                     *  When a 100 (Trying) response is generated, any Timestamp header field present in the request MUST
                     *  be copied into this 100 (Trying) response. If there is a delay in generating the response, the UAS
                     *  SHOULD add a delay value into the Timestamp value in the response. This value MUST contain the difference
                     *  between the time of sending of the response and receipt of the request, measured in seconds.
                     */

                    SIP_Response tryingResponse = Stack.CreateResponse(SIP_ResponseCodes.x100_Trying, Request);
                    if (Request.Timestamp != null)
                    {
                        tryingResponse.Timestamp = new SIP_t_Timestamp(Request.Timestamp.Time,
                                                                       (DateTime.Now - CreateTime).Seconds);
                    }

                    try
                    {
                        Stack.TransportLayer.SendResponse(this, tryingResponse);
                    }
                    catch (Exception x)
                    {
                        OnTransportError(x);
                        SetState(SIP_TransactionState.Terminated);
                        return;
                    }
                }

                if (m_pTimer100 != null)
                {
                    m_pTimer100.Dispose();
                    m_pTimer100 = null;
                }
            }
        }
コード例 #13
0
            /// <summary>
            /// Cleans up any resources being used.
            /// </summary>
            public void Dispose()
            {
                lock (m_pLock)
                {
                    if (m_IsDisposed)
                    {
                        return;
                    }
                    m_IsDisposed = true;

                    m_pDialog.m_pUasInvite2xxRetransmits.Remove(this);

                    if (m_pTimer != null)
                    {
                        m_pTimer.Dispose();
                        m_pTimer = null;
                    }
                    m_pDialog   = null;
                    m_pResponse = null;
                }
            }
コード例 #14
0
        /// <summary>
        /// Processes specified response through this dialog.
        /// </summary>
        /// <param name="response">SIP response to process.</param>
        /// <returns>Returns true if this dialog processed specified response, otherwise false.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>response</b> is null.</exception>
        protected internal override bool ProcessResponse(SIP_Response response)
        {
            if (response == null)
            {
                throw new ArgumentNullException("response");
            }

            if (response.StatusCodeType == SIP_StatusCodeType.Success)
            {
                // Search pending INVITE 2xx response retransmission waite entry.
                foreach (UacInvite2xxRetransmissionWaiter w in m_pUacInvite2xxRetransmitWaits)
                {
                    if (w.Match(response))
                    {
                        w.Process(response);

                        return(true);
                    }
                }
            }

            return(false);
        }
コード例 #15
0
            /// <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;
            }
コード例 #16
0
        /// <summary>
        /// Cancels current transaction processing and sends '487 Request Terminated'.
        /// </summary>
        /// <exception cref="ObjectDisposedException">Is raised when this class is Disposed and this method is accessed.</exception>
        /// <exception cref="InvalidOperationException">Is raised when final response is sent and Cancel method is called after it.</exception>
        public override void Cancel()
        {
            lock (SyncRoot)
            {
                if (State == SIP_TransactionState.Disposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }
                if (FinalResponse != null)
                {
                    throw new InvalidOperationException("Final response is already sent, CANCEL not allowed.");
                }

                try
                {
                    SIP_Response response = Stack.CreateResponse(SIP_ResponseCodes.x487_Request_Terminated,
                                                                 Request);
                    Stack.TransportLayer.SendResponse(this, response);

                    OnCanceled();
                }
                catch (SIP_TransportException x)
                {
                    // Log
                    if (Stack.Logger != null)
                    {
                        Stack.Logger.AddText(ID,
                                             "Transaction [branch='" + ID + "';method='" + Method +
                                             "';IsServer=true] transport exception: " + x.Message);
                    }

                    OnTransportError(x);
                    SetState(SIP_TransactionState.Terminated);
                }
            }
        }
コード例 #17
0
        /// <summary>
        /// Sends specified response to remote party.
        /// </summary>
        /// <param name="response">SIP response to send.</param>
        /// <exception cref="ObjectDisposedException">Is raised when this class is Disposed and this method is accessed.</exception>
        /// <exception cref="ArgumentNullException">Is raised when <b>response</b> is null reference.</exception>
        public void SendResponse(SIP_Response response)
        {
            lock (SyncRoot)
            {
                if (State == SIP_TransactionState.Disposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }
                if (response == null)
                {
                    throw new ArgumentNullException("response");
                }

                try
                {
                    #region INVITE

                    /* RFC 3261 17.2.1.
                     |INVITE
                     |pass INV to TU
                     *  INVITE             V send 100 if TU won't in 200ms
                     *  send response+-----------+
                     +--------|           |--------+101-199 from TU
                     |        | Proceeding|        |send response
                     +------->|           |<-------+
                     |           |          Transport Err.
                     |           |          Inform TU
                     |           |--------------->+
                     +-----------+                |
                     |  300-699 from TU |     |2xx from TU        |
                     |  send response   |     |send response      |
                     |     +------------------>+
                     |                         |
                     |  INVITE          V          Timer G fires  |
                     |  send response+-----------+ send response  |
                     +--------|           |--------+       |
                     |        | Completed |        |       |
                     +------->|           |<-------+       |
                     +-----------+                |
                     |     |                   |
                     |              ACK |     |                   |
                     |              -   |     +------------------>+
                     |        Timer H fires    |
                     |                  V        or Transport Err.|
                     +-----------+  Inform TU     |
                     |           |                |
                     | Confirmed |                |
                     |           |                |
                     +-----------+                |
                     |                      |
                     |Timer I fires         |
                     |-                     |
                     |                      |
                     |                     V                      |
                     +-----------+                |
                     |           |                |
                     | Terminated|<---------------+
                     |           |
                     +-----------+
                     */

                    if (Method == SIP_Methods.INVITE)
                    {
                        #region Proceeding

                        if (State == SIP_TransactionState.Proceeding)
                        {
                            AddResponse(response);

                            // 1xx
                            if (response.StatusCodeType == SIP_StatusCodeType.Provisional)
                            {
                                Stack.TransportLayer.SendResponse(this, response);
                                OnResponseSent(response);
                            }
                            // 2xx
                            else if (response.StatusCodeType == SIP_StatusCodeType.Success)
                            {
                                Stack.TransportLayer.SendResponse(this, response);
                                OnResponseSent(response);
                                SetState(SIP_TransactionState.Terminated);
                            }
                            // 3xx - 6xx
                            else
                            {
                                Stack.TransportLayer.SendResponse(this, response);
                                OnResponseSent(response);
                                SetState(SIP_TransactionState.Completed);

                                /* RFC 3261 17.2.1.
                                 *  For unreliable transports, timer G is set to fire in T1 seconds, and is not set to fire for reliable transports.
                                 */
                                if (!Flow.IsReliable)
                                {
                                    m_pTimerG          = new TimerEx(SIP_TimerConstants.T1, false);
                                    m_pTimerG.Elapsed += m_pTimerG_Elapsed;
                                    m_pTimerG.Enabled  = true;

                                    // Log
                                    if (Stack.Logger != null)
                                    {
                                        Stack.Logger.AddText(ID,
                                                             "Transaction [branch='" + ID + "';method='" +
                                                             Method +
                                                             "';IsServer=true] timer G(INVITE response(3xx - 6xx) retransmission) started, will triger after " +
                                                             m_pTimerG.Interval + ".");
                                    }
                                }

                                /* RFC 3261 17.2.1.
                                 *  When the "Completed" state is entered, timer H MUST be set to fire in 64*T1 seconds for all transports.
                                 */
                                m_pTimerH          = new TimerEx(64 * SIP_TimerConstants.T1);
                                m_pTimerH.Elapsed += m_pTimerH_Elapsed;
                                m_pTimerH.Enabled  = true;

                                // Log
                                if (Stack.Logger != null)
                                {
                                    Stack.Logger.AddText(ID,
                                                         "Transaction [branch='" + ID + "';method='" + Method +
                                                         "';IsServer=true] timer H(INVITE ACK wait) started, will triger after " +
                                                         m_pTimerH.Interval + ".");
                                }
                            }
                        }

                        #endregion

                        #region Completed

                        else if (State == SIP_TransactionState.Completed)
                        {
                            // We do nothing here, we just wait ACK to arrive.
                        }

                        #endregion

                        #region Confirmed

                        else if (State == SIP_TransactionState.Confirmed)
                        {
                            // We do nothing, just wait ACK retransmissions.
                        }

                        #endregion

                        #region Terminated

                        else if (State == SIP_TransactionState.Terminated)
                        {
                            // We should never rreach here, but if so, skip it.
                        }

                        #endregion
                    }

                    #endregion

                    #region Non-INVITE

                    /* RFC 3261 17.2.2.
                     |Request received
                     |pass to TU
                     *                    V
                     +-----------+
                     |           |
                     | Trying    |-------------+
                     |           |             |
                     +-----------+             |200-699 from TU
                     |                   |send response
                     |1xx from TU        |
                     |send response      |
                     |                   |
                     | Request            V      1xx from TU  |
                     | send response+-----------+send response|
                     +--------|           |--------+    |
                     |        | Proceeding|        |    |
                     +------->|           |<-------+    |
                     +<--------------|           |             |
                     |Trnsprt Err    +-----------+             |
                     |Inform TU            |                   |
                     |                     |                   |
                     |                     |200-699 from TU    |
                     |                     |send response      |
                     |  Request            V                   |
                     |  send response+-----------+             |
                     |      +--------|           |             |
                     |      |        | Completed |<------------+
                     |      +------->|           |
                     +<--------------|           |
                     |Trnsprt Err    +-----------+
                     |Inform TU            |
                     |                     |Timer J fires
                     |                     |-
                     |                     |
                     |                     V
                     |               +-----------+
                     |               |           |
                     +-------------->| Terminated|
                     |           |
                     +-----------+
                     */

                    else
                    {
                        #region Trying

                        if (State == SIP_TransactionState.Trying)
                        {
                            AddResponse(response);

                            // 1xx
                            if (response.StatusCodeType == SIP_StatusCodeType.Provisional)
                            {
                                Stack.TransportLayer.SendResponse(this, response);
                                OnResponseSent(response);
                                SetState(SIP_TransactionState.Proceeding);
                            }
                            // 2xx - 6xx
                            else
                            {
                                Stack.TransportLayer.SendResponse(this, response);
                                OnResponseSent(response);
                                SetState(SIP_TransactionState.Completed);

                                /* RFC 3261 17.2.2.
                                 *  When the server transaction enters the "Completed" state, it MUST set
                                 *  Timer J to fire in 64*T1 seconds for unreliable transports, and zero
                                 *  seconds for reliable transports.
                                 */
                                m_pTimerJ          = new TimerEx(64 * SIP_TimerConstants.T1, false);
                                m_pTimerJ.Elapsed += m_pTimerJ_Elapsed;
                                m_pTimerJ.Enabled  = true;

                                // Log
                                if (Stack.Logger != null)
                                {
                                    Stack.Logger.AddText(ID,
                                                         "Transaction [branch='" + ID + "';method='" + Method +
                                                         "';IsServer=true] timer J(Non-INVITE request retransmission wait) started, will triger after " +
                                                         m_pTimerJ.Interval + ".");
                                }
                            }
                        }

                        #endregion

                        #region Proceeding

                        else if (State == SIP_TransactionState.Proceeding)
                        {
                            AddResponse(response);

                            // 1xx
                            if (response.StatusCodeType == SIP_StatusCodeType.Provisional)
                            {
                                Stack.TransportLayer.SendResponse(this, response);
                                OnResponseSent(response);
                            }
                            // 2xx - 6xx
                            else
                            {
                                Stack.TransportLayer.SendResponse(this, response);
                                OnResponseSent(response);
                                SetState(SIP_TransactionState.Completed);

                                /* RFC 3261 17.2.2.
                                 *  When the server transaction enters the "Completed" state, it MUST set
                                 *  Timer J to fire in 64*T1 seconds for unreliable transports, and zero
                                 *  seconds for reliable transports.
                                 */
                                m_pTimerJ          = new TimerEx(64 * SIP_TimerConstants.T1, false);
                                m_pTimerJ.Elapsed += m_pTimerJ_Elapsed;
                                m_pTimerJ.Enabled  = true;

                                // Log
                                if (Stack.Logger != null)
                                {
                                    Stack.Logger.AddText(ID,
                                                         "Transaction [branch='" + ID + "';method='" + Method +
                                                         "';IsServer=true] timer J(Non-INVITE request retransmission wait) started, will triger after " +
                                                         m_pTimerJ.Interval + ".");
                                }
                            }
                        }

                        #endregion

                        #region Completed

                        else if (State == SIP_TransactionState.Completed)
                        {
                            // Do nothing.
                        }

                        #endregion

                        #region Terminated

                        else if (State == SIP_TransactionState.Terminated)
                        {
                            // Do nothing.
                        }

                        #endregion
                    }

                    #endregion
                }
                catch (SIP_TransportException x)
                {
                    // Log
                    if (Stack.Logger != null)
                    {
                        Stack.Logger.AddText(ID,
                                             "Transaction [branch='" + ID + "';method='" + Method +
                                             "';IsServer=true] transport exception: " + x.Message);
                    }

                    OnTransportError(x);
                    SetState(SIP_TransactionState.Terminated);
                }
            }
        }
コード例 #18
0
        /// <summary>
        /// Sends specified response back to request maker using RFC 3263 5. rules.
        /// </summary>
        /// <param name="logID">Log ID.</param>
        /// <param name="transactionID">Transaction ID. If null, then stateless response sending.</param>
        /// <param name="localEP">UDP local end point to use for sending. If null, system will use default.</param>
        /// <param name="response">SIP response.</param>
        /// <exception cref="SIP_TransportException">Is raised when <b>response</b> sending has failed.</exception>
        private void SendResponse_RFC_3263_5(string logID,
                                             string transactionID,
                                             IPEndPoint localEP,
                                             SIP_Response response)
        {
            /* RFC 3263 5.
                    RFC 3261 [1] defines procedures for sending responses from a server
                    back to the client.  Typically, for unicast UDP requests, the
                    response is sent back to the source IP address where the request came
                    from, using the port contained in the Via header.  For reliable
                    transport protocols, the response is sent over the connection the
                    request arrived on.  However, it is important to provide failover
                    support when the client element fails between sending the request and
                    receiving the response.

                    A server, according to RFC 3261 [1], will send a response on the
                    connection it arrived on (in the case of reliable transport
                    protocols), and for unreliable transport protocols, to the source
                    address of the request, and the port in the Via header field.  The
                    procedures here are invoked when a server attempts to send to that
                    location and that response fails (the specific conditions are
                    detailed in RFC 3261). "Fails" is defined as any closure of the
                    transport connection the request came in on before the response can
                    be sent, or communication of a fatal error from the transport layer.

                    In these cases, the server examines the value of the sent-by
                    construction in the topmost Via header.  If it contains a numeric IP
                    address, the server attempts to send the response to that address,
                    using the transport protocol from the Via header, and the port from
                    sent-by, if present, else the default for that transport protocol.
                    The transport protocol in the Via header can indicate "TLS", which
                    refers to TLS over TCP.  When this value is present, the server MUST
                    use TLS over TCP to send the response.
                 
                    If, however, the sent-by field contained a domain name and a port
                    number, the server queries for A or AAAA records with that name.  It
                    tries to send the response to each element on the resulting list of
                    IP addresses, using the port from the Via, and the transport protocol
                    from the Via (again, a value of TLS refers to TLS over TCP).  As in
                    the client processing, the next entry in the list is tried if the one
                    before it results in a failure.

                    If, however, the sent-by field contained a domain name and no port,
                    the server queries for SRV records at that domain name using the
                    service identifier "_sips" if the Via transport is "TLS", "_sip"
                    otherwise, and the transport from the topmost Via header ("TLS"
                    implies that the transport protocol in the SRV query is TCP).  The
                    resulting list is sorted as described in [2], and the response is
                    sent to the topmost element on the new list described there.  If that
                    results in a failure, the next entry on the list is tried.
                */

            SIP_t_ViaParm via = response.Via.GetTopMostValue();

            #region Sent-By is IP address

            if (via.SentBy.IsIPAddress)
            {
                SendResponseToHost(logID,
                                   transactionID,
                                   localEP,
                                   via.SentBy.Host,
                                   via.SentByPortWithDefault,
                                   via.ProtocolTransport,
                                   response);
            }

                #endregion

                #region Sent-By is host name with port number

            else if (via.SentBy.Port != -1)
            {
                SendResponseToHost(logID,
                                   transactionID,
                                   localEP,
                                   via.SentBy.Host,
                                   via.SentByPortWithDefault,
                                   via.ProtocolTransport,
                                   response);
            }

                #endregion

                #region Sent-By is just host name

            else
            {
                try
                {
                    // Query SRV records.
                    string srvQuery = "";
                    if (via.ProtocolTransport == SIP_Transport.UDP)
                    {
                        srvQuery = "_sip._udp." + via.SentBy.Host;
                    }
                    else if (via.ProtocolTransport == SIP_Transport.TCP)
                    {
                        srvQuery = "_sip._tcp." + via.SentBy.Host;
                    }
                    else if (via.ProtocolTransport == SIP_Transport.UDP)
                    {
                        srvQuery = "_sips._tcp." + via.SentBy.Host;
                    }
                    DnsServerResponse dnsResponse = m_pStack.Dns.Query(srvQuery, QTYPE.SRV);
                    if (dnsResponse.ResponseCode != RCODE.NO_ERROR)
                    {
                        throw new SIP_TransportException("Dns error: " + dnsResponse.ResponseCode);
                    }
                    DNS_rr_SRV[] srvRecords = dnsResponse.GetSRVRecords();

                    // Use SRV records.
                    if (srvRecords.Length > 0)
                    {
                        for (int i = 0; i < srvRecords.Length; i++)
                        {
                            DNS_rr_SRV srv = srvRecords[i];
                            try
                            {
                                if (m_pStack.Logger != null)
                                {
                                    m_pStack.Logger.AddText(logID,
                                                            "Starts sending response to DNS SRV record '" +
                                                            srv.Target + "'.");
                                }

                                SendResponseToHost(logID,
                                                   transactionID,
                                                   localEP,
                                                   srv.Target,
                                                   srv.Port,
                                                   via.ProtocolTransport,
                                                   response);
                            }
                            catch
                            {
                                // Generate error, all SRV records has failed.
                                if (i == (srvRecords.Length - 1))
                                {
                                    if (m_pStack.Logger != null)
                                    {
                                        m_pStack.Logger.AddText(logID,
                                                                "Failed to send response to DNS SRV record '" +
                                                                srv.Target + "'.");
                                    }

                                    throw new SIP_TransportException("Host '" + via.SentBy.Host +
                                                                     "' is not accessible.");
                                }
                                    // For loop will try next SRV record.
                                else
                                {
                                    if (m_pStack.Logger != null)
                                    {
                                        m_pStack.Logger.AddText(logID,
                                                                "Failed to send response to DNS SRV record '" +
                                                                srv.Target + "', will try next.");
                                    }
                                }
                            }
                        }
                    }
                        // If no SRV, use A and AAAA records. (Thats not in 3263 5., but we need to todo it so.)
                    else
                    {
                        if (m_pStack.Logger != null)
                        {
                            m_pStack.Logger.AddText(logID,
                                                    "No DNS SRV records found, starts sending to Via: sent-by host '" +
                                                    via.SentBy.Host + "'.");
                        }

                        SendResponseToHost(logID,
                                           transactionID,
                                           localEP,
                                           via.SentBy.Host,
                                           via.SentByPortWithDefault,
                                           via.ProtocolTransport,
                                           response);
                    }
                }
                catch (DNS_ClientException dnsX)
                {
                    throw new SIP_TransportException("Dns error: " + dnsX.ErrorCode);
                }
            }

            #endregion
        }
コード例 #19
0
        /// <summary>
        /// Processes specified request through this dialog.
        /// </summary>
        /// <param name="e">Method arguments.</param>
        /// <returns>Returns true if this dialog processed specified request, otherwise false.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>e</b> is null reference.</exception>
        protected internal override bool ProcessRequest(SIP_RequestReceivedEventArgs e)
        {
            if (e == null)
            {
                throw new ArgumentNullException("e");
            }

            if (base.ProcessRequest(e))
            {
                return(true);
            }

            // We must support: INVITE(re-invite),UPDATE,ACK,  [BYE will be handled by base class]

            #region INVITE

            if (e.Request.RequestLine.Method == SIP_Methods.INVITE)
            {
                /* RFC 3261 14.2.
                 *  A UAS that receives a second INVITE before it sends the final
                 *  response to a first INVITE with a lower CSeq sequence number on the
                 *  same dialog MUST return a 500 (Server Internal Error) response to the
                 *  second INVITE and MUST include a Retry-After header field with a
                 *  randomly chosen value of between 0 and 10 seconds.
                 *
                 *  A UAS that receives an INVITE on a dialog while an INVITE it had sent
                 *  on that dialog is in progress MUST return a 491 (Request Pending)
                 *  response to the received INVITE.
                 */

                if (m_pActiveInvite != null && m_pActiveInvite is SIP_ServerTransaction &&
                    (m_pActiveInvite).Request.CSeq.SequenceNumber < e.Request.CSeq.SequenceNumber)
                {
                    SIP_Response response =
                        Stack.CreateResponse(
                            SIP_ResponseCodes.x500_Server_Internal_Error +
                            ": INVITE with a lower CSeq is pending(RFC 3261 14.2).",
                            e.Request);
                    response.RetryAfter = new SIP_t_RetryAfter("10");
                    e.ServerTransaction.SendResponse(response);

                    return(true);
                }
                if (m_pActiveInvite != null && m_pActiveInvite is SIP_ClientTransaction)
                {
                    e.ServerTransaction.SendResponse(
                        Stack.CreateResponse(SIP_ResponseCodes.x491_Request_Pending, e.Request));

                    return(true);
                }

                // Force server transaction creation and set it as active INVITE transaction.
                m_pActiveInvite = e.ServerTransaction;
                m_pActiveInvite.StateChanged += delegate
                {
                    if (m_pActiveInvite.State ==
                        SIP_TransactionState.Terminated)
                    {
                        m_pActiveInvite = null;
                    }
                };
                // Once we send 2xx response, we need to retransmit it while get ACK or timeout. (RFC 3261 13.3.1.4.)
                ((SIP_ServerTransaction)m_pActiveInvite).ResponseSent +=
                    delegate(object s, SIP_ResponseSentEventArgs a)
                {
                    if (a.Response.StatusCodeType == SIP_StatusCodeType.Success)
                    {
                        m_pUasInvite2xxRetransmits.Add(new UasInvite2xxRetransmit(this, a.Response));
                    }
                };

                OnReinvite(((SIP_ServerTransaction)m_pActiveInvite));

                return(true);
            }

            #endregion

            #region ACK

            else if (e.Request.RequestLine.Method == SIP_Methods.ACK)
            {
                // Search corresponding INVITE 2xx retransmit entry and dispose it.
                foreach (UasInvite2xxRetransmit t in m_pUasInvite2xxRetransmits)
                {
                    if (t.MatchAck(e.Request))
                    {
                        t.Dispose();
                        if (State == SIP_DialogState.Early)
                        {
                            SetState(SIP_DialogState.Confirmed, true);

                            // TODO: If Terminating
                        }

                        return(true);
                    }
                }

                return(false);
            }

            #endregion

            #region UPDATE

            //else if(request.RequestLine.Method == SIP_Methods.UPDATE){
            // TODO:
            //}

            #endregion

            // RFC 5057 5.6. Refusing New Usages. Decline(603 Decline) new dialog usages.
            else if (SIP_Utils.MethodCanEstablishDialog(e.Request.RequestLine.Method))
            {
                e.ServerTransaction.SendResponse(
                    Stack.CreateResponse(
                        SIP_ResponseCodes.x603_Decline + " : New dialog usages not allowed (RFC 5057).",
                        e.Request));

                return(true);
            }
            else
            {
                return(false);
            }
        }
コード例 #20
0
        /// <summary>
        /// Sends specified response back to request maker using RFC 3261 18. rules.
        /// </summary>
        /// <param name="transaction">SIP server transaction which response to send.</param>
        /// <param name="response">SIP response.</param>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this method is accessed.</exception>
        /// <exception cref="InvalidOperationException">Is raised when stack ahs not been started and this method is accessed.</exception>
        /// <exception cref="ArgumentNullException">Is raised when <b>transaction</b> or <b>response</b> is null reference.</exception>
        /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
        /// <exception cref="SIP_TransportException">Is raised when <b>response</b> sending has failed.</exception>
        internal void SendResponse(SIP_ServerTransaction transaction, SIP_Response response)
        {
            if (transaction == null)
            {
                throw new ArgumentNullException("transaction");
            }
            // NOTE: all other paramter / state validations are done in SendResponseInternal.

            SendResponseInternal(transaction, response, null);
        }
コード例 #21
0
ファイル: SIP_Dialog.cs プロジェクト: vipwan/CommunityServer
        /// <summary>
        /// Processes specified response through this dialog.
        /// </summary>
        /// <param name="response">SIP response to process.</param>
        /// <returns>Returns true if this dialog processed specified response, otherwise false.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>response</b> is null.</exception>
        protected internal virtual bool ProcessResponse(SIP_Response response)
        {
            if (response == null)
            {
                throw new ArgumentNullException("response");
            }

            return false;
        }
コード例 #22
0
        /// <summary>
        /// Sends response to the specified host.
        /// </summary>
        /// <param name="logID">Log ID.</param>
        /// <param name="transactionID">Transaction ID. If null, then stateless response sending.</param>
        /// <param name="localEP">UDP local end point to use for sending. If null, system will use default.</param>
        /// <param name="host">Host name or IP address where to send response.</param>
        /// <param name="port">Target host port.</param>
        /// <param name="transport">SIP transport to use.</param>
        /// <param name="response">SIP response to send.</param>
        private void SendResponseToHost(string logID,
                                        string transactionID,
                                        IPEndPoint localEP,
                                        string host,
                                        int port,
                                        string transport,
                                        SIP_Response response)
        {
            try
            {
                IPAddress[] targets = null;
                if (Net_Utils.IsIPAddress(host))
                {
                    targets = new[] {IPAddress.Parse(host)};
                }
                else
                {
                    targets = m_pStack.Dns.GetHostAddresses(host);
                    if (targets.Length == 0)
                    {
                        throw new SIP_TransportException("Invalid Via: Sent-By host name '" + host +
                                                         "' could not be resolved.");
                    }
                }

                byte[] responseData = response.ToByteData();

                for (int i = 0; i < targets.Length; i++)
                {
                    IPEndPoint remoteEP = new IPEndPoint(targets[i], port);
                    try
                    {
                        SIP_Flow flow = GetOrCreateFlow(transport, localEP, remoteEP);
                        flow.Send(response);
                        // localEP = flow.LocalEP;

                        if (m_pStack.Logger != null)
                        {
                            m_pStack.Logger.AddWrite(logID,
                                                     null,
                                                     0,
                                                     "Response [transactionID='" + transactionID +
                                                     "'; method='" + response.CSeq.RequestMethod + "'; cseq='" +
                                                     response.CSeq.SequenceNumber + "'; " + "transport='" +
                                                     transport + "'; size='" + responseData.Length +
                                                     "'; statusCode='" + response.StatusCode + "'; " +
                                                     "reason='" + response.ReasonPhrase + "'; sent '" +
                                                     localEP + "' -> '" + remoteEP + "'.",
                                                     localEP,
                                                     remoteEP,
                                                     responseData);
                        }

                        // If we reach so far, send succeeded.
                        return;
                    }
                    catch
                    {
                        // Generate error, all IP addresses has failed.
                        if (i == (targets.Length - 1))
                        {
                            if (m_pStack.Logger != null)
                            {
                                m_pStack.Logger.AddText(logID,
                                                        "Failed to send response to host '" + host +
                                                        "' IP end point '" + remoteEP + "'.");
                            }

                            throw new SIP_TransportException("Host '" + host + ":" + port +
                                                             "' is not accessible.");
                        }
                            // For loop will try next IP address.
                        else
                        {
                            if (m_pStack.Logger != null)
                            {
                                m_pStack.Logger.AddText(logID,
                                                        "Failed to send response to host '" + host +
                                                        "' IP end point '" + remoteEP +
                                                        "', will try next A record.");
                            }
                        }
                    }
                }
            }
            catch (DNS_ClientException dnsX)
            {
                throw new SIP_TransportException("Dns error: " + dnsX.ErrorCode);
            }
        }
コード例 #23
0
        /// <summary>
        /// Parses SIP_Response from stream.
        /// </summary>
        /// <param name="stream">Stream what contains valid SIP response.</param>
        /// <returns>Returns parsed SIP_Response obeject.</returns>
        /// <exception cref="ArgumentNullException">Raised when <b>stream</b> is null.</exception>
        /// <exception cref="SIP_ParseException">Raised when invalid SIP message.</exception>
        public static SIP_Response Parse(Stream stream)
        {
            /* Syntax:
                SIP-Version SP Status-Code SP Reason-Phrase
                SIP-Message                          
            */

            if (stream == null)
            {
                throw new ArgumentNullException("stream");
            }

            SIP_Response retVal = new SIP_Response();

            // Parse Response-line
            StreamLineReader r = new StreamLineReader(stream);
            r.Encoding = "utf-8";
            string[] version_code_text = r.ReadLineString().Split(new[] {' '}, 3);
            if (version_code_text.Length != 3)
            {
                throw new SIP_ParseException(
                    "Invalid SIP Status-Line syntax ! Syntax: {SIP-Version SP Status-Code SP Reason-Phrase}.");
            }
            // SIP-Version
            try
            {
                retVal.SipVersion = Convert.ToDouble(version_code_text[0].Split('/')[1],
                                                     NumberFormatInfo.InvariantInfo);
            }
            catch
            {
                throw new SIP_ParseException("Invalid Status-Line SIP-Version value !");
            }

            // Status-Code
            try
            {
                retVal.StatusCode = Convert.ToInt32(version_code_text[1]);
            }
            catch
            {
                throw new SIP_ParseException("Invalid Status-Line Status-Code value !");
            }

            // Reason-Phrase
            retVal.ReasonPhrase = version_code_text[2];

            // Parse SIP-Message
            retVal.InternalParse(stream);

            return retVal;
        }
コード例 #24
0
        /// <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;
        }
コード例 #25
0
        /// <summary>
        /// Clones this request.
        /// </summary>
        /// <returns>Returns new cloned request.</returns>
        public SIP_Response Copy()
        {
            SIP_Response retVal = Parse(ToByteData());

            return(retVal);
        }
コード例 #26
0
        /// <summary>
        /// Adds specified response to transaction responses collection.
        /// </summary>
        /// <param name="response">SIP response.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>response</b> is null reference.</exception>
        protected void AddResponse(SIP_Response response)
        {
            if (response == null)
            {
                throw new ArgumentNullException("response");
            }

            // Don't store more than 15 responses, otherwise hacker may try todo buffer overrun with provisional responses.
            if (m_pResponses.Count < 15 || response.StatusCode >= 200)
            {
                m_pResponses.Add(response);
            }
        }
コード例 #27
0
        /// <summary>
        /// Creates and sends ACK for final(3xx - 6xx) failure response.
        /// </summary>
        /// <param name="response">SIP response.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>response</b> is null.</exception>
        private void SendAck(SIP_Response response)
        {
            if (response == null)
            {
                throw new ArgumentNullException("resposne");
            }

            /* RFC 3261 17.1.1.3 Construction of the ACK Request.
                The ACK request constructed by the client transaction MUST contain
                values for the Call-ID, From, and Request-URI that are equal to the
                values of those header fields in the request passed to the transport
                by the client transaction (call this the "original request").  The To
                header field in the ACK MUST equal the To header field in the
                response being acknowledged, and therefore will usually differ from
                the To header field in the original request by the addition of the
                tag parameter.  The ACK MUST contain a single Via header field, and
                this MUST be equal to the top Via header field of the original
                request.  The CSeq header field in the ACK MUST contain the same
                value for the sequence number as was present in the original request,
                but the method parameter MUST be equal to "ACK".
              
                If the INVITE request whose response is being acknowledged had Route
                header fields, those header fields MUST appear in the ACK.  This is
                to ensure that the ACK can be routed properly through any downstream
                stateless proxies.
            */

            SIP_Request ackRequest = new SIP_Request(SIP_Methods.ACK);
            ackRequest.RequestLine.Uri = Request.RequestLine.Uri;
            ackRequest.Via.AddToTop(Request.Via.GetTopMostValue().ToStringValue());
            ackRequest.CallID = Request.CallID;
            ackRequest.From = Request.From;
            ackRequest.To = response.To;
            ackRequest.CSeq = new SIP_t_CSeq(Request.CSeq.SequenceNumber, "ACK");
            foreach (SIP_HeaderField h in response.Header.Get("Route:"))
            {
                ackRequest.Header.Add("Route:", h.Value);
            }
            ackRequest.MaxForwards = 70;

            try
            {
                // Send request to target.
                Stack.TransportLayer.SendRequest(Flow, ackRequest, this);
            }
            catch (SIP_TransportException x)
            {
                OnTransportError(x);
                SetState(SIP_TransactionState.Terminated);
            }
        }
コード例 #28
0
ファイル: SIP_Stack.cs プロジェクト: Inzaghi2012/teamlab.v7.5
        /// <summary>
        /// Creates response for the specified request.
        /// </summary>
        /// <param name="statusCode_reasonText">Status-code reasontext.</param>
        /// <param name="request">SIP request.</param>
        /// <param name="flow">Data flow what sends response. This value is used to construct Contact: header value. 
        /// This value can be null, but then adding Contact: header is response sender responsibility.</param>
        /// <returns>Returns created response.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>statusCode_reasonText</b> or <b>request</b> is null reference.</exception>
        /// <exception cref="InvalidOperationException">Is raised when request is ACK-request. ACK request is response less.</exception>
        public SIP_Response CreateResponse(string statusCode_reasonText, SIP_Request request, SIP_Flow flow)
        {
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }
            if (request.RequestLine.Method == SIP_Methods.ACK)
            {
                throw new InvalidOperationException("ACK is responseless request !");
            }

            /* RFC 3261 8.2.6.1.
                When a 100 (Trying) response is generated, any Timestamp header field
                present in the request MUST be copied into this 100 (Trying)
                response.
              
               RFC 3261 8.2.6.2.
                The From field of the response MUST equal the From header field of
                the request.  The Call-ID header field of the response MUST equal the
                Call-ID header field of the request.  The CSeq header field of the
                response MUST equal the CSeq field of the request.  The Via header
                field values in the response MUST equal the Via header field values
                in the request and MUST maintain the same ordering.

                If a request contained a To tag in the request, the To header field
                in the response MUST equal that of the request.  However, if the To
                header field in the request did not contain a tag, the URI in the To
                header field in the response MUST equal the URI in the To header
                field; additionally, the UAS MUST add a tag to the To header field in
                the response (with the exception of the 100 (Trying) response, in
                which a tag MAY be present).  This serves to identify the UAS that is
                responding, possibly resulting in a component of a dialog ID.  The
                same tag MUST be used for all responses to that request, both final
                and provisional (again excepting the 100 (Trying)).  Procedures for
                the generation of tags are defined in Section 19.3.
            
               RFC 3261 12.1.1.
                When a UAS responds to a request with a response that establishes a
                dialog (such as a 2xx to INVITE), the UAS MUST copy all Record-Route
                header field values from the request into the response (including the
                URIs, URI parameters, and any Record-Route header field parameters,
                whether they are known or unknown to the UAS) and MUST maintain the
                order of those values.            
            */

            SIP_Response response = new SIP_Response(request);
            response.StatusCode_ReasonPhrase = statusCode_reasonText;
            foreach (SIP_t_ViaParm via in request.Via.GetAllValues())
            {
                response.Via.Add(via.ToStringValue());
            }
            response.From = request.From;
            response.To = request.To;
            if (request.To.Tag == null)
            {
                response.To.Tag = SIP_Utils.CreateTag();
            }
            response.CallID = request.CallID;
            response.CSeq = request.CSeq;

            // TODO: Allow: / Supported:

            if (SIP_Utils.MethodCanEstablishDialog(request.RequestLine.Method))
            {
                foreach (SIP_t_AddressParam route in request.RecordRoute.GetAllValues())
                {
                    response.RecordRoute.Add(route.ToStringValue());
                }

                if (response.StatusCodeType == SIP_StatusCodeType.Success &&
                    response.Contact.GetTopMostValue() == null && flow != null)
                {
                    try
                    {
                        string user = ((SIP_Uri) response.To.Address.Uri).User;
                        response.Contact.Add((flow.IsSecure ? "sips:" : "sip:") + user + "@" +
                                             TransportLayer.Resolve(flow));
                    }
                    catch
                    {
                        // TODO: Log
                    }
                }
            }

            return response;
        }
コード例 #29
0
ファイル: SIP_Flow.cs プロジェクト: Inzaghi2012/teamlab.v7.5
        /// <summary>
        /// Sends specified response to flow remote end point.
        /// </summary>
        /// <param name="response">SIP response to send.</param>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and this method is accessed.</exception>
        /// <exception cref="ArgumentNullException">Is raised when <b>response</b> is null reference.</exception>
        public void Send(SIP_Response response)
        {
            lock (m_pLock)
            {
                if (m_IsDisposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }
                if (response == null)
                {
                    throw new ArgumentNullException("response");
                }

                SendInternal(response.ToByteData());
            }
        }
コード例 #30
0
        /// <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;
            }
        }
コード例 #31
0
 /// <summary>
 /// Raises ResponseReceived event.
 /// </summary>
 /// <param name="response">SIP response received.</param>
 private void OnResponseReceived(SIP_Response response)
 {
     if (ResponseReceived != null)
     {
         ResponseReceived(this, new SIP_ResponseReceivedEventArgs(m_pStack, m_pTransaction, response));
     }
 }
コード例 #32
0
        /// <summary>
        /// Matches SIP response to client transaction. If not matching transaction found, returns null.
        /// </summary>
        /// <param name="response">SIP response to match.</param>
        internal SIP_ClientTransaction MatchClientTransaction(SIP_Response response)
        {
            /* RFC 3261 17.1.3 Matching Responses to Client Transactions.
                1.  If the response has the same value of the branch parameter in
                    the top Via header field as the branch parameter in the top
                    Via header field of the request that created the transaction.

                2.  If the method parameter in the CSeq header field matches the
                    method of the request that created the transaction.  The
                    method is needed since a CANCEL request constitutes a
                    different transaction, but shares the same value of the branch
                    parameter.
            */

            SIP_ClientTransaction retVal = null;

            string transactionID = response.Via.GetTopMostValue().Branch + "-" + response.CSeq.RequestMethod;
            lock (m_pClientTransactions)
            {
                m_pClientTransactions.TryGetValue(transactionID, out retVal);
            }

            return retVal;
        }
コード例 #33
0
ファイル: SIP_Dialog.cs プロジェクト: vipwan/CommunityServer
        /// <summary>
        /// Initializes dialog.
        /// </summary>
        /// <param name="stack">Owner stack.</param>
        /// <param name="transaction">Owner transaction.</param>
        /// <param name="response">SIP response what caused dialog creation.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>stack</b>,<b>transaction</b> or <b>response</b>.</exception>
        protected internal virtual void Init(SIP_Stack stack,
                                             SIP_Transaction transaction,
                                             SIP_Response response)
        {
            if (stack == null)
            {
                throw new ArgumentNullException("stack");
            }
            if (transaction == null)
            {
                throw new ArgumentNullException("transaction");
            }
            if (response == null)
            {
                throw new ArgumentNullException("response");
            }

            m_pStack = stack;

            #region UAS

            /* RFC 3261 12.1.1.
                The UAS then constructs the state of the dialog.  This state MUST be
                maintained for the duration of the dialog.

                If the request arrived over TLS, and the Request-URI contained a SIPS
                URI, the "secure" flag is set to TRUE.

                The route set MUST be set to the list of URIs in the Record-Route
                header field from the request, taken in order and preserving all URI
                parameters.  If no Record-Route header field is present in the
                request, the route set MUST be set to the empty set.  This route set,
                even if empty, overrides any pre-existing route set for future
                requests in this dialog.  The remote target MUST be set to the URI
                from the Contact header field of the request.

                The remote sequence number MUST be set to the value of the sequence
                number in the CSeq header field of the request.  The local sequence
                number MUST be empty.  The call identifier component of the dialog ID
                MUST be set to the value of the Call-ID in the request.  The local
                tag component of the dialog ID MUST be set to the tag in the To field
                in the response to the request (which always includes a tag), and the
                remote tag component of the dialog ID MUST be set to the tag from the
                From field in the request.  A UAS MUST be prepared to receive a
                request without a tag in the From field, in which case the tag is
                considered to have a value of null.

                    This is to maintain backwards compatibility with RFC 2543, which
                    did not mandate From tags.

                The remote URI MUST be set to the URI in the From field, and the
                local URI MUST be set to the URI in the To field.
            */

            if (transaction is SIP_ServerTransaction)
            {
                // TODO: Validate request or client transaction must do it ?

                m_IsSecure = ((SIP_Uri) transaction.Request.RequestLine.Uri).IsSecure;
                m_pRouteSet =
                    (SIP_t_AddressParam[]) Core.ReverseArray(transaction.Request.RecordRoute.GetAllValues());
                m_pRemoteTarget = (SIP_Uri) transaction.Request.Contact.GetTopMostValue().Address.Uri;
                m_RemoteSeqNo = transaction.Request.CSeq.SequenceNumber;
                m_LocalSeqNo = 0;
                m_CallID = transaction.Request.CallID;
                m_LocalTag = response.To.Tag;
                m_RemoteTag = transaction.Request.From.Tag;
                m_pRemoteUri = transaction.Request.From.Address.Uri;
                m_pLocalUri = transaction.Request.To.Address.Uri;
                m_pLocalContact = (SIP_Uri) response.Contact.GetTopMostValue().Address.Uri;
            }

                #endregion

                #region UAC

                /* RFC 3261 12.1.2.
                When a UAC receives a response that establishes a dialog, it
                constructs the state of the dialog.  This state MUST be maintained
                for the duration of the dialog.

                If the request was sent over TLS, and the Request-URI contained a
                SIPS URI, the "secure" flag is set to TRUE.

                The route set MUST be set to the list of URIs in the Record-Route
                header field from the response, taken in reverse order and preserving
                all URI parameters.  If no Record-Route header field is present in
                the response, the route set MUST be set to the empty set.  This route
                set, even if empty, overrides any pre-existing route set for future
                requests in this dialog.  The remote target MUST be set to the URI
                from the Contact header field of the response.

                The local sequence number MUST be set to the value of the sequence
                number in the CSeq header field of the request.  The remote sequence
                number MUST be empty (it is established when the remote UA sends a
                request within the dialog).  The call identifier component of the
                dialog ID MUST be set to the value of the Call-ID in the request.
                The local tag component of the dialog ID MUST be set to the tag in
                the From field in the request, and the remote tag component of the
                dialog ID MUST be set to the tag in the To field of the response.  A
                UAC MUST be prepared to receive a response without a tag in the To
                field, in which case the tag is considered to have a value of null.

                    This is to maintain backwards compatibility with RFC 2543, which
                    did not mandate To tags.

                The remote URI MUST be set to the URI in the To field, and the local
                URI MUST be set to the URI in the From field.
            */

            else
            {
                // TODO: Validate request or client transaction must do it ?

                m_IsSecure = ((SIP_Uri) transaction.Request.RequestLine.Uri).IsSecure;
                m_pRouteSet = (SIP_t_AddressParam[]) Core.ReverseArray(response.RecordRoute.GetAllValues());
                m_pRemoteTarget = (SIP_Uri) response.Contact.GetTopMostValue().Address.Uri;
                m_LocalSeqNo = transaction.Request.CSeq.SequenceNumber;
                m_RemoteSeqNo = 0;
                m_CallID = transaction.Request.CallID;
                m_LocalTag = transaction.Request.From.Tag;
                m_RemoteTag = response.To.Tag;
                m_pRemoteUri = transaction.Request.To.Address.Uri;
                m_pLocalUri = transaction.Request.From.Address.Uri;
                m_pLocalContact = (SIP_Uri) transaction.Request.Contact.GetTopMostValue().Address.Uri;
            }

            #endregion

            m_pFlow = transaction.Flow;
        }
コード例 #34
0
        /// <summary>
        /// Creates authorization for each challange in <b>response</b>.
        /// </summary>
        /// <param name="request">SIP request where to add authorization values.</param>
        /// <param name="response">SIP response which challanges to authorize.</param>
        /// <param name="credentials">Credentials for authorization.</param>
        /// <returns>Returns true if all challanges were authorized. If any of the challanges was not authorized, returns false.</returns>
        private bool Authorize(SIP_Request request, SIP_Response response, NetworkCredential[] credentials)
        {
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }
            if (response == null)
            {
                throw new ArgumentNullException("response");
            }
            if (credentials == null)
            {
                throw new ArgumentNullException("credentials");
            }

            bool allAuthorized = true;

            #region WWWAuthenticate

            foreach (SIP_t_Challenge challange in response.WWWAuthenticate.GetAllValues())
            {
                Auth_HttpDigest authDigest = new Auth_HttpDigest(challange.AuthData,
                                                                 request.RequestLine.Method);

                // Serach credential for the specified challange.
                NetworkCredential credential = null;
                foreach (NetworkCredential c in credentials)
                {
                    if (c.Domain.ToLower() == authDigest.Realm.ToLower())
                    {
                        credential = c;
                        break;
                    }
                }
                // We don't have credential for this challange.
                if (credential == null)
                {
                    allAuthorized = false;
                }
                    // Authorize challange.
                else
                {
                    authDigest.UserName = credential.UserName;
                    authDigest.Password = credential.Password;
                    authDigest.CNonce = Auth_HttpDigest.CreateNonce();

                    request.Authorization.Add(authDigest.ToAuthorization());
                }
            }

            #endregion

            #region ProxyAuthenticate

            foreach (SIP_t_Challenge challange in response.ProxyAuthenticate.GetAllValues())
            {
                Auth_HttpDigest authDigest = new Auth_HttpDigest(challange.AuthData,
                                                                 request.RequestLine.Method);

                // Serach credential for the specified challange.
                NetworkCredential credential = null;
                foreach (NetworkCredential c in credentials)
                {
                    if (c.Domain.ToLower() == authDigest.Realm.ToLower())
                    {
                        credential = c;
                        break;
                    }
                }
                // We don't have credential for this challange.
                if (credential == null)
                {
                    allAuthorized = false;
                }
                    // Authorize challange.
                else
                {
                    authDigest.UserName = credential.UserName;
                    authDigest.Password = credential.Password;
                    authDigest.CNonce = Auth_HttpDigest.CreateNonce();

                    request.ProxyAuthorization.Add(authDigest.ToAuthorization());
                }
            }

            #endregion

            return allAuthorized;
        }
コード例 #35
0
            /// <summary>
            /// Checks if specified response matches this 2xx response retransmission wait entry.
            /// </summary>
            /// <param name="response">INVITE 2xx response.</param>
            /// <returns>Returns true if response matches, othwerwise false.</returns>
            /// <exception cref="ArgumentNullException">Is raised when <b>response</b> is null reference value.</exception>
            public bool Match(SIP_Response response)
            {
                if (response == null)
                {
                    throw new ArgumentNullException("response");
                }

                if (m_pInvite.CSeq.RequestMethod == response.CSeq.RequestMethod &&
                    m_pInvite.CSeq.SequenceNumber == response.CSeq.SequenceNumber)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
コード例 #36
0
 /// <summary>
 /// Sends specified response back to request maker using RFC 3261 18. rules.
 /// </summary>
 /// <param name="response">SIP response.</param>
 /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this method is accessed.</exception>
 /// <exception cref="InvalidOperationException">Is raised when stack ahs not been started and this method is accessed.</exception>
 /// <exception cref="ArgumentNullException">Is raised when <b>response</b> is null reference.</exception>
 /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
 /// <exception cref="SIP_TransportException">Is raised when <b>response</b> sending has failed.</exception>
 /// <remarks>Use this method to send SIP responses from stateless SIP elements, like stateless proxy. 
 /// Otherwise SIP_ServerTransaction.SendResponse method should be used.</remarks>
 public void SendResponse(SIP_Response response)
 {
     SendResponse(response, null);
 }
コード例 #37
0
            /// <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;
            }
コード例 #38
0
        /// <summary>
        /// Initializes dialog.
        /// </summary>
        /// <param name="stack">Owner stack.</param>
        /// <param name="transaction">Owner transaction.</param>
        /// <param name="response">SIP response what caused dialog creation.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>stack</b>,<b>transaction</b> or <b>response</b>.</exception>
        protected internal override void Init(SIP_Stack stack,
                                              SIP_Transaction transaction,
                                              SIP_Response response)
        {
            if (stack == null)
            {
                throw new ArgumentNullException("stack");
            }
            if (transaction == null)
            {
                throw new ArgumentNullException("transaction");
            }
            if (response == null)
            {
                throw new ArgumentNullException("response");
            }

            base.Init(stack, transaction, response);

            if (transaction is SIP_ServerTransaction)
            {
                if (response.StatusCodeType == SIP_StatusCodeType.Success)
                {
                    SetState(SIP_DialogState.Early, false);

                    // We need to retransmit 2xx response while we get ACK or timeout. (RFC 3261 13.3.1.4.)
                    m_pUasInvite2xxRetransmits.Add(new UasInvite2xxRetransmit(this, response));
                }
                else if (response.StatusCodeType == SIP_StatusCodeType.Provisional)
                {
                    SetState(SIP_DialogState.Early, false);

                    m_pActiveInvite = transaction;
                    m_pActiveInvite.StateChanged += delegate
                    {
                        if (m_pActiveInvite != null &&
                            m_pActiveInvite.State ==
                            SIP_TransactionState.Terminated)
                        {
                            m_pActiveInvite = null;
                        }
                    };
                    // Once we send 2xx response, we need to retransmit it while get ACK or timeout. (RFC 3261 13.3.1.4.)
                    ((SIP_ServerTransaction)m_pActiveInvite).ResponseSent +=
                        delegate(object s, SIP_ResponseSentEventArgs a)
                    {
                        if (a.Response.StatusCodeType == SIP_StatusCodeType.Success)
                        {
                            m_pUasInvite2xxRetransmits.Add(new UasInvite2xxRetransmit(this, a.Response));
                        }
                    };
                }
                else
                {
                    throw new ArgumentException(
                              "Argument 'response' has invalid status code, 1xx - 2xx is only allowed.");
                }
            }
            else
            {
                if (response.StatusCodeType == SIP_StatusCodeType.Success)
                {
                    SetState(SIP_DialogState.Confirmed, false);

                    //  Wait for retransmited 2xx responses. (RFC 3261 13.2.2.4.)
                    m_pUacInvite2xxRetransmitWaits.Add(new UacInvite2xxRetransmissionWaiter(this,
                                                                                            transaction.
                                                                                            Request));
                }
                else if (response.StatusCodeType == SIP_StatusCodeType.Provisional)
                {
                    SetState(SIP_DialogState.Early, false);

                    m_pActiveInvite = transaction;
                    m_pActiveInvite.StateChanged += delegate
                    {
                        if (m_pActiveInvite != null &&
                            m_pActiveInvite.State ==
                            SIP_TransactionState.Terminated)
                        {
                            m_pActiveInvite = null;
                        }
                    };
                    // Once we receive 2xx response, we need to wait for retransmitted 2xx responses. (RFC 3261 13.2.2.4)
                    ((SIP_ClientTransaction)m_pActiveInvite).ResponseReceived +=
                        delegate(object s, SIP_ResponseReceivedEventArgs a)
                    {
                        if (a.Response.StatusCodeType == SIP_StatusCodeType.Success)
                        {
                            UacInvite2xxRetransmissionWaiter waiter =
                                new UacInvite2xxRetransmissionWaiter(this, m_pActiveInvite.Request);
                            m_pUacInvite2xxRetransmitWaits.Add(waiter);
                            // Force to send initial ACK to 2xx response.
                            waiter.Process(a.Response);

                            SetState(SIP_DialogState.Confirmed, true);
                        }
                    };
                }
                else
                {
                    throw new ArgumentException(
                              "Argument 'response' has invalid status code, 1xx - 2xx is only allowed.");
                }
            }
        }
コード例 #39
0
        /// <summary>
        /// Initializes dialog.
        /// </summary>
        /// <param name="stack">Owner stack.</param>
        /// <param name="transaction">Owner transaction.</param>
        /// <param name="response">SIP response what caused dialog creation.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>stack</b>,<b>transaction</b> or <b>response</b>.</exception>
        protected internal override void Init(SIP_Stack stack,
                                              SIP_Transaction transaction,
                                              SIP_Response response)
        {
            if (stack == null)
            {
                throw new ArgumentNullException("stack");
            }
            if (transaction == null)
            {
                throw new ArgumentNullException("transaction");
            }
            if (response == null)
            {
                throw new ArgumentNullException("response");
            }

            base.Init(stack, transaction, response);

            if (transaction is SIP_ServerTransaction)
            {
                if (response.StatusCodeType == SIP_StatusCodeType.Success)
                {
                    SetState(SIP_DialogState.Early, false);

                    // We need to retransmit 2xx response while we get ACK or timeout. (RFC 3261 13.3.1.4.)
                    m_pUasInvite2xxRetransmits.Add(new UasInvite2xxRetransmit(this, response));
                }
                else if (response.StatusCodeType == SIP_StatusCodeType.Provisional)
                {
                    SetState(SIP_DialogState.Early, false);

                    m_pActiveInvite = transaction;
                    m_pActiveInvite.StateChanged += delegate
                                                        {
                                                            if (m_pActiveInvite != null &&
                                                                m_pActiveInvite.State ==
                                                                SIP_TransactionState.Terminated)
                                                            {
                                                                m_pActiveInvite = null;
                                                            }
                                                        };
                    // Once we send 2xx response, we need to retransmit it while get ACK or timeout. (RFC 3261 13.3.1.4.)
                    ((SIP_ServerTransaction) m_pActiveInvite).ResponseSent +=
                        delegate(object s, SIP_ResponseSentEventArgs a)
                            {
                                if (a.Response.StatusCodeType == SIP_StatusCodeType.Success)
                                {
                                    m_pUasInvite2xxRetransmits.Add(new UasInvite2xxRetransmit(this, a.Response));
                                }
                            };
                }
                else
                {
                    throw new ArgumentException(
                        "Argument 'response' has invalid status code, 1xx - 2xx is only allowed.");
                }
            }
            else
            {
                if (response.StatusCodeType == SIP_StatusCodeType.Success)
                {
                    SetState(SIP_DialogState.Confirmed, false);

                    //  Wait for retransmited 2xx responses. (RFC 3261 13.2.2.4.)
                    m_pUacInvite2xxRetransmitWaits.Add(new UacInvite2xxRetransmissionWaiter(this,
                                                                                            transaction.
                                                                                                Request));
                }
                else if (response.StatusCodeType == SIP_StatusCodeType.Provisional)
                {
                    SetState(SIP_DialogState.Early, false);

                    m_pActiveInvite = transaction;
                    m_pActiveInvite.StateChanged += delegate
                                                        {
                                                            if (m_pActiveInvite != null &&
                                                                m_pActiveInvite.State ==
                                                                SIP_TransactionState.Terminated)
                                                            {
                                                                m_pActiveInvite = null;
                                                            }
                                                        };
                    // Once we receive 2xx response, we need to wait for retransmitted 2xx responses. (RFC 3261 13.2.2.4)
                    ((SIP_ClientTransaction) m_pActiveInvite).ResponseReceived +=
                        delegate(object s, SIP_ResponseReceivedEventArgs a)
                            {
                                if (a.Response.StatusCodeType == SIP_StatusCodeType.Success)
                                {
                                    UacInvite2xxRetransmissionWaiter waiter =
                                        new UacInvite2xxRetransmissionWaiter(this, m_pActiveInvite.Request);
                                    m_pUacInvite2xxRetransmitWaits.Add(waiter);
                                    // Force to send initial ACK to 2xx response.
                                    waiter.Process(a.Response);

                                    SetState(SIP_DialogState.Confirmed, true);
                                }
                            };
                }
                else
                {
                    throw new ArgumentException(
                        "Argument 'response' has invalid status code, 1xx - 2xx is only allowed.");
                }
            }
        }
コード例 #40
0
        /// <summary>
        /// Creates authorization for each challange in <b>response</b>.
        /// </summary>
        /// <param name="request">SIP request where to add authorization values.</param>
        /// <param name="response">SIP response which challanges to authorize.</param>
        /// <param name="credentials">Credentials for authorization.</param>
        /// <returns>Returns true if all challanges were authorized. If any of the challanges was not authorized, returns false.</returns>
        private bool Authorize(SIP_Request request, SIP_Response response, NetworkCredential[] credentials)
        {
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }
            if (response == null)
            {
                throw new ArgumentNullException("response");
            }
            if (credentials == null)
            {
                throw new ArgumentNullException("credentials");
            }

            bool allAuthorized = true;

            #region WWWAuthenticate

            foreach (SIP_t_Challenge challange in response.WWWAuthenticate.GetAllValues())
            {
                Auth_HttpDigest authDigest = new Auth_HttpDigest(challange.AuthData,
                                                                 request.RequestLine.Method);

                // Serach credential for the specified challange.
                NetworkCredential credential = null;
                foreach (NetworkCredential c in credentials)
                {
                    if (c.Domain.ToLower() == authDigest.Realm.ToLower())
                    {
                        credential = c;
                        break;
                    }
                }
                // We don't have credential for this challange.
                if (credential == null)
                {
                    allAuthorized = false;
                }
                // Authorize challange.
                else
                {
                    authDigest.UserName = credential.UserName;
                    authDigest.Password = credential.Password;
                    authDigest.CNonce   = Auth_HttpDigest.CreateNonce();

                    request.Authorization.Add(authDigest.ToAuthorization());
                }
            }

            #endregion

            #region ProxyAuthenticate

            foreach (SIP_t_Challenge challange in response.ProxyAuthenticate.GetAllValues())
            {
                Auth_HttpDigest authDigest = new Auth_HttpDigest(challange.AuthData,
                                                                 request.RequestLine.Method);

                // Serach credential for the specified challange.
                NetworkCredential credential = null;
                foreach (NetworkCredential c in credentials)
                {
                    if (c.Domain.ToLower() == authDigest.Realm.ToLower())
                    {
                        credential = c;
                        break;
                    }
                }
                // We don't have credential for this challange.
                if (credential == null)
                {
                    allAuthorized = false;
                }
                // Authorize challange.
                else
                {
                    authDigest.UserName = credential.UserName;
                    authDigest.Password = credential.Password;
                    authDigest.CNonce   = Auth_HttpDigest.CreateNonce();

                    request.ProxyAuthorization.Add(authDigest.ToAuthorization());
                }
            }

            #endregion

            return(allAuthorized);
        }
コード例 #41
0
        /// <summary>
        /// Sends specified response back to request maker using RFC 3261 18. rules.
        /// </summary>
        /// <param name="response">SIP response.</param>
        /// <param name="localEP">Local IP end point to use for sending resposne. Value null means system will allocate it.</param>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this method is accessed.</exception>
        /// <exception cref="InvalidOperationException">Is raised when stack ahs not been started and this method is accessed.</exception>
        /// <exception cref="ArgumentNullException">Is raised when <b>response</b> is null reference.</exception>
        /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
        /// <exception cref="SIP_TransportException">Is raised when <b>response</b> sending has failed.</exception>
        /// <remarks>Use this method to send SIP responses from stateless SIP elements, like stateless proxy. 
        /// Otherwise SIP_ServerTransaction.SendResponse method should be used.</remarks>
        public void SendResponse(SIP_Response response, IPEndPoint localEP)
        {
            // NOTE: all  paramter / state validations are done in SendResponseInternal.

            SendResponseInternal(null, response, localEP);
        }
コード例 #42
0
            /// <summary>
            /// Processes retransmited INVITE 2xx response.
            /// </summary>
            /// <param name="response">INVITE 2xx response.</param>
            /// <exception cref="ArgumentNullException">Is raised when <b>response</b> is null reference.</exception>
            public void Process(SIP_Response response)
            {
                if (response == null)
                {
                    throw new ArgumentNullException("response");
                }

                lock (m_pLock)
                {
                    SIP_Request ack = CreateAck();

                    try
                    {
                        // Try existing flow.
                        m_pDialog.Flow.Send(ack);

                        // Log
                        if (m_pDialog.Stack.Logger != null)
                        {
                            byte[] ackBytes = ack.ToByteData();

                            m_pDialog.Stack.Logger.AddWrite(m_pDialog.ID,
                                                            null,
                                                            ackBytes.Length,
                                                            "Dialog [id='" + m_pDialog.ID +
                                                            "] ACK sent for 2xx response.",
                                                            m_pDialog.Flow.LocalEP,
                                                            m_pDialog.Flow.RemoteEP,
                                                            ackBytes);
                        }
                    }
                    catch
                    {
                        /* RFC 3261 13.2.2.4.
                            Once the ACK has been constructed, the procedures of [4] are used to
                            determine the destination address, port and transport.  However, the
                            request is passed to the transport layer directly for transmission,
                            rather than a client transaction.
                        */
                        try
                        {
                            m_pDialog.Stack.TransportLayer.SendRequest(ack);
                        }
                        catch (Exception x)
                        {
                            // Log
                            if (m_pDialog.Stack.Logger != null)
                            {
                                m_pDialog.Stack.Logger.AddText("Dialog [id='" + m_pDialog.ID +
                                                               "'] ACK send for 2xx response failed: " +
                                                               x.Message + ".");
                            }
                        }
                    }
                }
            }
コード例 #43
0
 /// <summary>
 /// Raises <b>ResponseSent</b> event.
 /// </summary>
 /// <param name="response">SIP response.</param>
 private void OnResponseSent(SIP_Response response)
 {
     if (ResponseSent != null)
     {
         ResponseSent(this, new SIP_ResponseSentEventArgs(this, response));
     }
 }
コード例 #44
0
            /// <summary>
            /// Cleans up any resources being used.
            /// </summary>
            public void Dispose()
            {
                lock (m_pLock)
                {
                    if (m_IsDisposed)
                    {
                        return;
                    }
                    m_IsDisposed = true;

                    m_pDialog.m_pUasInvite2xxRetransmits.Remove(this);

                    if (m_pTimer != null)
                    {
                        m_pTimer.Dispose();
                        m_pTimer = null;
                    }
                    m_pDialog = null;
                    m_pResponse = null;
                }
            }
コード例 #45
0
        /// <summary>
        /// Processes specified request through this transaction.
        /// </summary>
        /// <param name="flow">SIP data flow.</param>
        /// <param name="request">SIP request.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>flow</b> or <b>request</b> is null reference.</exception>
        internal void ProcessRequest(SIP_Flow flow, SIP_Request request)
        {
            if (flow == null)
            {
                throw new ArgumentNullException("flow");
            }
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }

            lock (SyncRoot)
            {
                if (State == SIP_TransactionState.Disposed)
                {
                    return;
                }

                try
                {
                    // Log
                    if (Stack.Logger != null)
                    {
                        byte[] requestData = request.ToByteData();

                        Stack.Logger.AddRead(Guid.NewGuid().ToString(),
                                             null,
                                             0,
                                             "Request [transactionID='" + ID + "'; method='" +
                                             request.RequestLine.Method + "'; cseq='" +
                                             request.CSeq.SequenceNumber + "'; " + "transport='" +
                                             flow.Transport + "'; size='" + requestData.Length +
                                             "'; received '" + flow.LocalEP + "' <- '" + flow.RemoteEP + "'.",
                                             flow.LocalEP,
                                             flow.RemoteEP,
                                             requestData);
                    }

                    #region INVITE

                    if (Method == SIP_Methods.INVITE)
                    {
                        #region INVITE

                        if (request.RequestLine.Method == SIP_Methods.INVITE)
                        {
                            if (State == SIP_TransactionState.Proceeding)
                            {
                                /* RFC 3261 17.2.1.
                                 *  If a request retransmission is received while in the "Proceeding" state, the most recent provisional
                                 *  response that was received from the TU MUST be passed to the transport layer for retransmission.
                                 */
                                SIP_Response response = LastProvisionalResponse;
                                if (response != null)
                                {
                                    Stack.TransportLayer.SendResponse(this, response);
                                }
                            }
                            else if (State == SIP_TransactionState.Completed)
                            {
                                /* RFC 3261 17.2.1.
                                 *  While in the "Completed" state, if a request retransmission is received, the server SHOULD
                                 *  pass the response to the transport for retransmission.
                                 */
                                Stack.TransportLayer.SendResponse(this, FinalResponse);
                            }
                        }

                        #endregion

                        #region ACK

                        else if (request.RequestLine.Method == SIP_Methods.ACK)
                        {
                            /* RFC 3261 17.2.1
                             *  If an ACK is received while the server transaction is in the "Completed" state, the server transaction
                             *  MUST transition to the "Confirmed" state.  As Timer G is ignored in this state, any retransmissions of the
                             *  response will cease.
                             *
                             *  When this state is entered, timer I is set to fire in T4 seconds for unreliable transports,
                             *  and zero seconds for reliable transports.
                             */

                            if (State == SIP_TransactionState.Completed)
                            {
                                SetState(SIP_TransactionState.Confirmed);

                                // Stop timers G,H
                                if (m_pTimerG != null)
                                {
                                    m_pTimerG.Dispose();
                                    m_pTimerG = null;

                                    // Log
                                    if (Stack.Logger != null)
                                    {
                                        Stack.Logger.AddText(ID,
                                                             "Transaction [branch='" + ID + "';method='" +
                                                             Method +
                                                             "';IsServer=true] timer G(INVITE response(3xx - 6xx) retransmission) stoped.");
                                    }
                                }
                                if (m_pTimerH != null)
                                {
                                    m_pTimerH.Dispose();
                                    m_pTimerH = null;

                                    // Log
                                    if (Stack.Logger != null)
                                    {
                                        Stack.Logger.AddText(ID,
                                                             "Transaction [branch='" + ID + "';method='" +
                                                             Method +
                                                             "';IsServer=true] timer H(INVITE ACK wait) stoped.");
                                    }
                                }

                                // Start timer I.
                                m_pTimerI          = new TimerEx((flow.IsReliable ? 0 : SIP_TimerConstants.T4), false);
                                m_pTimerI.Elapsed += m_pTimerI_Elapsed;
                                // Log
                                if (Stack.Logger != null)
                                {
                                    Stack.Logger.AddText(ID,
                                                         "Transaction [branch='" + ID + "';method='" + Method +
                                                         "';IsServer=true] timer I(INVITE ACK retransission wait) started, will triger after " +
                                                         m_pTimerI.Interval + ".");
                                }
                                m_pTimerI.Enabled = true;
                            }
                        }

                        #endregion
                    }

                    #endregion

                    #region Non-INVITE

                    else
                    {
                        // Non-INVITE transaction may have only request retransmission requests.
                        if (Method == request.RequestLine.Method)
                        {
                            if (State == SIP_TransactionState.Proceeding)
                            {
                                /* RFC 3261 17.2.2.
                                 *  If a retransmission of the request is received while in the "Proceeding" state, the most
                                 *  recently sent provisional response MUST be passed to the transport layer for retransmission.
                                 */
                                Stack.TransportLayer.SendResponse(this, LastProvisionalResponse);
                            }
                            else if (State == SIP_TransactionState.Completed)
                            {
                                /* RFC 3261 17.2.2.
                                 *  While in the "Completed" state, the server transaction MUST pass the final response to the transport
                                 *  layer for retransmission whenever a retransmission of the request is received.
                                 */
                                Stack.TransportLayer.SendResponse(this, FinalResponse);
                            }
                        }
                    }

                    #endregion
                }
                catch (SIP_TransportException x)
                {
                    // Log
                    if (Stack.Logger != null)
                    {
                        Stack.Logger.AddText(ID,
                                             "Transaction [branch='" + ID + "';method='" + Method +
                                             "';IsServer=true] transport exception: " + x.Message);
                    }

                    OnTransportError(x);
                    SetState(SIP_TransactionState.Terminated);
                }
            }
        }
コード例 #46
0
        /// <summary>
        /// Processes specified response through this dialog.
        /// </summary>
        /// <param name="response">SIP response to process.</param>
        /// <returns>Returns true if this dialog processed specified response, otherwise false.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>response</b> is null.</exception>
        protected internal override bool ProcessResponse(SIP_Response response)
        {
            if (response == null)
            {
                throw new ArgumentNullException("response");
            }

            if (response.StatusCodeType == SIP_StatusCodeType.Success)
            {
                // Search pending INVITE 2xx response retransmission waite entry.
                foreach (UacInvite2xxRetransmissionWaiter w in m_pUacInvite2xxRetransmitWaits)
                {
                    if (w.Match(response))
                    {
                        w.Process(response);

                        return true;
                    }
                }
            }

            return false;
        }
コード例 #47
0
        /// <summary>
        /// Processes specified response through this transaction.
        /// </summary>
        /// <param name="flow">SIP data flow what received response.</param>
        /// <param name="response">SIP response to process.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>flow</b>,<b>response</b> is null reference.</exception>
        internal void ProcessResponse(SIP_Flow flow, SIP_Response response)
        {
            if (flow == null)
            {
                throw new ArgumentNullException("flow");
            }
            if (response == null)
            {
                throw new ArgumentNullException("response");
            }

            lock (SyncRoot)
            {
                if (State == SIP_TransactionState.Disposed)
                {
                    return;
                }
                    /* RFC 3261 9.1. CANCEL.
                    *) If provisional response, send CANCEL, we should get '478 Request terminated'.
                    *) If final response, skip canceling, nothing to cancel.
                */
                else if (m_IsCanceling && response.StatusCodeType == SIP_StatusCodeType.Provisional)
                {
                    SendCancel();
                    return;
                }

                // Log
                if (Stack.Logger != null)
                {
                    byte[] responseData = response.ToByteData();

                    Stack.Logger.AddRead(Guid.NewGuid().ToString(),
                                         null,
                                         0,
                                         "Response [transactionID='" + ID + "'; method='" +
                                         response.CSeq.RequestMethod + "'; cseq='" +
                                         response.CSeq.SequenceNumber + "'; " + "transport='" + flow.Transport +
                                         "'; size='" + responseData.Length + "'; statusCode='" +
                                         response.StatusCode + "'; " + "reason='" + response.ReasonPhrase +
                                         "'; received '" + flow.LocalEP + "' <- '" + flow.RemoteEP + "'.",
                                         flow.LocalEP,
                                         flow.RemoteEP,
                                         responseData);
                }

                #region INVITE

                /* RFC 3261 17.1.1.2.
                                                   |INVITE from TU
                                 Timer A fires     |INVITE sent
                                 Reset A,          V                      Timer B fires
                                 INVITE sent +-----------+                or Transport Err.
                                   +---------|           |---------------+inform TU
                                   |         |  Calling  |               |
                                   +-------->|           |-------------->|
                                             +-----------+ 2xx           |
                                                |  |       2xx to TU     |
                                                |  |1xx                  |
                        300-699 +---------------+  |1xx to TU            |
                       ACK sent |                  |                     |
                    resp. to TU |  1xx             V                     |
                                |  1xx to TU  -----------+               |
                                |  +---------|           |               |
                                |  |         |Proceeding |-------------->|
                                |  +-------->|           | 2xx           |
                                |            +-----------+ 2xx to TU     |
                                |       300-699    |                     |
                                |       ACK sent,  |                     |
                                |       resp. to TU|                     |
                                |                  |                     |      NOTE:
                                |  300-699         V                     |
                                |  ACK sent  +-----------+Transport Err. |  transitions
                                |  +---------|           |Inform TU      |  labeled with
                                |  |         | Completed |-------------->|  the event
                                |  +-------->|           |               |  over the action
                                |            +-----------+               |  to take
                                |              ^   |                     |
                                |              |   | Timer D fires       |
                                +--------------+   | -                   |
                                                   |                     |
                                                   V                     |
                                             +-----------+               |
                                             |           |               |
                                             | Terminated|<--------------+
                                             |           |
                                             +-----------+

                */

                if (Method == SIP_Methods.INVITE)
                {
                    #region Calling

                    if (State == SIP_TransactionState.Calling)
                    {
                        // Store response.
                        AddResponse(response);

                        // Stop timer A,B
                        if (m_pTimerA != null)
                        {
                            m_pTimerA.Dispose();
                            m_pTimerA = null;

                            // Log
                            if (Stack.Logger != null)
                            {
                                Stack.Logger.AddText(ID,
                                                     "Transaction [branch='" + ID + "';method='" + Method +
                                                     "';IsServer=false] timer A(INVITE request retransmission) stoped.");
                            }
                        }
                        if (m_pTimerB != null)
                        {
                            m_pTimerB.Dispose();
                            m_pTimerB = null;

                            // Log
                            if (Stack.Logger != null)
                            {
                                Stack.Logger.AddText(ID,
                                                     "Transaction [branch='" + ID + "';method='" + Method +
                                                     "';IsServer=false] timer B(INVITE calling state timeout) stoped.");
                            }
                        }

                        // 1xx response.
                        if (response.StatusCodeType == SIP_StatusCodeType.Provisional)
                        {
                            OnResponseReceived(response);
                            SetState(SIP_TransactionState.Proceeding);
                        }
                            // 2xx response.
                        else if (response.StatusCodeType == SIP_StatusCodeType.Success)
                        {
                            OnResponseReceived(response);
                            SetState(SIP_TransactionState.Terminated);
                        }
                            // 3xx - 6xx response.
                        else
                        {
                            SendAck(response);
                            OnResponseReceived(response);
                            SetState(SIP_TransactionState.Completed);

                            /* RFC 3261 17.1.1.2. 
                                The client transaction SHOULD start timer D when it enters the "Completed" state, 
                                with a value of at least 32 seconds for unreliable transports, and a value of zero 
                                seconds for reliable transports.
                            */
                            m_pTimerD = new TimerEx(Flow.IsReliable ? 0 : Workaround.Definitions.MaxStreamLineLength, false);
                            m_pTimerD.Elapsed += m_pTimerD_Elapsed;
                            // Log
                            if (Stack.Logger != null)
                            {
                                Stack.Logger.AddText(ID,
                                                     "Transaction [branch='" + ID + "';method='" + Method +
                                                     "';IsServer=false] timer D(INVITE 3xx - 6xx response retransmission wait) started, will triger after " +
                                                     m_pTimerD.Interval + ".");
                            }
                            m_pTimerD.Enabled = true;
                        }
                    }

                        #endregion

                        #region Proceeding

                    else if (State == SIP_TransactionState.Proceeding)
                    {
                        // Store response.
                        AddResponse(response);

                        // 1xx response.
                        if (response.StatusCodeType == SIP_StatusCodeType.Provisional)
                        {
                            OnResponseReceived(response);
                        }
                            // 2xx response.
                        else if (response.StatusCodeType == SIP_StatusCodeType.Success)
                        {
                            OnResponseReceived(response);
                            SetState(SIP_TransactionState.Terminated);
                        }
                            // 3xx - 6xx response.
                        else
                        {
                            SendAck(response);
                            OnResponseReceived(response);
                            SetState(SIP_TransactionState.Completed);

                            /* RFC 3261 17.1.1.2. 
                                The client transaction SHOULD start timer D when it enters the "Completed" state, 
                                with a value of at least 32 seconds for unreliable transports, and a value of zero 
                                seconds for reliable transports.
                            */
                            m_pTimerD = new TimerEx(Flow.IsReliable ? 0 : Workaround.Definitions.MaxStreamLineLength, false);
                            m_pTimerD.Elapsed += m_pTimerD_Elapsed;
                            // Log
                            if (Stack.Logger != null)
                            {
                                Stack.Logger.AddText(ID,
                                                     "Transaction [branch='" + ID + "';method='" + Method +
                                                     "';IsServer=false] timer D(INVITE 3xx - 6xx response retransmission wait) started, will triger after " +
                                                     m_pTimerD.Interval + ".");
                            }
                            m_pTimerD.Enabled = true;
                        }
                    }

                        #endregion

                        #region Completed

                    else if (State == SIP_TransactionState.Completed)
                    {
                        // 3xx - 6xx
                        if (response.StatusCode >= 300)
                        {
                            SendAck(response);
                        }
                    }

                        #endregion

                        #region Terminated

                    else if (State == SIP_TransactionState.Terminated)
                    {
                        // We should never reach here, but if so, do nothing.
                    }

                    #endregion
                }

                    #endregion

                    #region Non-INVITE

                    /* RFC 3251 17.1.2.2
                                               |Request from TU
                                               |send request
                           Timer E             V
                           send request  +-----------+
                               +---------|           |-------------------+
                               |         |  Trying   |  Timer F          |
                               +-------->|           |  or Transport Err.|
                                         +-----------+  inform TU        |
                            200-699         |  |                         |
                            resp. to TU     |  |1xx                      |
                            +---------------+  |resp. to TU              |
                            |                  |                         |
                            |   Timer E        V       Timer F           |
                            |   send req +-----------+ or Transport Err. |
                            |  +---------|           | inform TU         |
                            |  |         |Proceeding |------------------>|
                            |  +-------->|           |-----+             |
                            |            +-----------+     |1xx          |
                            |              |      ^        |resp to TU   |
                            | 200-699      |      +--------+             |
                            | resp. to TU  |                             |
                            |              |                             |
                            |              V                             |
                            |            +-----------+                   |
                            |            |           |                   |
                            |            | Completed |                   |
                            |            |           |                   |
                            |            +-----------+                   |
                            |              ^   |                         |
                            |              |   | Timer K                 |
                            +--------------+   | -                       |
                                               |                         |
                                               V                         |
                         NOTE:           +-----------+                   |
                                         |           |                   |
                     transitions         | Terminated|<------------------+
                     labeled with        |           |
                     the event           +-----------+
                     over the action
                     to take
                */

                else
                {
                    #region Trying

                    if (State == SIP_TransactionState.Trying)
                    {
                        // Store response.
                        AddResponse(response);

                        // Stop timer E
                        if (m_pTimerE != null)
                        {
                            m_pTimerE.Dispose();
                            m_pTimerE = null;

                            // Log
                            if (Stack.Logger != null)
                            {
                                Stack.Logger.AddText(ID,
                                                     "Transaction [branch='" + ID + "';method='" + Method +
                                                     "';IsServer=false] timer E(Non-INVITE request retransmission) stoped.");
                            }
                        }

                        // 1xx response.
                        if (response.StatusCodeType == SIP_StatusCodeType.Provisional)
                        {
                            OnResponseReceived(response);
                            SetState(SIP_TransactionState.Proceeding);
                        }
                            // 2xx - 6xx response.
                        else
                        {
                            // Stop timer F
                            if (m_pTimerF != null)
                            {
                                m_pTimerF.Dispose();
                                m_pTimerF = null;

                                // Log
                                if (Stack.Logger != null)
                                {
                                    Stack.Logger.AddText(ID,
                                                         "Transaction [branch='" + ID + "';method='" + Method +
                                                         "';IsServer=false] timer F(Non-INVITE trying,proceeding state timeout) stoped.");
                                }
                            }

                            OnResponseReceived(response);
                            SetState(SIP_TransactionState.Completed);

                            /* RFC 3261 17.1.2.2. 
                                The client transaction enters the "Completed" state, it MUST set
                                Timer K to fire in T4 seconds for unreliable transports, and zero
                                seconds for reliable transports.
                            */
                            m_pTimerK = new TimerEx(Flow.IsReliable ? 1 : SIP_TimerConstants.T4, false);
                            m_pTimerK.Elapsed += m_pTimerK_Elapsed;
                            // Log
                            if (Stack.Logger != null)
                            {
                                Stack.Logger.AddText(ID,
                                                     "Transaction [branch='" + ID + "';method='" + Method +
                                                     "';IsServer=false] timer K(Non-INVITE 3xx - 6xx response retransmission wait) started, will triger after " +
                                                     m_pTimerK.Interval + ".");
                            }
                            m_pTimerK.Enabled = true;
                        }
                    }

                        #endregion

                        #region Proceeding

                    else if (State == SIP_TransactionState.Proceeding)
                    {
                        // Store response.
                        AddResponse(response);

                        // 1xx response.
                        if (response.StatusCodeType == SIP_StatusCodeType.Provisional)
                        {
                            OnResponseReceived(response);
                        }                        
                            // 2xx - 6xx response.
                        else
                        {
                            // Stop timer F
                            if (m_pTimerF != null)
                            {
                                m_pTimerF.Dispose();
                                m_pTimerF = null;

                                // Log
                                if (Stack.Logger != null)
                                {
                                    Stack.Logger.AddText(ID,
                                                         "Transaction [branch='" + ID + "';method='" + Method +
                                                         "';IsServer=false] timer F(Non-INVITE trying,proceeding state timeout) stoped.");
                                }
                            }

                            OnResponseReceived(response);
                            SetState(SIP_TransactionState.Completed);

                            /* RFC 3261 17.1.2.2. 
                                The client transaction enters the "Completed" state, it MUST set
                                Timer K to fire in T4 seconds for unreliable transports, and zero
                                seconds for reliable transports.
                            */
                            m_pTimerK = new TimerEx(Flow.IsReliable ? 0 : SIP_TimerConstants.T4, false);
                            m_pTimerK.Elapsed += m_pTimerK_Elapsed;
                            // Log
                            if (Stack.Logger != null)
                            {
                                Stack.Logger.AddText(ID,
                                                     "Transaction [branch='" + ID + "';method='" + Method +
                                                     "';IsServer=false] timer K(Non-INVITE 3xx - 6xx response retransmission wait) started, will triger after " +
                                                     m_pTimerK.Interval + ".");
                            }
                            m_pTimerK.Enabled = true;
                        }
                    }

                        #endregion

                        #region Completed

                    else if (State == SIP_TransactionState.Completed)
                    {
                        // Eat retransmited response.
                    }

                        #endregion

                        #region Terminated

                    else if (State == SIP_TransactionState.Terminated)
                    {
                        // We should never reach here, but if so, do nothing.
                    }

                    #endregion
                }

                #endregion
            }
        }
コード例 #48
0
        /// <summary>
        /// Sends specified response to remote party.
        /// </summary>
        /// <param name="response">SIP response to send.</param>
        /// <exception cref="ObjectDisposedException">Is raised when this class is Disposed and this method is accessed.</exception>
        /// <exception cref="ArgumentNullException">Is raised when <b>response</b> is null reference.</exception>
        public void SendResponse(SIP_Response response)
        {
            lock (SyncRoot)
            {
                if (State == SIP_TransactionState.Disposed)
                {
                    throw new ObjectDisposedException(GetType().Name);
                }
                if (response == null)
                {
                    throw new ArgumentNullException("response");
                }

                try
                {
                    #region INVITE

                    /* RFC 3261 17.2.1.
                                           |INVITE
                                           |pass INV to TU
                        INVITE             V send 100 if TU won't in 200ms
                        send response+-----------+
                            +--------|           |--------+101-199 from TU
                            |        | Proceeding|        |send response
                            +------->|           |<-------+
                                     |           |          Transport Err.
                                     |           |          Inform TU
                                     |           |--------------->+
                                     +-----------+                |
                        300-699 from TU |     |2xx from TU        |
                        send response   |     |send response      |
                                        |     +------------------>+
                                        |                         |
                        INVITE          V          Timer G fires  |
                        send response+-----------+ send response  |
                            +--------|           |--------+       |
                            |        | Completed |        |       |
                            +------->|           |<-------+       |
                                     +-----------+                |
                                        |     |                   |
                                    ACK |     |                   |
                                    -   |     +------------------>+
                                        |        Timer H fires    |
                                        V        or Transport Err.|
                                     +-----------+  Inform TU     |
                                     |           |                |
                                     | Confirmed |                |
                                     |           |                |
                                     +-----------+                |
                                           |                      |
                                           |Timer I fires         |
                                           |-                     |
                                           |                      |
                                           V                      |
                                     +-----------+                |
                                     |           |                |
                                     | Terminated|<---------------+
                                     |           |
                                     +-----------+
                    */

                    if (Method == SIP_Methods.INVITE)
                    {
                        #region Proceeding

                        if (State == SIP_TransactionState.Proceeding)
                        {
                            AddResponse(response);

                            // 1xx
                            if (response.StatusCodeType == SIP_StatusCodeType.Provisional)
                            {
                                Stack.TransportLayer.SendResponse(this, response);
                                OnResponseSent(response);
                            }
                                // 2xx
                            else if (response.StatusCodeType == SIP_StatusCodeType.Success)
                            {
                                Stack.TransportLayer.SendResponse(this, response);
                                OnResponseSent(response);
                                SetState(SIP_TransactionState.Terminated);
                            }
                                // 3xx - 6xx
                            else
                            {
                                Stack.TransportLayer.SendResponse(this, response);
                                OnResponseSent(response);
                                SetState(SIP_TransactionState.Completed);

                                /* RFC 3261 17.2.1.
                                    For unreliable transports, timer G is set to fire in T1 seconds, and is not set to fire for reliable transports.
                                */
                                if (!Flow.IsReliable)
                                {
                                    m_pTimerG = new TimerEx(SIP_TimerConstants.T1, false);
                                    m_pTimerG.Elapsed += m_pTimerG_Elapsed;
                                    m_pTimerG.Enabled = true;

                                    // Log
                                    if (Stack.Logger != null)
                                    {
                                        Stack.Logger.AddText(ID,
                                                             "Transaction [branch='" + ID + "';method='" +
                                                             Method +
                                                             "';IsServer=true] timer G(INVITE response(3xx - 6xx) retransmission) started, will triger after " +
                                                             m_pTimerG.Interval + ".");
                                    }
                                }

                                /* RFC 3261 17.2.1.
                                    When the "Completed" state is entered, timer H MUST be set to fire in 64*T1 seconds for all transports.
                                */
                                m_pTimerH = new TimerEx(64*SIP_TimerConstants.T1);
                                m_pTimerH.Elapsed += m_pTimerH_Elapsed;
                                m_pTimerH.Enabled = true;

                                // Log
                                if (Stack.Logger != null)
                                {
                                    Stack.Logger.AddText(ID,
                                                         "Transaction [branch='" + ID + "';method='" + Method +
                                                         "';IsServer=true] timer H(INVITE ACK wait) started, will triger after " +
                                                         m_pTimerH.Interval + ".");
                                }
                            }
                        }

                            #endregion

                            #region Completed

                        else if (State == SIP_TransactionState.Completed)
                        {
                            // We do nothing here, we just wait ACK to arrive.
                        }

                            #endregion

                            #region Confirmed

                        else if (State == SIP_TransactionState.Confirmed)
                        {
                            // We do nothing, just wait ACK retransmissions.
                        }

                            #endregion

                            #region Terminated

                        else if (State == SIP_TransactionState.Terminated)
                        {
                            // We should never rreach here, but if so, skip it.
                        }

                        #endregion
                    }

                        #endregion

                        #region Non-INVITE

                        /* RFC 3261 17.2.2.
                                              |Request received
                                              |pass to TU
                                              V
                                        +-----------+
                                        |           |
                                        | Trying    |-------------+
                                        |           |             |
                                        +-----------+             |200-699 from TU
                                              |                   |send response
                                              |1xx from TU        |
                                              |send response      |
                                              |                   |
                           Request            V      1xx from TU  |
                           send response+-----------+send response|
                               +--------|           |--------+    |
                               |        | Proceeding|        |    |
                               +------->|           |<-------+    |
                        +<--------------|           |             |
                        |Trnsprt Err    +-----------+             |
                        |Inform TU            |                   |
                        |                     |                   |
                        |                     |200-699 from TU    |
                        |                     |send response      |
                        |  Request            V                   |
                        |  send response+-----------+             |
                        |      +--------|           |             |
                        |      |        | Completed |<------------+
                        |      +------->|           |
                        +<--------------|           |
                        |Trnsprt Err    +-----------+
                        |Inform TU            |
                        |                     |Timer J fires
                        |                     |-
                        |                     |
                        |                     V
                        |               +-----------+
                        |               |           |
                        +-------------->| Terminated|
                                        |           |
                                        +-----------+
                    */

                    else
                    {
                        #region Trying

                        if (State == SIP_TransactionState.Trying)
                        {
                            AddResponse(response);

                            // 1xx
                            if (response.StatusCodeType == SIP_StatusCodeType.Provisional)
                            {
                                Stack.TransportLayer.SendResponse(this, response);
                                OnResponseSent(response);
                                SetState(SIP_TransactionState.Proceeding);
                            }
                                // 2xx - 6xx
                            else
                            {
                                Stack.TransportLayer.SendResponse(this, response);
                                OnResponseSent(response);
                                SetState(SIP_TransactionState.Completed);

                                /* RFC 3261 17.2.2.
                                    When the server transaction enters the "Completed" state, it MUST set
                                    Timer J to fire in 64*T1 seconds for unreliable transports, and zero
                                    seconds for reliable transports.
                                */
                                m_pTimerJ = new TimerEx(64*SIP_TimerConstants.T1, false);
                                m_pTimerJ.Elapsed += m_pTimerJ_Elapsed;
                                m_pTimerJ.Enabled = true;

                                // Log
                                if (Stack.Logger != null)
                                {
                                    Stack.Logger.AddText(ID,
                                                         "Transaction [branch='" + ID + "';method='" + Method +
                                                         "';IsServer=true] timer J(Non-INVITE request retransmission wait) started, will triger after " +
                                                         m_pTimerJ.Interval + ".");
                                }
                            }
                        }

                            #endregion

                            #region Proceeding

                        else if (State == SIP_TransactionState.Proceeding)
                        {
                            AddResponse(response);

                            // 1xx
                            if (response.StatusCodeType == SIP_StatusCodeType.Provisional)
                            {
                                Stack.TransportLayer.SendResponse(this, response);
                                OnResponseSent(response);
                            }
                                // 2xx - 6xx
                            else
                            {
                                Stack.TransportLayer.SendResponse(this, response);
                                OnResponseSent(response);
                                SetState(SIP_TransactionState.Completed);

                                /* RFC 3261 17.2.2.
                                    When the server transaction enters the "Completed" state, it MUST set
                                    Timer J to fire in 64*T1 seconds for unreliable transports, and zero
                                    seconds for reliable transports.
                                */
                                m_pTimerJ = new TimerEx(64*SIP_TimerConstants.T1, false);
                                m_pTimerJ.Elapsed += m_pTimerJ_Elapsed;
                                m_pTimerJ.Enabled = true;

                                // Log
                                if (Stack.Logger != null)
                                {
                                    Stack.Logger.AddText(ID,
                                                         "Transaction [branch='" + ID + "';method='" + Method +
                                                         "';IsServer=true] timer J(Non-INVITE request retransmission wait) started, will triger after " +
                                                         m_pTimerJ.Interval + ".");
                                }
                            }
                        }

                            #endregion

                            #region Completed

                        else if (State == SIP_TransactionState.Completed)
                        {
                            // Do nothing.
                        }

                            #endregion

                            #region Terminated

                        else if (State == SIP_TransactionState.Terminated)
                        {
                            // Do nothing.
                        }

                        #endregion
                    }

                    #endregion
                }
                catch (SIP_TransportException x)
                {
                    // Log
                    if (Stack.Logger != null)
                    {
                        Stack.Logger.AddText(ID,
                                             "Transaction [branch='" + ID + "';method='" + Method +
                                             "';IsServer=true] transport exception: " + x.Message);
                    }

                    OnTransportError(x);
                    SetState(SIP_TransactionState.Terminated);
                }
            }
        }
コード例 #49
0
        /// <summary>
        /// Sends response to request maker using RFC 3261 18. rules.
        /// </summary>
        /// <param name="transaction">Owner server transaction. Can be null if stateless response sending.</param>
        /// <param name="response">SIP response to send.</param>
        /// <param name="localEP">Local IP end point to use for sending resposne. Value null means system will allocate it.</param>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this method is accessed.</exception>
        /// <exception cref="InvalidOperationException">Is raised when stack ahs not been started and this method is accessed.</exception>
        /// <exception cref="ArgumentNullException">Is raised when <b>response</b> is null reference.</exception>
        /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception>
        /// <exception cref="SIP_TransportException">Is raised when <b>response</b> sending has failed.</exception>
        private void SendResponseInternal(SIP_ServerTransaction transaction,
                                          SIP_Response response,
                                          IPEndPoint localEP)
        {
            if (m_IsDisposed)
            {
                throw new ObjectDisposedException(GetType().Name);
            }
            if (!m_IsRunning)
            {
                throw new InvalidOperationException("Stack has not been started.");
            }
            if (response == null)
            {
                throw new ArgumentNullException("response");
            }

            /* RFC 3261 18.2.2.
                The server transport uses the value of the top Via header field in
                order to determine where to send a response.  It MUST follow the
                following process:

                    o  If the "sent-protocol" is a reliable transport protocol such as
                       TCP or SCTP, or TLS over those, the response MUST be sent using
                       the existing connection to the source of the original request
                       that created the transaction, if that connection is still open.
                       This requires the server transport to maintain an association
                       between server transactions and transport connections.  If that
                       connection is no longer open, the server SHOULD open a
                       connection to the IP address in the "received" parameter, if
                       present, using the port in the "sent-by" value, or the default
                       port for that transport, if no port is specified.  If that
                       connection attempt fails, the server SHOULD use the procedures
                       in [4] for servers in order to determine the IP address and
                       port to open the connection and send the response to.

                    o  Otherwise, if the Via header field value contains a "maddr"
                       parameter, the response MUST be forwarded to the address listed
                       there, using the port indicated in "sent-by", or port 5060 if
                       none is present.  If the address is a multicast address, the
                       response SHOULD be sent using the TTL indicated in the "ttl"
                       parameter, or with a TTL of 1 if that parameter is not present.

                    o  Otherwise (for unreliable unicast transports), if the top Via
                       has a "received" parameter, the response MUST be sent to the
                       address in the "received" parameter, using the port indicated
                       in the "sent-by" value, or using port 5060 if none is specified
                       explicitly.  If this fails, for example, elicits an ICMP "port
                       unreachable" response, the procedures of Section 5 of [4]
                       SHOULD be used to determine where to send the response.
                  
                    o  Otherwise, if it is not receiver-tagged, the response MUST be
                       sent to the address indicated by the "sent-by" value, using the
                       procedures in Section 5 of [4].
            */

            /* RFC 3581 4. (Adds new processing between RFC 3261 18.2.2. bullet 2 and 3)
                When a server attempts to send a response, it examines the topmost
                Via header field value of that response.  If the "sent-protocol"
                component indicates an unreliable unicast transport protocol, such as
                UDP, and there is no "maddr" parameter, but there is both a
                "received" parameter and an "rport" parameter, the response MUST be
                sent to the IP address listed in the "received" parameter, and the
                port in the "rport" parameter.  The response MUST be sent from the
                same address and port that the corresponding request was received on.
                This effectively adds a new processing step between bullets two and
                three in Section 18.2.2 of SIP [1].

                The response must be sent from the same address and port that the
                request was received on in order to traverse symmetric NATs.  When a
                server is listening for requests on multiple ports or interfaces, it
                will need to remember the one on which the request was received.  For
                a stateful proxy, storing this information for the duration of the
                transaction is not an issue.  However, a stateless proxy does not
                store state between a request and its response, and therefore cannot
                remember the address and port on which a request was received.  To
                properly implement this specification, a stateless proxy can encode
                the destination address and port of a request into the Via header
                field value that it inserts.  When the response arrives, it can
                extract this information and use it to forward the response.
            */

            SIP_t_ViaParm via = response.Via.GetTopMostValue();
            if (via == null)
            {
                throw new ArgumentException("Argument 'response' does not contain required Via: header field.");
            }

            // TODO: If transport is not supported.            
            //throw new SIP_TransportException("Not supported transport '" + via.ProtocolTransport + "'.");

            string logID = Guid.NewGuid().ToString();
            string transactionID = transaction == null ? "" : transaction.ID;

            // Try to get local IP end point which we should use to send response back.            
            if (transaction != null && transaction.Request.LocalEndPoint != null)
            {
                localEP = transaction.Request.LocalEndPoint;
            }

                // TODO: no "localEP" at moment

                // TODO: Stateless should use flowID instead.

                // Our stateless proxy add 'localEP' parameter to Via: if so normally we can get it from there.
            else if (via.Parameters["localEP"] != null)
            {
                localEP = Net_Utils.ParseIPEndPoint(via.Parameters["localEP"].Value);
            }

            byte[] responseData = response.ToByteData();

            #region Try existing flow first

            /* First try active flow to send response, thats not 100% as RFC says, but works better in any case.
               RFC says that for TCP and TLS only, we do it for any transport.
            */

            if (transaction != null)
            {
                try
                {
                    SIP_Flow flow = transaction.Flow;
                    flow.Send(response);

                    if (m_pStack.Logger != null)
                    {
                        m_pStack.Logger.AddWrite(logID,
                                                 null,
                                                 0,
                                                 "Response [flowReuse=true; transactionID='" + transactionID +
                                                 "'; method='" + response.CSeq.RequestMethod + "'; cseq='" +
                                                 response.CSeq.SequenceNumber + "'; " + "transport='" +
                                                 flow.Transport + "'; size='" + responseData.Length +
                                                 "'; statusCode='" + response.StatusCode + "'; " + "reason='" +
                                                 response.ReasonPhrase + "'; sent '" + flow.LocalEP + "' -> '" +
                                                 flow.RemoteEP + "'.",
                                                 localEP,
                                                 flow.RemoteEP,
                                                 responseData);
                    }

                    return;
                }
                catch
                {
                    // Do nothing, processing will continue.
                }
            }

            #endregion

            #region Reliable TCP,TLS, ...

            if (SIP_Utils.IsReliableTransport(via.ProtocolTransport))
            {
                // Get original request remote end point.
                IPEndPoint remoteEP = null;
                if (transaction != null && transaction.Request.RemoteEndPoint != null)
                {
                    remoteEP = transaction.Request.RemoteEndPoint;
                }
                else if (via.Received != null)
                {
                    remoteEP = new IPEndPoint(via.Received, via.SentBy.Port == -1 ? 5060 : via.SentBy.Port);
                }

                #region If original request connection alive, use it

                try
                {
                    SIP_Flow flow = null;

                    // Statefull
                    if (transaction != null)
                    {
                        if (transaction.Request.Flow != null && !transaction.Request.Flow.IsDisposed)
                        {
                            flow = transaction.Request.Flow;
                        }
                    }
                        // Stateless
                    else
                    {
                        string flowID = via.Parameters["connectionID"].Value;
                        if (flowID != null)
                        {
                            flow = m_pFlowManager[flowID];
                        }
                    }

                    if (flow != null)
                    {
                        flow.Send(response);

                        if (m_pStack.Logger != null)
                        {
                            m_pStack.Logger.AddWrite(logID,
                                                     null,
                                                     0,
                                                     "Response [flowReuse=true; transactionID='" +
                                                     transactionID + "'; method='" +
                                                     response.CSeq.RequestMethod + "'; cseq='" +
                                                     response.CSeq.SequenceNumber + "'; " + "transport='" +
                                                     flow.Transport + "'; size='" + responseData.Length +
                                                     "'; statusCode='" + response.StatusCode + "'; " +
                                                     "reason='" + response.ReasonPhrase + "'; sent '" +
                                                     flow.RemoteEP + "' -> '" + flow.LocalEP + "'.",
                                                     localEP,
                                                     remoteEP,
                                                     responseData);
                        }

                        return;
                    }
                }
                catch
                {
                    // Do nothing, processing will continue.
                    // Override RFC, if there is any existing connection and it gives error, try always RFC 3261 18.2.2(recieved) and 3265 5.
                }

                #endregion

                #region Send RFC 3261 18.2.2(recieved)

                if (remoteEP != null)
                {
                    try
                    {
                        SendResponseToHost(logID,
                                           transactionID,
                                           null,
                                           remoteEP.Address.ToString(),
                                           remoteEP.Port,
                                           via.ProtocolTransport,
                                           response);
                    }
                    catch
                    {
                        // Do nothing, processing will continue -> "RFC 3265 5.".
                    }
                }

                #endregion

                #region Send RFC 3265 5.

                SendResponse_RFC_3263_5(logID, transactionID, localEP, response);

                #endregion
            }

                #endregion

                #region UDP Via: maddr parameter

            else if (via.Maddr != null)
            {
                throw new SIP_TransportException(
                    "Sending responses to multicast address(Via: 'maddr') is not supported.");
            }

                #endregion

                #region RFC 3581 4. UDP Via: received and rport parameters

            else if (via.Maddr == null && via.Received != null && via.RPort > 0)
            {
                SendResponseToHost(logID,
                                   transactionID,
                                   localEP,
                                   via.Received.ToString(),
                                   via.RPort,
                                   via.ProtocolTransport,
                                   response);
            }

                #endregion

                #region UDP Via: received parameter

            else if (via.Received != null)
            {
                SendResponseToHost(logID,
                                   transactionID,
                                   localEP,
                                   via.Received.ToString(),
                                   via.SentByPortWithDefault,
                                   via.ProtocolTransport,
                                   response);
            }

                #endregion

                #region UDP

            else
            {
                SendResponse_RFC_3263_5(logID, transactionID, localEP, response);
            }

            #endregion
        }
コード例 #50
0
        /// <summary>
        /// Initializes dialog.
        /// </summary>
        /// <param name="stack">Owner stack.</param>
        /// <param name="transaction">Owner transaction.</param>
        /// <param name="response">SIP response what caused dialog creation.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>stack</b>,<b>transaction</b> or <b>response</b>.</exception>
        protected internal virtual void Init(SIP_Stack stack,
                                             SIP_Transaction transaction,
                                             SIP_Response response)
        {
            if (stack == null)
            {
                throw new ArgumentNullException("stack");
            }
            if (transaction == null)
            {
                throw new ArgumentNullException("transaction");
            }
            if (response == null)
            {
                throw new ArgumentNullException("response");
            }

            m_pStack = stack;

            #region UAS

            /* RFC 3261 12.1.1.
             *  The UAS then constructs the state of the dialog.  This state MUST be
             *  maintained for the duration of the dialog.
             *
             *  If the request arrived over TLS, and the Request-URI contained a SIPS
             *  URI, the "secure" flag is set to TRUE.
             *
             *  The route set MUST be set to the list of URIs in the Record-Route
             *  header field from the request, taken in order and preserving all URI
             *  parameters.  If no Record-Route header field is present in the
             *  request, the route set MUST be set to the empty set.  This route set,
             *  even if empty, overrides any pre-existing route set for future
             *  requests in this dialog.  The remote target MUST be set to the URI
             *  from the Contact header field of the request.
             *
             *  The remote sequence number MUST be set to the value of the sequence
             *  number in the CSeq header field of the request.  The local sequence
             *  number MUST be empty.  The call identifier component of the dialog ID
             *  MUST be set to the value of the Call-ID in the request.  The local
             *  tag component of the dialog ID MUST be set to the tag in the To field
             *  in the response to the request (which always includes a tag), and the
             *  remote tag component of the dialog ID MUST be set to the tag from the
             *  From field in the request.  A UAS MUST be prepared to receive a
             *  request without a tag in the From field, in which case the tag is
             *  considered to have a value of null.
             *
             *      This is to maintain backwards compatibility with RFC 2543, which
             *      did not mandate From tags.
             *
             *  The remote URI MUST be set to the URI in the From field, and the
             *  local URI MUST be set to the URI in the To field.
             */

            if (transaction is SIP_ServerTransaction)
            {
                // TODO: Validate request or client transaction must do it ?

                m_IsSecure  = ((SIP_Uri)transaction.Request.RequestLine.Uri).IsSecure;
                m_pRouteSet =
                    (SIP_t_AddressParam[])Core.ReverseArray(transaction.Request.RecordRoute.GetAllValues());
                m_pRemoteTarget = (SIP_Uri)transaction.Request.Contact.GetTopMostValue().Address.Uri;
                m_RemoteSeqNo   = transaction.Request.CSeq.SequenceNumber;
                m_LocalSeqNo    = 0;
                m_CallID        = transaction.Request.CallID;
                m_LocalTag      = response.To.Tag;
                m_RemoteTag     = transaction.Request.From.Tag;
                m_pRemoteUri    = transaction.Request.From.Address.Uri;
                m_pLocalUri     = transaction.Request.To.Address.Uri;
                m_pLocalContact = (SIP_Uri)response.Contact.GetTopMostValue().Address.Uri;
            }

            #endregion

            #region UAC

            /* RFC 3261 12.1.2.
             * When a UAC receives a response that establishes a dialog, it
             * constructs the state of the dialog.  This state MUST be maintained
             * for the duration of the dialog.
             *
             * If the request was sent over TLS, and the Request-URI contained a
             * SIPS URI, the "secure" flag is set to TRUE.
             *
             * The route set MUST be set to the list of URIs in the Record-Route
             * header field from the response, taken in reverse order and preserving
             * all URI parameters.  If no Record-Route header field is present in
             * the response, the route set MUST be set to the empty set.  This route
             * set, even if empty, overrides any pre-existing route set for future
             * requests in this dialog.  The remote target MUST be set to the URI
             * from the Contact header field of the response.
             *
             * The local sequence number MUST be set to the value of the sequence
             * number in the CSeq header field of the request.  The remote sequence
             * number MUST be empty (it is established when the remote UA sends a
             * request within the dialog).  The call identifier component of the
             * dialog ID MUST be set to the value of the Call-ID in the request.
             * The local tag component of the dialog ID MUST be set to the tag in
             * the From field in the request, and the remote tag component of the
             * dialog ID MUST be set to the tag in the To field of the response.  A
             * UAC MUST be prepared to receive a response without a tag in the To
             * field, in which case the tag is considered to have a value of null.
             *
             *  This is to maintain backwards compatibility with RFC 2543, which
             *  did not mandate To tags.
             *
             * The remote URI MUST be set to the URI in the To field, and the local
             * URI MUST be set to the URI in the From field.
             */

            else
            {
                // TODO: Validate request or client transaction must do it ?

                m_IsSecure      = ((SIP_Uri)transaction.Request.RequestLine.Uri).IsSecure;
                m_pRouteSet     = (SIP_t_AddressParam[])Core.ReverseArray(response.RecordRoute.GetAllValues());
                m_pRemoteTarget = (SIP_Uri)response.Contact.GetTopMostValue().Address.Uri;
                m_LocalSeqNo    = transaction.Request.CSeq.SequenceNumber;
                m_RemoteSeqNo   = 0;
                m_CallID        = transaction.Request.CallID;
                m_LocalTag      = transaction.Request.From.Tag;
                m_RemoteTag     = response.To.Tag;
                m_pRemoteUri    = transaction.Request.To.Address.Uri;
                m_pLocalUri     = transaction.Request.From.Address.Uri;
                m_pLocalContact = (SIP_Uri)transaction.Request.Contact.GetTopMostValue().Address.Uri;
            }

            #endregion

            m_pFlow = transaction.Flow;
        }
コード例 #51
0
        // FIX ME:

        /// <summary>
        /// Raises ResponseReceived event.
        /// </summary>
        /// <param name="response">SIP response received.</param>
        private void OnResponseReceived(SIP_Response response)
        {
            if (ResponseReceived != null)
            {
                ResponseReceived(this, new SIP_ResponseReceivedEventArgs(Stack, this, response));
            }
        }