/// <summary>
 /// Raises event <b>Error</b>.
 /// </summary>
 /// <param name="e">Event data.</param>
 private void OnError(SIP_ResponseReceivedEventArgs e)
 {
     if (this.Error != null)
     {
         this.Error(this, e);
     }
 }
        /// <summary>
        /// This method is called when REGISTER has finished.
        /// </summary>
        /// <param name="sender">Sender.</param>
        /// <param name="e">Event data.</param>
        private void m_pRegisterSender_ResponseReceived(object sender, SIP_ResponseReceivedEventArgs e)
        {
            m_pFlow = e.ClientTransaction.Flow;

            if (e.Response.StatusCodeType == SIP_StatusCodeType.Success)
            {
                SetState(SIP_UA_RegistrationState.Registered);

                OnRegistered();

                m_pFlow.SendKeepAlives = true;
            }
            else
            {
                SetState(SIP_UA_RegistrationState.Error);

                OnError(e);
            }

            // REMOVE ME:
            if (this.AutoFixContact && (m_pContact is SIP_Uri))
            {
                // If Via: received or rport paramter won't match to our sent-by, use received and rport to construct new contact value.

                SIP_Uri       cContact   = ((SIP_Uri)m_pContact);
                IPAddress     cContactIP = Net_Utils.IsIPAddress(cContact.Host) ? IPAddress.Parse(cContact.Host) : null;
                SIP_t_ViaParm via        = e.Response.Via.GetTopMostValue();
                if (via != null && cContactIP != null)
                {
                    IPEndPoint ep = new IPEndPoint(via.Received != null ? via.Received : cContactIP, via.RPort > 0 ? via.RPort : cContact.Port);
                    if (!cContactIP.Equals(ep.Address) || cContact.Port != via.RPort)
                    {
                        // Unregister old contact.
                        BeginUnregister(false);

                        // Fix contact.
                        cContact.Host = ep.Address.ToString();
                        cContact.Port = ep.Port;

                        m_pRegisterSender.Dispose();
                        m_pRegisterSender = null;

                        BeginRegister(m_AutoRefresh);

                        return;
                    }
                }
            }

            if (m_AutoRefresh)
            {
                // Set registration refresh timer.
                m_pTimer.Enabled = true;
            }

            m_pRegisterSender.Dispose();
            m_pRegisterSender = null;
        }
        /// <summary>
        /// This method is called when un-REGISTER has finished.
        /// </summary>
        /// <param name="sender">Sender.</param>
        /// <param name="e">Event data.</param>
        private void m_pUnregisterSender_ResponseReceived(object sender, SIP_ResponseReceivedEventArgs e)
        {
            SetState(SIP_UA_RegistrationState.Unregistered);
            OnUnregistered();

            if (m_AutoDispose)
            {
                Dispose();
            }

            m_pUnregisterSender = null;
        }
Exemple #4
0
 /// <summary>
 /// This method is called when new response is received.
 /// </summary>
 /// <param name="e">Response event arguments.</param>
 internal void OnResponseReceived(SIP_ResponseReceivedEventArgs e)
 {
     // If we get response here, that means we have stray response, just do nothing.
     // All reponses must match to transactions, so we never should reach here.
 }
 /// <summary>
 /// Is called when client transactions receives response.
 /// </summary>
 /// <param name="e">Event data.</param>
 private void ClientTransaction_ResponseReceived(SIP_ResponseReceivedEventArgs e)
 {
     ProcessResponse(e.Response);
 }
Exemple #6
0
 /// <summary>
 /// Raises event <b>Error</b>.
 /// </summary>
 /// <param name="e">Event data.</param>
 private void OnError(SIP_ResponseReceivedEventArgs e)
 {
     if(this.Error != null){
         this.Error(this,e);
     }
 }
Exemple #7
0
        /// <summary>
        /// This method is called when un-REGISTER has finished.
        /// </summary>
        /// <param name="sender">Sender.</param>
        /// <param name="e">Event data.</param>
        private void m_pUnregisterSender_ResponseReceived(object sender,SIP_ResponseReceivedEventArgs e)
        {
            SetState(SIP_UA_RegistrationState.Unregistered);
            OnUnregistered();

            if(m_AutoDispose){
                Dispose();
            }

            m_pUnregisterSender = null;
        }
Exemple #8
0
        /// <summary>
        /// This method is called when REGISTER has finished.
        /// </summary>
        /// <param name="sender">Sender.</param>
        /// <param name="e">Event data.</param>
        private void m_pRegisterSender_ResponseReceived(object sender,SIP_ResponseReceivedEventArgs e)
        {   
            m_pFlow = e.ClientTransaction.Flow;
       
            if(e.Response.StatusCodeType == SIP_StatusCodeType.Provisional){
                return;
            }
            else if(e.Response.StatusCodeType == SIP_StatusCodeType.Success){
                m_pContacts.Clear();
                foreach(SIP_t_ContactParam c in e.Response.Contact.GetAllValues()){
                    m_pContacts.Add(c.Address.Uri);
                }

                SetState(SIP_UA_RegistrationState.Registered);
                                             
                OnRegistered();

                m_pFlow.SendKeepAlives = true;
            }
            else{
                SetState(SIP_UA_RegistrationState.Error);

                OnError(e);
            }

            // REMOVE ME:
            if(this.AutoFixContact && (m_pContact is SIP_Uri)){
                // If Via: received or rport paramter won't match to our sent-by, use received and rport to construct new contact value.
                   
                SIP_Uri       cContact    = ((SIP_Uri)m_pContact);
                IPAddress     cContactIP  = Net_Utils.IsIPAddress(cContact.Host) ? IPAddress.Parse(cContact.Host) : null;
                SIP_t_ViaParm via         = e.Response.Via.GetTopMostValue();
                if(via != null && cContactIP != null){
                    IPEndPoint ep = new IPEndPoint(via.Received != null ? via.Received : cContactIP,via.RPort > 0 ? via.RPort : cContact.Port);
                    if(!cContactIP.Equals(ep.Address) || cContact.Port != via.RPort){
                        // Unregister old contact.
                        BeginUnregister(false);

                        // Fix contact.
                        cContact.Host = ep.Address.ToString();
                        cContact.Port = ep.Port;

                        m_pRegisterSender.Dispose();
                        m_pRegisterSender = null;
                                                
                        BeginRegister(m_AutoRefresh);

                        return;
                    }
                }
            }

            if(m_AutoRefresh){
                // Set registration refresh timer.
                m_pTimer.Enabled = true;
            }

            m_pRegisterSender.Dispose();
            m_pRegisterSender = null;
        }
Exemple #9
0
        /// <summary>
        /// This method is called when initial INVITE sender got response.
        /// </summary>
        /// <param name="sender">Sender.</param>
        /// <param name="e">Event data.</param>
        private void m_pInitialInviteSender_ResponseReceived(object sender,SIP_ResponseReceivedEventArgs e)
        {          
            try{
                lock(m_pLock){
                    // If remote party provided SDP, parse it.               
                    if(e.Response.ContentType != null && e.Response.ContentType.ToLower().IndexOf("application/sdp") > -1){
                        m_pRemoteSDP = SDP_Message.Parse(Encoding.UTF8.GetString(e.Response.Data));

                        // TODO: If parsing failed, end call.
                    }

                    if(e.Response.StatusCodeType == SIP_StatusCodeType.Provisional){
                        if(e.Response.StatusCode == 180){
                            SetState(SIP_UA_CallState.Ringing);
                        }
                        else if(e.Response.StatusCode == 182){
                            SetState(SIP_UA_CallState.Queued);
                        }
                        // We don't care other status responses.

                        /* RFC 3261 13.2.2.1.
                            Zero, one or multiple provisional responses may arrive before one or
                            more final responses are received.  Provisional responses for an
                            INVITE request can create "early dialogs".  If a provisional response
                            has a tag in the To field, and if the dialog ID of the response does
                            not match an existing dialog, one is constructed using the procedures
                            defined in Section 12.1.2.
                        */
                        if(e.Response.StatusCode > 100 && e.Response.To.Tag != null){
                            m_pEarlyDialogs.Add((SIP_Dialog_Invite)m_pUA.Stack.TransactionLayer.GetOrCreateDialog(e.ClientTransaction,e.Response));
                        }
                    }
                    else if(e.Response.StatusCodeType == SIP_StatusCodeType.Success){
                        m_StartTime = DateTime.Now;
                        SetState(SIP_UA_CallState.Active);

                        m_pDialog = m_pUA.Stack.TransactionLayer.GetOrCreateDialog(e.ClientTransaction,e.Response);
                        m_pDialog.StateChanged += new EventHandler(m_pDialog_StateChanged);

                        /* Exit all all other dialogs created by this call (due to forking).
                           That is not defined in RFC but, since UAC can send BYE to early and confirmed dialogs, 
                           because of this all 100% valid.
                        */
                        foreach(SIP_Dialog_Invite dialog in m_pEarlyDialogs.ToArray()){
                            if(!m_pDialog.Equals(dialog)){
                                dialog.Terminate("Another forking leg accepted.",true);
                            }
                        }
                    }
                    else{
                        /* RFC 3261 13.2.2.3.
                            All early dialogs are considered terminated upon reception of the non-2xx final response.
                        */
                        foreach(SIP_Dialog_Invite dialog in m_pEarlyDialogs.ToArray()){
                            dialog.Terminate("All early dialogs are considered terminated upon reception of the non-2xx final response. (RFC 3261 13.2.2.3)",false);
                        }
                        m_pEarlyDialogs.Clear();

                        Error();

                        SetState(SIP_UA_CallState.Terminated);                
                    }
                }
            }
            catch(Exception x){  
                m_pUA.Stack.OnError(x);            
            }

        }
 /// <summary>
 /// This method is called when caller dialog client transaction receives response.
 /// </summary>
 /// <param name="sender">Sender.</param>
 /// <param name="e">Event data.</param>
 private void m_pCaller_ResponseReceived(object sender,SIP_ResponseReceivedEventArgs e)
 {
     SIP_ServerTransaction serverTransaction = (SIP_ServerTransaction)e.ClientTransaction.Tag;
     //SIP_Response response = serverTransaction.Request.CreateResponse(e.Response.StatusCode_ReasonPhrase);
     //CopyMessage(e.Response,response,new string[]{"Via:","Call-Id:","To:","From:","CSeq:","Contact:","Route:","Record-Route:","Allow:","Supported:"});
     //serverTransaction.SendResponse(response);
 }
            /// <summary>
            /// Is called when client transactions receives response.
            /// </summary>
            /// <param name="sender">Sender.</param>
            /// <param name="e">Event data.</param>
            private void ClientTransaction_ResponseReceived(object sender,SIP_ResponseReceivedEventArgs e)
            {
                lock(m_pLock){
                    m_HasReceivedResponse = true;

                    /* RFC 3261 16.7 Response Processing.
                        1.  Find the appropriate response context
                        2.  Update timer C for provisional responses

                        Steps 3 - 10 done in ProxyContext.ProcessResponse method.
                    */

                    #region 1. Find Context

                    // Done, m_pOwner is it.

                    #endregion

                    #region 2. Update timer C for provisional responses

                    /* For an INVITE transaction, if the response is a provisional
                       response with status codes 101 to 199 inclusive (i.e., anything
                       but 100), the proxy MUST reset timer C for that client
                       transaction.  The timer MAY be reset to a different value, but
                       this value MUST be greater than 3 minutes.
                    */
                    if(m_pTimerC != null && e.Response.StatusCode >= 101 && e.Response.StatusCode <= 199){
                        m_pTimerC.Interval = 3 * 60 * 1000;
                    }

                    #endregion

                    /*
                    // If 401 or 407 (Authentication required), see i we have specified realm(s) credentials,
                    // if so try to authenticate.
                    if(e.Response.StatusCode == 401 || e.Response.StatusCode == 407){
                        SIP_t_Challenge[] challanges = null;
                        if(e.Response.StatusCode == 401){
                            challanges = e.Response.WWWAuthenticate.GetAllValues();
                        }
                        else{
                            challanges = e.Response.ProxyAuthenticate.GetAllValues();
                        }

                        // TODO: Porbably we need to auth only if we can provide authentication data to all realms ?

                        SIP_Request request = m_pServerTransaction.Request.Copy();
                        request.CSeq.SequenceNumber++;
                        bool hasAny = false;
                        foreach(SIP_t_Challenge challange in challanges){
                            Auth_HttpDigest authDigest = new Auth_HttpDigest(challange.AuthData,m_pServerTransaction.Request.Method);
                            NetworkCredential credential = GetCredential(authDigest.Realm);
                            if(credential != null){
                                // Don't authenticate again, if we tried already once and failed.
                                // FIX ME: if user passed authorization, then works wrong.
                                if(e.ClientTransaction.Request.Authorization.Count == 0 && e.ClientTransaction.Request.ProxyAuthorization.Count == 0){
                                    authDigest.RequestMethod = m_pServerTransaction.Request.Method;
                                    authDigest.Uri           = e.ClientTransaction.Request.Uri;
                                    authDigest.Realm         = credential.Domain;
                                    authDigest.UserName      = credential.UserName;
                                    authDigest.Password      = credential.Password;
                                    authDigest.CNonce        = Auth_HttpDigest.CreateNonce();
                                    authDigest.Qop           = authDigest.Qop;
                                    authDigest.Opaque        = authDigest.Opaque;
                                    authDigest.Algorithm     = authDigest.Algorithm;
                                    if(e.Response.StatusCode == 401){
                                        request.Authorization.Add(authDigest.ToAuthorization());
                                    }
                                    else{
                                        request.ProxyAuthorization.Add(authDigest.ToAuthorization());
                                    }
                                    hasAny = true;
                                }
                            }
                        }
                        if(hasAny){
                            // CreateClientTransaction((SIP_Target)e.ClientTransaction.Tag,request);
                            return;
                        }
                    }*/

                    if(e.Response.StatusCodeType != SIP_StatusCodeType.Provisional){
                        m_IsCompleted = true;
                    }

                    m_pOwner.ProcessResponse(this,m_pTransaction,e.Response);
                }
            }
        /// <summary>
        /// Is called when client transactions receives response.
        /// </summary>
        /// <param name="sender">Sender.</param>
        /// <param name="e">Event data.</param>
        private void ClientTransaction_ResponseReceived(object sender,SIP_ResponseReceivedEventArgs e)
        {                              
            lock(m_pLock){
                m_pFlow = e.ClientTransaction.Request.Flow;

                if(e.Response.StatusCode == 401 || e.Response.StatusCode == 407){
                    // Check if authentication failed(We sent authorization data and it's challenged again, 
                    // probably user name or password inccorect)
                    bool hasFailedAuthorization = false;
                    foreach(SIP_t_Challenge challange in e.Response.WWWAuthenticate.GetAllValues()){
                        foreach(SIP_t_Credentials credentials in m_pTransaction.Request.Authorization.GetAllValues()){
                            if(new Auth_HttpDigest(challange.AuthData,"").Realm == new Auth_HttpDigest(credentials.AuthData,"").Realm){
                                hasFailedAuthorization = true;
                                break;
                            }
                        }
                    }
                    foreach(SIP_t_Challenge challange in e.Response.ProxyAuthenticate.GetAllValues()){
                        foreach(SIP_t_Credentials credentials in m_pTransaction.Request.ProxyAuthorization.GetAllValues()){
                            if(new Auth_HttpDigest(challange.AuthData,"").Realm == new Auth_HttpDigest(credentials.AuthData,"").Realm){
                                hasFailedAuthorization = true;
                                break;
                            }
                        }
                    }

                    // Authorization failed, pass response to UA.
                    if(hasFailedAuthorization){
                        OnResponseReceived(e.Response);
                    }
                    // Try to authorize challanges.
                    else{
                        SIP_Request request = m_pRequest.Copy();

                        /* RFC 3261 22.2.
                            When a UAC resubmits a request with its credentials after receiving a
                            401 (Unauthorized) or 407 (Proxy Authentication Required) response,
                            it MUST increment the CSeq header field value as it would normally
                            when sending an updated request.
                        */
                        request.CSeq = new SIP_t_CSeq(m_pStack.ConsumeCSeq(),request.CSeq.RequestMethod);

                        // All challanges authorized, resend request.
                        if(Authorize(request,e.Response,this.Credentials.ToArray())){
                            SIP_Flow flow  = m_pTransaction.Flow;
                            CleanUpActiveTransaction();            
                            SendToFlow(flow,request);
                        }
                        // We don't have credentials for one or more challenges.
                        else{
                            OnResponseReceived(e.Response);
                        }
                    }                   
                }
                else{
                    OnResponseReceived(e.Response);
                    if(e.Response.StatusCodeType != SIP_StatusCodeType.Provisional){
                        OnCompleted();
                    }
                }
            }
        }
 /// <summary>
 /// This method is called when new response is received.
 /// </summary>
 /// <param name="e">Response event arguments.</param>
 public virtual void OnResponseReceived(SIP_ResponseReceivedEventArgs e)
 {
 }
Exemple #14
0
        /// <summary>
        /// This method is called when new response is received.
        /// </summary>
        /// <param name="e">Response event arguments.</param>
        private void OnResponseReceived(SIP_ResponseReceivedEventArgs e)
        {
            if((m_ProxyMode & SIP_ProxyMode.B2BUA) != 0){
                m_pB2BUA.OnResponseReceived(e);
            }
            else if((m_ProxyMode & SIP_ProxyMode.Statefull) != 0){
                /* RFC 6026 7.3. Proxy Considerations.
                    This document changes the behavior of transaction-stateful proxies to
                    not forward stray INVITE responses.  When receiving any SIP response,
                    a transaction-stateful proxy MUST compare the transaction identifier
                    in that response against its existing transaction state machines.
                    The proxy MUST NOT forward the response if there is no matching
                    transaction state machine.
                */
            }
            else{
                /* This method is called when stateless proxy gets response.
                */
                               
                /* RFC 3261 16.11.
                    When a response arrives at a stateless proxy, the proxy MUST inspect the sent-by 
                    value in the first (topmost) Via header field value. If that address matches the proxy,
                    (it equals a value this proxy has inserted into previous requests) the proxy MUST 
                    remove that header field value from the response and forward the result to the 
                    location indicated in the next Via header field value.
                */
                // Just remove topmost Via:, sent-by check is done in transport layer.
                e.Response.Via.RemoveTopMostValue();

                if((m_ProxyMode & SIP_ProxyMode.Statefull) != 0){
                    // We should not reach here. This happens when no matching client transaction found.
                    // RFC 3161 18.1.2 orders to forward them statelessly.
                    m_pStack.TransportLayer.SendResponse(e.Response);
                }
                else if((m_ProxyMode & SIP_ProxyMode.Stateless) != 0){
                    m_pStack.TransportLayer.SendResponse(e.Response);
                }
            }
        }
Exemple #15
0
 /// <summary>
 /// This method is called when SIP stack receives new response.
 /// </summary>
 /// <param name="sender">Sender.</param>
 /// <param name="e">Event data.</param>
 private void m_pStack_ResponseReceived(object sender,SIP_ResponseReceivedEventArgs e)
 {
     OnResponseReceived(e);            
 }
        /// <summary>
        /// Is called when client transactions receives response.
        /// </summary>
        /// <param name="sender">Sender.</param>
        /// <param name="e">Event data.</param>
        private void ClientTransaction_ResponseReceived(object sender, SIP_ResponseReceivedEventArgs e)
        {
            lock (m_pLock){
                m_pFlow = e.ClientTransaction.Request.Flow;

                if (e.Response.StatusCode == 401 || e.Response.StatusCode == 407)
                {
                    // Check if authentication failed(We sent authorization data and it's challenged again,
                    // probably user name or password inccorect)
                    bool hasFailedAuthorization = false;
                    foreach (SIP_t_Challenge challange in e.Response.WWWAuthenticate.GetAllValues())
                    {
                        foreach (SIP_t_Credentials credentials in m_pTransaction.Request.Authorization.GetAllValues())
                        {
                            if (new Auth_HttpDigest(challange.AuthData, "").Realm == new Auth_HttpDigest(credentials.AuthData, "").Realm)
                            {
                                hasFailedAuthorization = true;
                                break;
                            }
                        }
                    }
                    foreach (SIP_t_Challenge challange in e.Response.ProxyAuthenticate.GetAllValues())
                    {
                        foreach (SIP_t_Credentials credentials in m_pTransaction.Request.ProxyAuthorization.GetAllValues())
                        {
                            if (new Auth_HttpDigest(challange.AuthData, "").Realm == new Auth_HttpDigest(credentials.AuthData, "").Realm)
                            {
                                hasFailedAuthorization = true;
                                break;
                            }
                        }
                    }

                    // Authorization failed, pass response to UA.
                    if (hasFailedAuthorization)
                    {
                        OnResponseReceived(e.Response);
                    }
                    // Try to authorize challanges.
                    else
                    {
                        SIP_Request request = m_pRequest.Copy();

                        /* RFC 3261 22.2.
                         *  When a UAC resubmits a request with its credentials after receiving a
                         *  401 (Unauthorized) or 407 (Proxy Authentication Required) response,
                         *  it MUST increment the CSeq header field value as it would normally
                         *  when sending an updated request.
                         */
                        request.CSeq = new SIP_t_CSeq(m_pStack.ConsumeCSeq(), request.CSeq.RequestMethod);

                        // All challanges authorized, resend request.
                        if (Authorize(request, e.Response, this.Credentials.ToArray()))
                        {
                            SIP_Flow flow = m_pTransaction.Flow;
                            CleanUpActiveTransaction();
                            SendToFlow(flow, request);
                        }
                        // We don't have credentials for one or more challenges.
                        else
                        {
                            OnResponseReceived(e.Response);
                        }
                    }
                }
                else
                {
                    OnResponseReceived(e.Response);
                    if (e.Response.StatusCodeType != SIP_StatusCodeType.Provisional)
                    {
                        OnCompleted();
                    }
                }
            }
        }
Exemple #17
0
 /// <summary>
 /// Raises <b>ResponseReceived</b> event.
 /// </summary>
 /// <param name="e">Event data.</param>
 internal void OnResponseReceived(SIP_ResponseReceivedEventArgs e)
 {
     if(this.ResponseReceived != null){
         this.ResponseReceived(this,e);
     }
 }