Ejemplo n.º 1
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>
        internal protected virtual bool ProcessResponse(SIP_Response response)
        {
            if (response == null)
            {
                throw new ArgumentNullException("response");
            }

            return(false);
        }
Ejemplo n.º 2
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();
                    }
                    else if (response.CSeq.RequestMethod.ToUpper() == SIP_Methods.REFER)
                    {
                        dialog = new SIP_Dialog_Refer();
                    }
                    else
                    {
                        throw new ArgumentException("Method '" + response.CSeq.RequestMethod + "' has no dialog handler.");
                    }

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

                return(dialog);
            }
        }
Ejemplo n.º 3
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);
            }
        }
Ejemplo n.º 4
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;
        }
Ejemplo n.º 5
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(this.GetType().Name);
                }
                if (response == null)
                {
                    throw new ArgumentNullException("response");
                }

                SendInternal(response.ToByteData());
                m_LastPing = DateTime.Now;
            }
        }
Ejemplo n.º 6
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 char[] { ' ' }, 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], System.Globalization.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);
        }
Ejemplo n.º 7
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, System.Timers.ElapsedEventArgs e)
        {
            lock (this.SyncRoot){
                // RFC 3261 17.2.1. TU didn't generate response in 200 ms, send '100 Trying' to stop request retransmission.
                if (this.State == SIP_TransactionState.Proceeding && this.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 = this.Stack.CreateResponse(SIP_ResponseCodes.x100_Trying, this.Request);
                    if (this.Request.Timestamp != null)
                    {
                        tryingResponse.Timestamp = new SIP_t_Timestamp(this.Request.Timestamp.Time, (DateTime.Now - this.CreateTime).Seconds);
                    }

                    try{
                        this.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;
                }
            }
        }
Ejemplo n.º 8
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);
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Clones this request.
        /// </summary>
        /// <returns>Returns new cloned request.</returns>
        public SIP_Response Copy()
        {
            SIP_Response retVal = SIP_Response.Parse(this.ToByteData());

            return(retVal);
        }
Ejemplo n.º 10
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>
        internal protected 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)
            {
                m_IsSecure      = ((SIP_Uri)transaction.Request.RequestLine.Uri).IsSecure;
                m_pRouteSet     = (SIP_t_AddressParam[])Net_Utils.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;

                List <string> allow = new List <string>();
                foreach (SIP_t_Method m in response.Allow.GetAllValues())
                {
                    allow.Add(m.Method);
                }
                m_pRemoteAllow = allow.ToArray();

                List <string> supported = new List <string>();
                foreach (SIP_t_OptionTag s in response.Supported.GetAllValues())
                {
                    supported.Add(s.OptionTag);
                }
                m_pRemoteSupported = supported.ToArray();
            }

            #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[])Net_Utils.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;

                List <string> allow = new List <string>();
                foreach (SIP_t_Method m in response.Allow.GetAllValues())
                {
                    allow.Add(m.Method);
                }
                m_pRemoteAllow = allow.ToArray();

                List <string> supported = new List <string>();
                foreach (SIP_t_OptionTag s in response.Supported.GetAllValues())
                {
                    supported.Add(s.OptionTag);
                }
                m_pRemoteSupported = supported.ToArray();
            }

            #endregion

            m_pFlow = transaction.Flow;
            AddTransaction(transaction);
        }
Ejemplo n.º 11
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 (this.SyncRoot){
                if (this.State == SIP_TransactionState.Disposed)
                {
                    return;
                }

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

                        this.Stack.Logger.AddRead(
                            Guid.NewGuid().ToString(),
                            null,
                            0,
                            "Request [transactionID='" + this.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 (this.Method == SIP_Methods.INVITE)
                    {
                        #region INVITE

                        if (request.RequestLine.Method == SIP_Methods.INVITE)
                        {
                            if (this.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 = this.LastProvisionalResponse;
                                if (response != null)
                                {
                                    this.Stack.TransportLayer.SendResponse(this, response);
                                }
                            }
                            else if (this.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.
                                 */
                                this.Stack.TransportLayer.SendResponse(this, this.FinalResponse);
                            }
                        }

                        #endregion

                        #region ACK

                        else if (request.RequestLine.Method == SIP_Methods.ACK)
                        {
                            #region Accepeted

                            if (this.State == SIP_TransactionState.Accpeted)
                            {
                            }

                            #endregion

                            #region Completed

                            else if (this.State == SIP_TransactionState.Completed)
                            {
                                /* 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.
                                 */

                                SetState(SIP_TransactionState.Confirmed);

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

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

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

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

                            #endregion
                        }

                        #endregion
                    }

                    #endregion

                    #region Non-INVITE

                    else
                    {
                        // Non-INVITE transaction may have only request retransmission requests.
                        if (this.Method == request.RequestLine.Method)
                        {
                            if (this.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.
                                 */
                                this.Stack.TransportLayer.SendResponse(this, this.LastProvisionalResponse);
                            }
                            else if (this.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.
                                 */
                                this.Stack.TransportLayer.SendResponse(this, this.FinalResponse);
                            }
                        }
                    }

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

                    OnTransportError(x);
                }
            }
        }
Ejemplo n.º 12
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 (this.SyncRoot){
                if (this.State == SIP_TransactionState.Disposed)
                {
                    throw new ObjectDisposedException(this.GetType().Name);
                }
                if (response == null)
                {
                    throw new ArgumentNullException("response");
                }

                try{
                    #region INVITE

                    /* RFC 6026 7.1. INVITE server transaction. (Udpates RFC 3261)
                     *
                     |INVITE
                     |pass INV to TU
                     *                    INVITE             V send 100 if TU won't in 200 ms
                     *                    send response+------------+
                     +--------|            |--------+ 101-199 from TU
                     |        |            |        | send response
                     +------->|            |<-------+
                     | Proceeding |
                     |            |--------+ 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 |<-------+      INVITE  |  Transport Err.
                     |           |               -       |  Inform TU
                     +--------|           |----+          +-----+ |  +---+
                     |        +-----------+    | ACK      |     | v  |   v
                     |          ^   |          | -        |  +------------+
                     |          |   |          |          |  |            |---+ ACK
                     +----------+   |          |          +->|  Accepted  |   | to TU
                     |         Transport Err. |          |             |            |<--+
                     |         Inform TU      |          V             +------------+
                     |      +-----------+        |  ^     |
                     |      |           |        |  |     |
                     |      | Confirmed |        |  +-----+
                     |      |           |        |  2xx from TU
                     |          Timer H fires |      +-----------+        |  send response
                     |          -             |          |                |
                     |          | Timer I fires  |
                     |          | -              | Timer L fires
                     |          V                | -
                     |        +------------+     |
                     |        |            |<----+
                     +------->| Terminated |
                     |            |
                     +------------+
                     |
                     */

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

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

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

                                /* RFC 6025 7.1.
                                 *  When the "Accepted" state is entered, timer L MUST be set to fire in 64*T1.
                                 */
                                m_pTimerL          = new TimerEx(64 * SIP_TimerConstants.T1);
                                m_pTimerL.Elapsed += new System.Timers.ElapsedEventHandler(m_pTimerL_Elapsed);
                                m_pTimerL.Enabled  = true;

                                // Log
                                if (this.Stack.Logger != null)
                                {
                                    this.Stack.Logger.AddText(this.ID, "Transaction [branch='" + this.ID + "';method='" + this.Method + "';IsServer=true] timer L(ACK wait) started, will trigger after " + m_pTimerL.Interval + ".");
                                }
                            }
                            // 3xx - 6xx
                            else
                            {
                                this.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 (!this.Flow.IsReliable)
                                {
                                    m_pTimerG          = new TimerEx(SIP_TimerConstants.T1, false);
                                    m_pTimerG.Elapsed += new System.Timers.ElapsedEventHandler(m_pTimerG_Elapsed);
                                    m_pTimerG.Enabled  = true;

                                    // Log
                                    if (this.Stack.Logger != null)
                                    {
                                        this.Stack.Logger.AddText(this.ID, "Transaction [branch='" + this.ID + "';method='" + this.Method + "';IsServer=true] timer G(INVITE response(3xx - 6xx) retransmission) started, will trigger 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 += new System.Timers.ElapsedEventHandler(m_pTimerH_Elapsed);
                                m_pTimerH.Enabled  = true;

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

                        #endregion

                        #region Accepted

                        else if (this.State == SIP_TransactionState.Accpeted)
                        {
                            this.Stack.TransportLayer.SendResponse(this, response);
                            OnResponseSent(response);
                        }

                        #endregion

                        #region Completed

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

                        #endregion

                        #region Confirmed

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

                        #endregion

                        #region Terminated

                        else if (this.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 (this.State == SIP_TransactionState.Trying)
                        {
                            AddResponse(response);

                            // 1xx
                            if (response.StatusCodeType == SIP_StatusCodeType.Provisional)
                            {
                                this.Stack.TransportLayer.SendResponse(this, response);
                                OnResponseSent(response);
                                SetState(SIP_TransactionState.Proceeding);
                            }
                            // 2xx - 6xx
                            else
                            {
                                this.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 += new System.Timers.ElapsedEventHandler(m_pTimerJ_Elapsed);
                                m_pTimerJ.Enabled  = true;

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

                        #endregion

                        #region Proceeding

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

                            // 1xx
                            if (response.StatusCodeType == SIP_StatusCodeType.Provisional)
                            {
                                this.Stack.TransportLayer.SendResponse(this, response);
                                OnResponseSent(response);
                            }
                            // 2xx - 6xx
                            else
                            {
                                this.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 += new System.Timers.ElapsedEventHandler(m_pTimerJ_Elapsed);
                                m_pTimerJ.Enabled  = true;

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

                        #endregion

                        #region Completed

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

                        #endregion

                        #region Terminated

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

                        #endregion
                    }

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

                    OnTransportError(x);
                }
            }
        }
Ejemplo n.º 13
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>
        internal protected 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);
                }
                else if (response.StatusCodeType == SIP_StatusCodeType.Provisional)
                {
                    SetState(SIP_DialogState.Early, false);

                    m_pActiveInvite = transaction;
                    m_pActiveInvite.StateChanged += delegate(object s, EventArgs a){
                        if (m_pActiveInvite != null && m_pActiveInvite.State == SIP_TransactionState.Terminated)
                        {
                            m_pActiveInvite = null;

                            /* RFC 3261 13.3.1.4.
                             *  If the server retransmits the 2xx response for 64*T1 seconds without
                             *  receiving an ACK, the dialog is confirmed, but the session SHOULD be
                             *  terminated.
                             */
                            if (this.State == SIP_DialogState.Early)
                            {
                                this.SetState(SIP_DialogState.Confirmed, true);
                                Terminate("ACK was not received for initial INVITE 2xx response.", true);
                            }
                            else if (this.State == SIP_DialogState.Terminating)
                            {
                                this.SetState(SIP_DialogState.Confirmed, false);
                                Terminate(m_TerminateReason, true);
                            }
                        }
                    };
                }
                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);
                }
                else if (response.StatusCodeType == SIP_StatusCodeType.Provisional)
                {
                    SetState(SIP_DialogState.Early, false);

                    m_pActiveInvite = transaction;
                    m_pActiveInvite.StateChanged += delegate(object s, EventArgs a){
                        if (m_pActiveInvite != null && m_pActiveInvite.State == SIP_TransactionState.Terminated)
                        {
                            m_pActiveInvite = null;
                        }
                    };

                    // Once we receive 2xx response, dialog will switch to confirmed state.
                    ((SIP_ClientTransaction)transaction).ResponseReceived += delegate(object s, SIP_ResponseReceivedEventArgs a){
                        if (a.Response.StatusCodeType == SIP_StatusCodeType.Success)
                        {
                            SetState(SIP_DialogState.Confirmed, true);
                        }
                    };
                }
                else
                {
                    throw new ArgumentException("Argument 'response' has invalid status code, 1xx - 2xx is only allowed.");
                }
            }
        }
Ejemplo n.º 14
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();
                    authDigest.Uri      = request.RequestLine.Uri.ToString();

                    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();
                    authDigest.Uri      = request.RequestLine.Uri.ToString();

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

            #endregion

            return(allAuthorized);
        }
Ejemplo n.º 15
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;
 }