Status Codes: 1xx: Provisional -- request received, continuing to process the request; 2xx: Success -- the action was successfully received, understood, and accepted; 3xx: Redirection -- further action needs to be taken in order to complete the request; 4xx: Client Error -- the request contains bad syntax or cannot be fulfilled at this server; 5xx: Server Error -- the server failed to fulfill an apparently valid request; 6xx: Global Failure -- the request cannot be fulfilled at any server.
 private void SIPCancelTransaction_TransactionFinalResponseReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPResponse sipResponse)
 {
     if (sipResponse.StatusCode < 200)
     {
         logger.Warn("A SIP CANCEL transaction received an unexpected SIP information response " + sipResponse.ReasonPhrase + ".");
     }
     else
     {
         if (CancelTransactionFinalResponseReceived != null)
         {
             CancelTransactionFinalResponseReceived(localSIPEndPoint, remoteEndPoint, sipTransaction, sipResponse);
         }
     }
 }
        public static bool IsMagicJackRequest(SIPResponse sipResponse) {
            if (sipResponse.Header.AuthenticationHeader != null &&
                sipResponse.Header.AuthenticationHeader.SIPDigest.Realm == "stratus.com" &&
                sipResponse.Header.To != null && 
                sipResponse.Header.To.ToURI != null &&
                sipResponse.Header.To.ToURI.Host.ToLower() == "talk4free.com") {
                return true;
            }

            return false;
        }
        /// <summary>
        /// MagicJack apply a custom algorithm when calculating their nonce seemingly in order to
        /// prevent other SIP UAs from being able to authenticate. This method attempts to apply the same
        /// algorithm to allow the authenticated requests from this stack.
        /// </summary>
        /// <remarks>
        /// MJ is modifying the nonce dynamically. They append an underscore, then 8 characters to the nonce before computing the MD5. The 8 characters come from the call id. 
        /// Use the first 8 bytes of the nonce as an index into your call id. 
        /// Assume your callid is: 
        /// callid: 9876ABC56738DD43... 
        /// index:  0123456789ABCDEF
        /// and your nonce is: 8765abc4_32190
        /// Take the first digit of your nonce (which in our example is 8 ), and find the value in the callid at index 8, which is 6. 
        /// So, append that to the nonce. 8765abc4_32190_6 
        /// Then move on to the second digit of the nonce, which is 7 in our example. Find the value at index 7 in the callid, which is 5, and append that: 
        /// 8765abc4_32190_65 continue until you have done 8 digits. Your new nonce would be: 
        /// 8765abc4_32190_65CB38DA Use this value when computing the MD5, but pass the original nonce to magicJack. 
        /// </remarks>
        /// <param name="authReqdResponse"></param>
        /// <returns></returns>
        public static SIPAuthenticationHeader GetAuthenticationHeader(SIPResponse authReqdResponse) {
            try {
                SIPAuthenticationHeader mjAuthHeader = new SIPAuthenticationHeader(authReqdResponse.Header.AuthenticationHeader.SIPDigest);
                string origNonce = mjAuthHeader.SIPDigest.Nonce;
                string mjNonce = GetNonce(origNonce, authReqdResponse.Header.CallId);
                mjAuthHeader.SIPDigest.Nonce = mjNonce;
                mjAuthHeader.SIPDigest.Response = mjAuthHeader.SIPDigest.Digest;
                mjAuthHeader.SIPDigest.Nonce = origNonce;

                return mjAuthHeader;
            }
            catch (Exception excp) {
                logger.Error("Exception SIPProviderMagicJack GetAuthenticationHeader. " + excp.Message);
                throw;
            }
        }
        /// <summary>
        /// In transaction ACK requests are for non-2xx responses, i.e. INVITE rejected and no dialogue being created.
        /// </summary>
        private SIPRequest GetInTransactionACKRequest(SIPResponse sipResponse, SIPURI ackURI, SIPEndPoint localSIPEndPoint)
        {
            SIPRequest ackRequest = new SIPRequest(SIPMethodsEnum.ACK, ackURI.ToString());
            ackRequest.LocalSIPEndPoint = localSIPEndPoint;

            SIPHeader header = new SIPHeader(TransactionRequest.Header.From, sipResponse.Header.To, sipResponse.Header.CSeq, sipResponse.Header.CallId);
            header.CSeqMethod = SIPMethodsEnum.ACK;
            header.AuthenticationHeader = TransactionRequest.Header.AuthenticationHeader;
            header.Routes = base.TransactionRequest.Header.Routes;
            header.ProxySendFrom = base.TransactionRequest.Header.ProxySendFrom;

            ackRequest.Header = header;

            SIPViaHeader viaHeader = new SIPViaHeader(localSIPEndPoint, sipResponse.Header.Vias.TopViaHeader.Branch);
            ackRequest.Header.Vias.PushViaHeader(viaHeader);

            return ackRequest;
        }
        private void UACInviteTransaction_TransactionFinalResponseReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPResponse sipResponse)
        {
            try
            {
                // BranchId for 2xx responses needs to be a new one, non-2xx final responses use same one as original request.
                SIPRequest ackRequest = null;
                if (sipResponse.StatusCode >= 200 && sipResponse.StatusCode < 299)
                {
                    if (sipResponse.Header.To != null)
                    {
                        m_remoteTag = sipResponse.Header.To.ToTag;
                    }

                    SIPURI ackURI = m_transactionRequest.URI;
                    if (sipResponse.Header.Contact != null && sipResponse.Header.Contact.Count > 0)
                    {
                        ackURI = sipResponse.Header.Contact[0].ContactURI;
                        // Don't mangle private contacts if there is a Record-Route header. If a proxy is putting private IP's in a Record-Route header that's its problem.
                        if ((sipResponse.Header.RecordRoutes == null || sipResponse.Header.RecordRoutes.Length == 0)
                            && IPSocket.IsPrivateAddress(ackURI.Host) && !sipResponse.Header.ProxyReceivedFrom.IsNullOrBlank())
                        {
                            // Setting the Proxy-ReceivedOn header is how an upstream proxy will let an agent know it should mangle the contact.
                            SIPEndPoint remoteUASSIPEndPoint = SIPEndPoint.ParseSIPEndPoint(sipResponse.Header.ProxyReceivedFrom);
                            ackURI.Host = remoteUASSIPEndPoint.GetIPEndPoint().ToString();
                        }
                    }

                    // ACK for 2xx response needs to be a new transaction and gets routed based on SIP request fields.
                    ackRequest = GetNewTransactionACKRequest(sipResponse, ackURI, LocalSIPEndPoint);
                    base.SendRequest(ackRequest);
                }
                else
                {
                    // ACK for non 2xx response is part of the INVITE transaction and gets routed to the same endpoint as the INVITE.
                    ackRequest = GetInTransactionACKRequest(sipResponse, m_transactionRequest.URI, LocalSIPEndPoint);
                    base.SendRequest(RemoteEndPoint, ackRequest);
                }

                if (UACInviteTransactionFinalResponseReceived != null)
                {
                    UACInviteTransactionFinalResponseReceived(localSIPEndPoint, remoteEndPoint, sipTransaction, sipResponse);
                }

                if (CDR != null)
                {
                    SIPEndPoint localEP = SIPEndPoint.TryParse(sipResponse.Header.ProxyReceivedOn) ?? localSIPEndPoint;
                    SIPEndPoint remoteEP = SIPEndPoint.TryParse(sipResponse.Header.ProxyReceivedFrom) ?? remoteEndPoint;
                    CDR.Answered(sipResponse.StatusCode, sipResponse.Status, sipResponse.ReasonPhrase, localEP, remoteEP);
                }
            }
            catch (Exception excp)
            {
                logger.Error("Exception UACInviteTransaction_TransactionFinalResponseReceived. " + excp.Message);
            }
        }
        /// <summary>
        /// The event handler for responses to the initial register request.
        /// </summary>
        private void ServerResponseReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPResponse sipResponse)
        {
            try
            {
                Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentClient, SIPMonitorEventTypesEnum.ContactRegisterInProgress, "Server response " + sipResponse.Status + " received for " + m_sipAccountAOR.ToString() + ".", m_owner));

                if (sipResponse.Status == SIPResponseStatusCodesEnum.ProxyAuthenticationRequired || sipResponse.Status == SIPResponseStatusCodesEnum.Unauthorised)
                {
                    if (sipResponse.Header.AuthenticationHeader != null)
                    {
                        if (m_attempts >= MAX_REGISTER_ATTEMPTS)
                        {
                            Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentClient, SIPMonitorEventTypesEnum.ContactRegisterFailed, "Registration to " + m_sipAccountAOR.ToString() + " reached the maximum number of allowed attempts without a failure condition.", m_owner));
                            m_isRegistered = false;
                            if (RegistrationTemporaryFailure != null)
                            {
                                RegistrationTemporaryFailure(m_sipAccountAOR, "Registration reached the maximum number of allowed attempts.");
                            }
                            m_waitForRegistrationMRE.Set();
                        }
                        else
                        {
                            m_attempts++;
                            SIPRequest authenticatedRequest = GetAuthenticatedRegistrationRequest(sipTransaction.TransactionRequest, sipResponse);
                            SIPNonInviteTransaction regAuthTransaction = m_sipTransport.CreateNonInviteTransaction(authenticatedRequest, sipTransaction.RemoteEndPoint, localSIPEndPoint, m_outboundProxy);
                            regAuthTransaction.NonInviteTransactionFinalResponseReceived += (lep, rep, tn, rsp) => { ThreadPool.QueueUserWorkItem(delegate { AuthResponseReceived(lep, rep, tn, rsp); }); };
                            regAuthTransaction.NonInviteTransactionTimedOut += (tn) => { ThreadPool.QueueUserWorkItem(delegate { RegistrationTimedOut(tn); }); };
                            m_sipTransport.SendSIPReliable(regAuthTransaction);
                        }
                    }
                    else
                    {
                        Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentClient, SIPMonitorEventTypesEnum.ContactRegisterFailed, "Registration failed with " + sipResponse.Status + " but no authentication header was supplied for " + m_sipAccountAOR.ToString() + ".", m_owner));
                        m_isRegistered = false;
                        if (RegistrationTemporaryFailure != null)
                        {
                            RegistrationTemporaryFailure(m_sipAccountAOR, "Registration failed with " + sipResponse.Status + " but no authentication header was supplied.");
                        }
                        m_waitForRegistrationMRE.Set();
                    }
                }
                else
                {
                    if (sipResponse.Status == SIPResponseStatusCodesEnum.Ok)
                    {
                        if (m_expiry > 0)
                        {
                            m_isRegistered = true;
                            m_expiry = GetUpdatedExpiry(sipResponse);
                            //if (sipResponse.Header.SwitchboardToken != null && m_lastServerNonce != null)
                            //{
                            //    SwitchboardToken = Crypto.SymmetricDecrypt(m_password, m_lastServerNonce, sipResponse.Header.SwitchboardToken);
                            //}
                            RegistrationSuccessful(m_sipAccountAOR);
                        }
                        else
                        {
                            m_isRegistered = false;
                            RegistrationRemoved(m_sipAccountAOR);
                        }

                        m_waitForRegistrationMRE.Set();
                    }
                    else if (sipResponse.Status == SIPResponseStatusCodesEnum.Forbidden || sipResponse.Status == SIPResponseStatusCodesEnum.NotFound)
                    {
                        // SIP account does not appear to exist.
                        Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentClient, SIPMonitorEventTypesEnum.ContactRegisterFailed, "Registration failed with " + sipResponse.Status + " for " + m_sipAccountAOR.ToString() + ", no further registration attempts will be made.", m_owner));
                        string reasonPhrase = (sipResponse.ReasonPhrase.IsNullOrBlank()) ? sipResponse.Status.ToString() : sipResponse.ReasonPhrase;
                        if (RegistrationFailed != null)
                        {
                            RegistrationFailed(m_sipAccountAOR, "Registration failed with " + (int)sipResponse.Status + " " + reasonPhrase + ".");
                        }
                        m_exit = true;
                        m_waitForRegistrationMRE.Set();
                    }
                    else if (sipResponse.Status == SIPResponseStatusCodesEnum.IntervalTooBrief && m_expiry != 0)
                    {
                        m_expiry = GetUpdatedExpiryForIntervalTooBrief(sipResponse);
                        Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentClient, SIPMonitorEventTypesEnum.ContactRegisterInProgress, "Registration for " + m_sipAccountAOR.ToString() + " had a too short expiry, updated to +" + m_expiry + " and trying again.", m_owner));
                        SendInitialRegister();
                    }
                    else
                    {
                        Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentClient, SIPMonitorEventTypesEnum.ContactRegisterFailed, "Registration failed with " + sipResponse.Status + " for " + m_sipAccountAOR.ToString() + ".", m_owner));
                        m_isRegistered = false;
                        if (RegistrationTemporaryFailure != null)
                        {
                            RegistrationTemporaryFailure(m_sipAccountAOR, "Registration failed with " + sipResponse.Status + ".");
                        }
                        m_waitForRegistrationMRE.Set();
                    }
                }
            }
            catch (Exception excp)
            {
                logger.Error("Exception SIPRegistrationUserAgent ServerResponseReceived (" + remoteEndPoint + "). " + excp.Message);
            }
        }
Example #7
0
        /// <summary>
        ///  From RFC3261: Stateless Proxy Response Processing:
        ///  
        /// 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.  The proxy MUST NOT add 
        /// to, modify, or remove the message body.  Unless specified otherwise, the proxy MUST NOT remove
        /// any other header field values.  If the address does not match the  proxy, the message MUST be silently discarded.
        /// </summary>
        private void GotResponse(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPResponse sipResponse)
        {
            try
            {
                // Used in the proxy monitor messages only, plays no part in response processing.
                string fromUser = (sipResponse.Header.From != null) ? sipResponse.Header.From.FromURI.User : null;
                string toUser = (sipResponse.Header.To != null) ? sipResponse.Header.To.ToURI.User : null;
                string summaryStr = "resp " + sipResponse.Header.CSeqMethod + " from=" + fromUser + ", to=" + toUser + ", " + remoteEndPoint.ToString();

                SIPViaHeader topVia = sipResponse.Header.Vias.PopTopViaHeader();
                SIPEndPoint outSocket = localSIPEndPoint;

                // If the second Via header on the response was also set by this proxy it means the request was originally received and forwarded
                // on different sockets. To get the response to travel the same path in reverse it must be forwarded from the proxy socket indicated
                // by the second top Via.
                if (sipResponse.Header.Vias.Length > 1)
                {
                    SIPViaHeader nextTopVia = sipResponse.Header.Vias.TopViaHeader;
                    SIPEndPoint nextTopViaSIPEndPoint = SIPEndPoint.ParseSIPEndPoint(nextTopVia.Transport + ":" + nextTopVia.ReceivedFromAddress);
                    //if (!(PublicIPAddress != null && nextTopVia.ReceivedFromIPAddress != null && nextTopVia.ReceivedFromIPAddress != PublicIPAddress.ToString())
                    //    &&
                    //    (m_sipTransport.IsLocalSIPEndPoint(nextTopViaSIPEndPoint) || (PublicIPAddress != null && nextTopVia.ReceivedFromIPAddress == PublicIPAddress.ToString())))
                    if(m_sipTransport.IsLocalSIPEndPoint(nextTopViaSIPEndPoint))
                    {
                        sipResponse.Header.Vias.PopTopViaHeader();
                        outSocket = nextTopViaSIPEndPoint;
                    }
                }

                bool isFromAppServer = (m_sipCallDispatcherFile != null) ?  m_sipCallDispatcherFile.IsAppServerEndPoint(remoteEndPoint) : false;

                lock (this)
                {
                    m_compiledScript.DefaultScope.RemoveVariable("sys");
                    m_compiledScript.DefaultScope.RemoveVariable("isreq");
                    m_compiledScript.DefaultScope.RemoveVariable("localEndPoint");
                    m_compiledScript.DefaultScope.RemoveVariable("outSocket");
                    m_compiledScript.DefaultScope.RemoveVariable("resp");
                    m_compiledScript.DefaultScope.RemoveVariable("remoteEndPoint");
                    m_compiledScript.DefaultScope.RemoveVariable("summary");
                    m_compiledScript.DefaultScope.RemoveVariable("sipMethod");
                    m_compiledScript.DefaultScope.RemoveVariable("topVia");
                    m_compiledScript.DefaultScope.RemoveVariable("IsFromAppServer");

                    m_compiledScript.DefaultScope.SetVariable("sys", m_proxyScriptFacade);
                    m_compiledScript.DefaultScope.SetVariable("isreq", false);
                    m_compiledScript.DefaultScope.SetVariable("localEndPoint", localSIPEndPoint);
                    m_compiledScript.DefaultScope.SetVariable("outSocket", outSocket);
                    m_compiledScript.DefaultScope.SetVariable("resp", sipResponse);
                    m_compiledScript.DefaultScope.SetVariable("remoteEndPoint", remoteEndPoint);
                    m_compiledScript.DefaultScope.SetVariable("summary", summaryStr);
                    m_compiledScript.DefaultScope.SetVariable("sipMethod", sipResponse.Header.CSeqMethod.ToString());
                    m_compiledScript.DefaultScope.SetVariable("topVia", topVia);
                    m_compiledScript.DefaultScope.SetVariable("IsFromAppServer", isFromAppServer);

                    m_compiledScript.Execute();
                }

                //if (responseStopwatch.ElapsedMilliseconds > 20)
                //{
                //    logger.Debug("GotResponse processing time=" + responseStopwatch.ElapsedMilliseconds + "ms, script time=" + scriptStopwatch.ElapsedMilliseconds + "ms.");
                //}
            }
            catch (Exception excp)
            {
                string respExcpError = "Exception SIPProxyCore GotResponse. " + excp.Message;
                logger.Error(respExcpError + "\n" + sipResponse.ToString());
                SIPMonitorEvent respExcpEvent = new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.SIPProxy, SIPMonitorEventTypesEnum.Error, respExcpError, localSIPEndPoint, remoteEndPoint, null);
                SendMonitorEvent(respExcpEvent);

                throw excp;
            }
        }
Example #8
0
        private void UACCallAnswered(ISIPClientUserAgent answeredUAC, SIPResponse answeredResponse)
        {
            try
            {
                // Remove the current call from the pending list.
                lock (m_switchCalls)
                {
                    m_switchCalls.Remove(answeredUAC);
                }

                if (m_switchCallTransactions != null && answeredUAC.ServerTransaction != null)
                {
                    m_switchCallTransactions.Add(answeredUAC.ServerTransaction);
                }

                if (answeredResponse != null && answeredResponse.StatusCode >= 200 && answeredResponse.StatusCode <= 299)
                {
                    #region 2xx final response.

                    if (!m_callAnswered && !m_commandCancelled)
                    {
                        // This is the first call we've got an answer on.
                        m_callAnswered = true;
                        m_answeredUAC = answeredUAC;
                        AnsweredSIPResponse = answeredResponse;

                        SIPDialogueTransferModesEnum uasTransferMode = SIPDialogueTransferModesEnum.Default;
                        if (m_answeredUAC.CallDescriptor.TransferMode == SIPDialogueTransferModesEnum.NotAllowed)
                        {
                            answeredUAC.SIPDialogue.TransferMode = SIPDialogueTransferModesEnum.NotAllowed;
                            uasTransferMode = SIPDialogueTransferModesEnum.NotAllowed;
                        }
                        else if (m_answeredUAC.CallDescriptor.TransferMode == SIPDialogueTransferModesEnum.BlindPlaceCall)
                        {
                            answeredUAC.SIPDialogue.TransferMode = SIPDialogueTransferModesEnum.BlindPlaceCall;
                            uasTransferMode = SIPDialogueTransferModesEnum.BlindPlaceCall;
                        }
                        else if (m_answeredUAC.CallDescriptor.TransferMode == SIPDialogueTransferModesEnum.PassThru)
                        {
                            answeredUAC.SIPDialogue.TransferMode = SIPDialogueTransferModesEnum.PassThru;
                            uasTransferMode = SIPDialogueTransferModesEnum.PassThru;
                        }
                        /*else if (m_answeredUAC.CallDescriptor.TransferMode == SIPCallTransferModesEnum.Caller)
                        {
                            answeredUAC.SIPDialogue.TransferMode = SIPDialogueTransferModesEnum.NotAllowed;
                            uasTransferMode = SIPDialogueTransferModesEnum.Allowed;
                        }
                        else if (m_answeredUAC.CallDescriptor.TransferMode == SIPCallTransferModesEnum.Callee)
                        {
                            answeredUAC.SIPDialogue.TransferMode = SIPDialogueTransferModesEnum.Allowed;
                            uasTransferMode = SIPDialogueTransferModesEnum.NotAllowed;
                        }
                        else if (m_answeredUAC.CallDescriptor.TransferMode == SIPCallTransferModesEnum.Both)
                        {
                            answeredUAC.SIPDialogue.TransferMode = SIPDialogueTransferModesEnum.Allowed;
                            uasTransferMode = SIPDialogueTransferModesEnum.Allowed;
                        }*/

                        if (CallAnswered != null)
                        {
                            logger.Debug("Transfer mode=" + m_answeredUAC.CallDescriptor.TransferMode + ".");
                            CallAnswered(answeredResponse.Status, answeredResponse.ReasonPhrase, null, null, answeredResponse.Header.ContentType, answeredResponse.Body, answeredUAC.SIPDialogue, uasTransferMode);
                        }

                        // Cancel/hangup and other calls on this leg that are still around.
                        CancelNotRequiredCallLegs(CallCancelCause.NormalClearing);
                    }
                    else
                    {
                        // Call already answered or cancelled, hangup (send BYE).
                        FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Call leg " + answeredUAC.CallDescriptor.Uri + " answered but call was already answered or cancelled, hanging up.", m_username));
                        SIPDialogue sipDialogue = new SIPDialogue(answeredUAC.ServerTransaction, m_username, m_adminMemberId);
                        sipDialogue.Hangup(m_sipTransport, m_outboundProxySocket);
                    }

                    #endregion

                    CallLegCompleted();
                }
                else if (answeredUAC.SIPDialogue != null)
                {
                    // Google Voice calls create the dialogue without using a SIP response.
                    if (!m_callAnswered && !m_commandCancelled)
                    {
                        FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Call leg for Google Voice call to " + answeredUAC.CallDescriptor.Uri + " answered.", m_username));

                        // This is the first call we've got an answer on.
                        m_callAnswered = true;
                        m_answeredUAC = answeredUAC;

                        if (CallAnswered != null)
                        {
                            CallAnswered(SIPResponseStatusCodesEnum.Ok, null, null, null, answeredUAC.SIPDialogue.ContentType, answeredUAC.SIPDialogue.RemoteSDP, answeredUAC.SIPDialogue, SIPDialogueTransferModesEnum.NotAllowed);
                        }

                        // Cancel/hangup and other calls on this leg that are still around.
                        CancelNotRequiredCallLegs(CallCancelCause.NormalClearing);
                    }
                    else
                    {
                        // Call already answered or cancelled, hangup (send BYE).
                        FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Call leg for Google Voice call to " + answeredUAC.CallDescriptor.Uri + " answered but call was already answered or cancelled, hanging up.", m_username));
                        answeredUAC.SIPDialogue.Hangup(m_sipTransport, m_outboundProxySocket);
                    }
                }
                else if (answeredResponse != null && answeredResponse.StatusCode >= 300 && answeredResponse.StatusCode <= 399)
                {
                    ProcessRedirect(answeredUAC, answeredResponse);
                }
                else if (answeredResponse != null)
                {
                    // This call leg failed, record the failure status and reason.
                    m_lastFailureStatus = answeredResponse.Status;
                    m_lastFailureReason = answeredResponse.ReasonPhrase;

                    if (m_switchCallTransactions != null && answeredUAC.ServerTransaction != null)
                    {
                        m_switchCallTransactions.Add(answeredUAC.ServerTransaction);
                    }

                    CallLegCompleted();
                }
            }
            catch (Exception excp)
            {
                logger.Error("Exception ForkCall UACCallAnswered. " + excp);
            }
        }
        private int GetUpdatedExpiry(SIPResponse sipResponse)
        {
            // Find the contact in the list that matches the one being maintained by this agent in order to determine the expiry value.
            int serverExpiry = 0;
            int headerExpires = sipResponse.Header.Expires;
            int contactExpires = -1;
            if (sipResponse.Header.Contact != null && sipResponse.Header.Contact.Count > 0)
            {
                if (sipResponse.Header.Contact.Count == 1)
                {
                    contactExpires = sipResponse.Header.Contact[0].Expires;
                }
                else
                {
                    foreach (SIPContactHeader contactHeader in sipResponse.Header.Contact)
                    {
                        if (contactHeader.ContactURI == m_contactURI)
                        {
                            contactExpires = contactHeader.Expires;
                            break;
                        }
                    }
                }
            }

            if (contactExpires != -1)
            {
                serverExpiry = contactExpires;
            }
            else if (headerExpires != -1)
            {
                serverExpiry = headerExpires;
            }

            if (serverExpiry < REGISTER_MINIMUM_EXPIRY)
            {
                // Make sure we don't do a 3CX and send registration floods.
                return REGISTER_MINIMUM_EXPIRY;
            }
            else if (serverExpiry > MAX_EXPIRY)
            {
                return MAX_EXPIRY;
            }
            else
            {
                return serverExpiry;
            }
        }
Example #10
0
        /// <summary>
        /// Used to create a SIP response when it was not possible to parse the incoming SIP request.
        /// </summary>
        public SIPResponse GetResponse(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPResponseStatusCodesEnum responseCode, string reasonPhrase)
        {
            try
            {
                if (localSIPEndPoint == null)
                {
                    localSIPEndPoint = GetDefaultSIPEndPoint();
                }

                SIPResponse response = new SIPResponse(responseCode, reasonPhrase, localSIPEndPoint);
                SIPSchemesEnum sipScheme = (localSIPEndPoint.Protocol == SIPProtocolsEnum.tls) ? SIPSchemesEnum.sips : SIPSchemesEnum.sip;
                SIPFromHeader from = new SIPFromHeader(null, new SIPURI(sipScheme, localSIPEndPoint), null);
                SIPToHeader to = new SIPToHeader(null, new SIPURI(sipScheme, localSIPEndPoint), null);
                int cSeq = 1;
                string callId = CallProperties.CreateNewCallId();
                response.Header = new SIPHeader(from, to, cSeq, callId);
                response.Header.CSeqMethod = SIPMethodsEnum.NONE;
                response.Header.Vias.PushViaHeader(new SIPViaHeader(new SIPEndPoint(localSIPEndPoint.Protocol, remoteEndPoint.GetIPEndPoint()), CallProperties.CreateBranchId()));
                response.Header.MaxForwards = Int32.MinValue;
                response.Header.Allow = ALLOWED_SIP_METHODS;

                return response;
            }
            catch (Exception excp)
            {
                logger.Error("Exception SIPTransport GetResponse. " + excp.Message);
                throw;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="data"></param>
        /// <param name="ringTimeout"></param>
        /// <param name="answeredCallLimit"></param>
        /// <param name="redirectMode"></param>
        /// <param name="clientTransaction"></param>
        /// <param name="keepScriptAlive">If false will let the dial plan engine know the script has finished and the call is answered. For applications
        /// like Callback which need to have two calls answered it will be true.</param>
        /// <returns></returns>
        private DialPlanAppResult Dial(
            string data,
            int ringTimeout,
            int answeredCallLimit,
            SIPRequest clientRequest,
            CRMHeaders contact)
        {
            if (m_dialPlanContext.IsAnswered)
            {
                Log("The call has already been answered the Dial command was not processed.");
                return DialPlanAppResult.AlreadyAnswered;
            }
            else if (data.IsNullOrBlank())
            {
                Log("The dial string cannot be empty when calling Dial.");
                return DialPlanAppResult.Error;
            }
            else if (m_callInitialisationCount > MAX_CALLS_ALLOWED)
            {
                Log("You have exceeded the maximum allowed calls for a dialplan execution.");
                return DialPlanAppResult.Error;
            }
            else
            {
                Log("Commencing Dial with: " + data + ".");

                DialPlanAppResult result = DialPlanAppResult.Unknown;
                m_waitForCallCompleted = new ManualResetEvent(false);

                SIPResponseStatusCodesEnum answeredStatus = SIPResponseStatusCodesEnum.None;
                string answeredReason = null;
                string answeredContentType = null;
                string answeredBody = null;
                SIPDialogue answeredDialogue = null;
                SIPDialogueTransferModesEnum uasTransferMode = SIPDialogueTransferModesEnum.Default;
                int numberLegs = 0;

                QueueNewCallDelegate queueNewCall = (m_callManager != null) ? m_callManager.QueueNewCall : (QueueNewCallDelegate)null;
                m_currentCall = new ForkCall(m_sipTransport, FireProxyLogEvent, queueNewCall, m_dialStringParser, Username, m_adminMemberId, m_outboundProxySocket, m_callManager, m_dialPlanContext, out LastDialled);
                m_currentCall.CallProgress += m_dialPlanContext.CallProgress;
                m_currentCall.CallFailed += (status, reason, headers) =>
                {
                    LastFailureStatus = status;
                    LastFailureReason = reason;
                    result = DialPlanAppResult.Failed;
                    m_waitForCallCompleted.Set();
                };
                m_currentCall.CallAnswered += (status, reason, toTag, headers, contentType, body, dialogue, transferMode) =>
                {
                    answeredStatus = status;
                    answeredReason = reason;
                    answeredContentType = contentType;
                    answeredBody = body;
                    answeredDialogue = dialogue;
                    uasTransferMode = transferMode;
                    result = DialPlanAppResult.Answered;
                    m_waitForCallCompleted.Set();
                };

                try
                {
                    Queue<List<SIPCallDescriptor>> callsQueue = m_dialStringParser.ParseDialString(
                        DialPlanContextsEnum.Script,
                        clientRequest,
                        data,
                        m_customSIPHeaders,
                        m_customContentType,
                        m_customContent,
                        m_dialPlanContext.CallersNetworkId,
                        m_customFromName,
                        m_customFromUser,
                        m_customFromHost,
                        contact,
                        ServiceLevel);

                    List<SIPCallDescriptor>[] callListArray = callsQueue.ToArray();
                    callsQueue.ToList().ForEach((list) => numberLegs += list.Count);

                    if (numberLegs == 0)
                    {
                        Log("The dial string did not result in any call legs.");
                        return DialPlanAppResult.Error;
                    }
                    else
                    {
                        m_callInitialisationCount += numberLegs;
                        if (m_callInitialisationCount > MAX_CALLS_ALLOWED)
                        {
                            Log("You have exceeded the maximum allowed calls for a dialplan execution.");
                            return DialPlanAppResult.Error;
                        }
                    }

                    m_currentCall.Start(callsQueue);

                    // Wait for an answer.
                    if (ringTimeout <= 0 || ringTimeout * 1000 > m_maxRingTime)
                    {
                        ringTimeout = m_maxRingTime;
                    }
                    else
                    {
                        ringTimeout = ringTimeout * 1000;
                    }
                    ExtendScriptTimeout(ringTimeout / 1000 + DEFAULT_CREATECALL_RINGTIME);
                    DateTime startTime = DateTime.Now;

                    if (m_waitForCallCompleted.WaitOne(ringTimeout, false))
                    {
                        if (!m_clientCallCancelled)
                        {
                            if (result == DialPlanAppResult.Answered)
                            {
                                // The call limit duration is only used if there hasn't already been a per leg duration set on the call.
                                if (answeredCallLimit > 0 && answeredDialogue.CallDurationLimit == 0)
                                {
                                    answeredDialogue.CallDurationLimit = answeredCallLimit;
                                }

                                m_dialPlanContext.CallAnswered(answeredStatus, answeredReason, null, null, answeredContentType, answeredBody, answeredDialogue, uasTransferMode);

                                // Dial plan script stops once there is an answered call to bridge to or the client call is cancelled.
                                Log("Dial command was successfully answered in " + DateTime.Now.Subtract(startTime).TotalSeconds.ToString("0.00") + "s.");

                                // Do some Google Analytics call tracking.
                                if (answeredDialogue.RemoteUserField != null)
                                {
                                    SendGoogleAnalyticsEvent("Call", "Answered", answeredDialogue.RemoteUserField.URI.Host, 1);
                                }

                                m_executingScript.StopExecution();
                            }
                            else if (result == DialPlanAppResult.Failed)
                            {
                                // Check whether any of the responses were redirects.
                                if (LastDialled != null && LastDialled.Count > 0)
                                {
                                    var redirect = (from trans in LastDialled
                                                    where trans.TransactionFinalResponse != null && trans.TransactionFinalResponse.StatusCode >= 300 &&
                                                        trans.TransactionFinalResponse.StatusCode <= 399 && trans.TransactionFinalResponse.Header.Contact != null
                                                        && trans.TransactionFinalResponse.Header.Contact.Count > 0
                                                    select trans.TransactionFinalResponse).FirstOrDefault();

                                    if (redirect != null)
                                    {
                                        m_redirectResponse = redirect;
                                        m_redirectURI = RedirectResponse.Header.Contact[0].ContactURI;
                                        result = DialPlanAppResult.Redirect;
                                    }
                                }
                            }
                        }
                    }
                    else
                    {
                        if (!m_clientCallCancelled)
                        {
                            // Call timed out.
                            m_currentCall.CancelNotRequiredCallLegs(CallCancelCause.TimedOut);
                            result = DialPlanAppResult.TimedOut;
                        }
                    }

                    if (m_clientCallCancelled)
                    {
                        Log("Dial command was halted by cancellation of client call after " + DateTime.Now.Subtract(startTime).TotalSeconds.ToString("#.00") + "s.");
                        m_executingScript.StopExecution();
                    }

                    return result;
                }
                catch (ThreadAbortException)
                {
                    return DialPlanAppResult.Unknown;
                }
                catch (Exception excp)
                {
                    logger.Error("Exception DialPlanScriptFacade Dial. " + excp.Message);
                    return DialPlanAppResult.Error;
                }
            }
        }
Example #12
0
        private void UACInviteTransaction_TransactionInformationResponseReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPResponse sipResponse)
        {
            try
            {
                UACInviteTransactionInformationResponseReceived?.Invoke(localSIPEndPoint, remoteEndPoint, sipTransaction, sipResponse);

                if (sipResponse.StatusCode > 100 && sipResponse.StatusCode <= 199 && sipResponse.Header.RSeq > 0)
                {
                    // Send a PRACK for this provisional response.
                    SendPRackRequest(sipResponse);
                }

                if (CDR != null)
                {
                    SIPEndPoint localEP  = SIPEndPoint.TryParse(sipResponse.Header.ProxyReceivedOn) ?? localSIPEndPoint;
                    SIPEndPoint remoteEP = SIPEndPoint.TryParse(sipResponse.Header.ProxyReceivedFrom) ?? remoteEndPoint;
                    CDR.Progress(sipResponse.Status, sipResponse.ReasonPhrase, localEP, remoteEP);
                }
            }
            catch (Exception excp)
            {
                logger.LogError("Exception UACInviteTransaction_TransactionInformationResponseReceived. " + excp.Message);
            }
        }
Example #13
0
 private void FireSIPResponseOutTraceEvent(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPResponse sipResponse)
 {
     try
     {
         if (SIPResponseOutTraceEvent != null)
         {
             SIPResponseOutTraceEvent(localSIPEndPoint, remoteEndPoint, sipResponse);
         }
     }
     catch (Exception excp)
     {
         logger.Error("Exception FireSIPResponseOutTraceEvent. " + excp.Message);
     }
 }
 public void SendResponse(SIPResponse finalResponse)
 {
     base.SendFinalResponse(finalResponse);
 }
 private Task <SocketError> SIPNonInviteTransaction_TransactionFinalResponseReceived(SIPEndPoint localSIPEndPoint,
                                                                                     SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPResponse sipResponse)
 {
     return(NonInviteTransactionFinalResponseReceived?.Invoke(localSIPEndPoint, remoteEndPoint, this,
                                                              sipResponse));
 }
Example #16
0
        public void GotResponse(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPResponse sipResponse)
        {
            if (TransactionState == SIPTransactionStatesEnum.Completed || TransactionState == SIPTransactionStatesEnum.Confirmed)
            {
                FireTransactionTraceMessage("Received Duplicate Response " + localSIPEndPoint.ToString() + "<-" + remoteEndPoint + m_crLF + sipResponse.ToString());

                if (sipResponse.Header.CSeqMethod == SIPMethodsEnum.INVITE)
                {
                    if (sipResponse.StatusCode >= 100 && sipResponse.StatusCode <= 199)
                    {
                        // Ignore info response on completed transaction.
                    }
                    else
                    {
                        ResendAckRequest();
                    }
                }

                if (TransactionDuplicateResponse != null)
                {
                    TransactionDuplicateResponse(localSIPEndPoint, remoteEndPoint, this, sipResponse);
                }
            }
            else
            {
                FireTransactionTraceMessage("Received Response " + localSIPEndPoint.ToString() + "<-" + remoteEndPoint + m_crLF + sipResponse.ToString());

                if (sipResponse.StatusCode >= 100 && sipResponse.StatusCode <= 199)
                {
                    UpdateTransactionState(SIPTransactionStatesEnum.Proceeding);
                    TransactionInformationResponseReceived(localSIPEndPoint, remoteEndPoint, this, sipResponse);
                }
                else
                {
                    m_transactionFinalResponse = sipResponse;
                    UpdateTransactionState(SIPTransactionStatesEnum.Completed);
                    TransactionFinalResponseReceived(localSIPEndPoint, remoteEndPoint, this, sipResponse);
                }
            }
        }
Example #17
0
        public void GotResponse(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPResponse sipResponse)
        {
            if (TransactionState == SIPTransactionStatesEnum.Completed || TransactionState == SIPTransactionStatesEnum.Confirmed)
            {
                FireTransactionTraceMessage($"Transaction received duplicate response {localSIPEndPoint.ToString()}<-{remoteEndPoint}: {sipResponse.ShortDescription}");

                if (sipResponse.Header.CSeqMethod == SIPMethodsEnum.INVITE)
                {
                    if (sipResponse.StatusCode > 100 && sipResponse.StatusCode <= 199)
                    {
                        ResendPrackRequest();
                    }
                    else
                    {
                        ResendAckRequest();
                    }
                }

                TransactionDuplicateResponse?.Invoke(localSIPEndPoint, remoteEndPoint, this, sipResponse);
            }
            else
            {
                FireTransactionTraceMessage($"Transaction received Response {localSIPEndPoint.ToString()}<-{remoteEndPoint}: {sipResponse.ShortDescription}");

                if (sipResponse.StatusCode >= 100 && sipResponse.StatusCode <= 199)
                {
                    UpdateTransactionState(SIPTransactionStatesEnum.Proceeding);
                    TransactionInformationResponseReceived(localSIPEndPoint, remoteEndPoint, this, sipResponse);
                }
                else
                {
                    m_transactionFinalResponse = sipResponse;
                    UpdateTransactionState(SIPTransactionStatesEnum.Completed);
                    TransactionFinalResponseReceived(localSIPEndPoint, remoteEndPoint, this, sipResponse);
                }
            }
        }
Example #18
0
        private void UACInviteTransaction_TransactionFinalResponseReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPResponse sipResponse)
        {
            try
            {
                // BranchId for 2xx responses needs to be a new one, non-2xx final responses use same one as original request.
                SIPRequest ackRequest = null;
                if (sipResponse.StatusCode >= 200 && sipResponse.StatusCode < 299)
                {
                    if (sipResponse.Header.To != null)
                    {
                        m_remoteTag = sipResponse.Header.To.ToTag;
                    }

                    SIPURI ackURI = m_transactionRequest.URI;
                    if (sipResponse.Header.Contact != null && sipResponse.Header.Contact.Count > 0)
                    {
                        ackURI = sipResponse.Header.Contact[0].ContactURI;
                        // Don't mangle private contacts if there is a Record-Route header. If a proxy is putting private IP's in a Record-Route header that's its problem.
                        if ((sipResponse.Header.RecordRoutes == null || sipResponse.Header.RecordRoutes.Length == 0) &&
                            IPSocket.IsPrivateAddress(ackURI.Host) && !sipResponse.Header.ProxyReceivedFrom.IsNullOrBlank())
                        {
                            // Setting the Proxy-ReceivedOn header is how an upstream proxy will let an agent know it should mangle the contact.
                            SIPEndPoint remoteUASSIPEndPoint = SIPEndPoint.ParseSIPEndPoint(sipResponse.Header.ProxyReceivedFrom);
                            ackURI.Host = remoteUASSIPEndPoint.GetIPEndPoint().ToString();
                        }
                    }

                    // ACK for 2xx response needs to be a new transaction and gets routed based on SIP request fields.
                    ackRequest = GetNewTransactionACKRequest(sipResponse, ackURI, LocalSIPEndPoint);
                    base.SendRequest(ackRequest);
                }
                else
                {
                    // ACK for non 2xx response is part of the INVITE transaction and gets routed to the same endpoint as the INVITE.
                    ackRequest = GetInTransactionACKRequest(sipResponse, m_transactionRequest.URI, LocalSIPEndPoint);
                    base.SendRequest(RemoteEndPoint, ackRequest);
                }

                if (UACInviteTransactionFinalResponseReceived != null)
                {
                    UACInviteTransactionFinalResponseReceived(localSIPEndPoint, remoteEndPoint, sipTransaction, sipResponse);
                }

                if (CDR != null)
                {
                    SIPEndPoint localEP  = SIPEndPoint.TryParse(sipResponse.Header.ProxyReceivedOn) ?? localSIPEndPoint;
                    SIPEndPoint remoteEP = SIPEndPoint.TryParse(sipResponse.Header.ProxyReceivedFrom) ?? remoteEndPoint;
                    CDR.Answered(sipResponse.StatusCode, sipResponse.Status, sipResponse.ReasonPhrase, localEP, remoteEP);
                }
            }
            catch (Exception excp)
            {
                logger.Error("Exception UACInviteTransaction_TransactionFinalResponseReceived. " + excp.Message);
            }
        }
Example #19
0
        private void SendResponse(SIPChannel sipChannel, SIPEndPoint dstEndPoint, SIPResponse sipResponse)
        {
            try
            {
                if (dstEndPoint != null && dstEndPoint.Address.Equals(BlackholeAddress))
                {
                    // Ignore packet, it's destined for the blackhole.
                    return;
                }

                if (m_sipChannels.Count == 0)
                {
                    throw new ApplicationException("No channels are configured in the SIP transport layer. The response could not be sent.");
                }

                sipResponse.Header.ContentLength = (sipResponse.Body.NotNullOrBlank()) ? Encoding.UTF8.GetByteCount(sipResponse.Body) : 0;
                sipChannel.Send(dstEndPoint.GetIPEndPoint(), Encoding.UTF8.GetBytes(sipResponse.ToString()));

                if (SIPRequestOutTraceEvent != null)
                {
                    FireSIPResponseOutTraceEvent(sipChannel.SIPChannelEndPoint, dstEndPoint, sipResponse);
                }
            }
            catch (ApplicationException appExcp)
            {
                logger.Warn("ApplicationException SIPTransport SendResponse. " + appExcp.Message);
            }
        }
 private void SIPNonInviteTransaction_TransactionFinalResponseReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPResponse sipResponse)
 {
     if (NonInviteTransactionFinalResponseReceived != null)
     {
         NonInviteTransactionFinalResponseReceived(localSIPEndPoint, remoteEndPoint, this, sipResponse);
     }
 }
Example #21
0
        public void SendResponse(SIPResponse sipResponse)
        {
            if (sipResponse.LocalSIPEndPoint != null && sipResponse.LocalSIPEndPoint.Address.Equals(BlackholeAddress))
            {
                // Ignore packet, it's destined for the blackhole.
                return;
            }

            if (m_sipChannels.Count == 0)
            {
                throw new ApplicationException("No channels are configured in the SIP transport layer. The response could not be sent.");
            }

            //SIPChannel sipChannel = GetChannelForSocketId(sipResponse.SocketId);
            SIPViaHeader topViaHeader = sipResponse.Header.Vias.TopViaHeader;
            if (topViaHeader == null)
            {
                logger.Warn("There was no top Via header on a SIP response from " + sipResponse.RemoteSIPEndPoint + " when attempting to send it, response dropped.");
                //logger.Warn(sipResponse.ToString());
            }
            else
            {
                SIPChannel sipChannel = FindSIPChannel(sipResponse.LocalSIPEndPoint);
                sipChannel = sipChannel ?? GetDefaultChannel(topViaHeader.Transport);

                if (sipChannel != null)
                {
                    SendResponse(sipChannel, sipResponse);
                }
                else
                {
                    throw new ApplicationException("Could not find a SIP channel to send SIP Response to " + topViaHeader.ReceivedFromAddress + ".");
                }
            }
        }
Example #22
0
 private void UASInviteTransaction_TransactionResponseReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPResponse sipResponse)
 {
     logger.LogWarning("UASInviteTransaction received unexpected response, " + sipResponse.ReasonPhrase + " from " + remoteEndPoint.ToString() + ", ignoring.");
 }
            public void MagicJackAuthUnitTest()
            {
                Console.WriteLine("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name);

                string nonce = "8765abc4_32190";
                SIPResponse authReqdResponse = new SIPResponse(SIPResponseStatusCodesEnum.Unauthorised, null, null);
                authReqdResponse.Header.CallId = "9876ABC56738DD43";
                authReqdResponse.Header.AuthenticationHeader = SIPAuthenticationHeader.ParseSIPAuthenticationHeader(SIPAuthorisationHeadersEnum.WWWAuthenticate, "Digest nonce=\"" + nonce + "\",realm=\"stratus.com\",algorithm=MD5");
                authReqdResponse.Header.AuthenticationHeader.SIPDigest.SetCredentials("username", "password", "sip:[email protected]", SIPMethodsEnum.INVITE.ToString());

                Assert.IsTrue(SIPProviderMagicJack.IsMagicJackRequest(authReqdResponse), "The SIP Response was not correctly identified as being for a MagicJack request.");

                string mjNonce = GetNonce(authReqdResponse.Header.AuthenticationHeader.SIPDigest.Nonce, authReqdResponse.Header.CallId);
                SIPAuthenticationHeader mjAuthheader = SIPProviderMagicJack.GetAuthenticationHeader(authReqdResponse);

                Assert.IsTrue(mjNonce == "8765abc4_32190_65CB38DA", "The MagicJack nonce was not correctly generated.");
                Assert.IsTrue(authReqdResponse.Header.AuthenticationHeader.SIPDigest.Nonce == nonce, "The nonce set in the MagicJack response was not preserved correctly.");

                Console.WriteLine("-----------------------------------------");
            }
 private Task <SocketError> UASInviteTransaction_TransactionResponseReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPResponse sipResponse)
 {
     logger.LogWarning("UASInviteTransaction received unexpected response, " + sipResponse.ReasonPhrase + " from " + remoteEndPoint.ToString() + ", ignoring.");
     return(Task.FromResult(SocketError.Fault));
 }
 public new Task <SocketError> SendProvisionalResponse(SIPResponse sipResponse)
 {
     CDR?.Progress(sipResponse.Status, sipResponse.ReasonPhrase, null, null);
     return(base.SendProvisionalResponse(sipResponse));
 }
 public new void SendFinalResponse(SIPResponse sipResponse)
 {
     CDR?.Answered(sipResponse.StatusCode, sipResponse.Status, sipResponse.ReasonPhrase, null, null);
     base.SendFinalResponse(sipResponse);
 }
        private int GetUpdatedExpiryForIntervalTooBrief(SIPResponse sipResponse)
        {
            int newExpiry = sipResponse.Header.MinExpires;

            if (newExpiry != 0 && newExpiry > m_expiry)
            {
                if(newExpiry > MAX_EXPIRY)
                {
                    return MAX_EXPIRY;
                }
                else
                {
                    return newExpiry;
                }
            }
            else if(m_expiry < MAX_EXPIRY)
            {
                return m_expiry * 2;
            }

            return m_expiry;
        }
Example #28
0
        public Task <SocketError> GotResponse(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPResponse sipResponse)
        {
            if (TransactionState == SIPTransactionStatesEnum.Completed || TransactionState == SIPTransactionStatesEnum.Confirmed)
            {
                FireTransactionTraceMessage($"Transaction received duplicate response {localSIPEndPoint.ToString()}<-{remoteEndPoint}: {sipResponse.ShortDescription}");
                TransactionDuplicateResponse?.Invoke(localSIPEndPoint, remoteEndPoint, this, sipResponse);

                if (sipResponse.Header.CSeqMethod == SIPMethodsEnum.INVITE)
                {
                    if (sipResponse.StatusCode > 100 && sipResponse.StatusCode <= 199)
                    {
                        return(ResendPrackRequest());
                    }
                    else
                    {
                        return(ResendAckRequest());
                    }
                }
                else
                {
                    return(Task.FromResult(SocketError.Success));
                }
            }
            else
            {
                FireTransactionTraceMessage($"Transaction received Response {localSIPEndPoint.ToString()}<-{remoteEndPoint}: {sipResponse.ShortDescription}");

                if (sipResponse.StatusCode >= 100 && sipResponse.StatusCode <= 199)
                {
                    UpdateTransactionState(SIPTransactionStatesEnum.Proceeding);
                    return(TransactionInformationResponseReceived(localSIPEndPoint, remoteEndPoint, this, sipResponse));
                }
                else
                {
                    m_transactionFinalResponse = sipResponse;

                    if (TransactionType == SIPTransactionTypesEnum.NonInvite)
                    {
                        // No ACK's for non-INVITE's so go straight to confirmed.
                        UpdateTransactionState(SIPTransactionStatesEnum.Confirmed);
                    }
                    else
                    {
                        UpdateTransactionState(SIPTransactionStatesEnum.Completed);
                    }

                    return(TransactionFinalResponseReceived(localSIPEndPoint, remoteEndPoint, this, sipResponse));
                }
            }
        }
 public SIPEndPoint LookupTransactionID(SIPResponse sipResponse)
 {
     return LookupTransactionID(sipResponse.Header.CallId);
 }
Example #30
0
        private void UACInviteTransaction_TransactionInformationResponseReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPResponse sipResponse)
        {
            try
            {
                if (UACInviteTransactionInformationResponseReceived != null)
                {
                    UACInviteTransactionInformationResponseReceived(localSIPEndPoint, remoteEndPoint, sipTransaction, sipResponse);
                }

                if (CDR != null)
                {
                    SIPEndPoint localEP  = SIPEndPoint.TryParse(sipResponse.Header.ProxyReceivedOn) ?? localSIPEndPoint;
                    SIPEndPoint remoteEP = SIPEndPoint.TryParse(sipResponse.Header.ProxyReceivedFrom) ?? remoteEndPoint;
                    CDR.Progress(sipResponse.Status, sipResponse.ReasonPhrase, localEP, remoteEP);
                }
            }
            catch (Exception excp)
            {
                logger.Error("Exception UACInviteTransaction_TransactionInformationResponseReceived. " + excp.Message);
            }
        }
 private void CallProgress(SIPResponseStatusCodesEnum progressStatus, string reasonPhrase, string[] customHeaders, string progressContentType, string progressBody, ISIPClientUserAgent uac)
 {
     SIPResponse progressResponse = new SIPResponse(progressStatus, reasonPhrase, null);
     CallRinging(this, progressResponse);
 }
Example #32
0
        private void UACInviteTransaction_TransactionFinalResponseReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPResponse sipResponse)
        {
            try
            {
                // BranchId for 2xx responses needs to be a new one, non-2xx final responses use same one as original request.
                if (sipResponse.StatusCode >= 200 && sipResponse.StatusCode < 299)
                {
                    if (_sendOkAckManually == false)
                    {
                        Send2xxAckRequest(null, null);
                    }
                }
                else
                {
                    // ACK for non 2xx response is part of the INVITE transaction and gets routed to the same endpoint as the INVITE.
                    var ackRequest = GetInTransactionACKRequest(sipResponse, m_transactionRequest.URI, LocalSIPEndPoint);
                    base.SendRequest(RemoteEndPoint, ackRequest);
                }

                if (UACInviteTransactionFinalResponseReceived != null)
                {
                    UACInviteTransactionFinalResponseReceived(localSIPEndPoint, remoteEndPoint, sipTransaction, sipResponse);
                }

                if (CDR != null)
                {
                    SIPEndPoint localEP  = SIPEndPoint.TryParse(sipResponse.Header.ProxyReceivedOn) ?? localSIPEndPoint;
                    SIPEndPoint remoteEP = SIPEndPoint.TryParse(sipResponse.Header.ProxyReceivedFrom) ?? remoteEndPoint;
                    CDR.Answered(sipResponse.StatusCode, sipResponse.Status, sipResponse.ReasonPhrase, localEP, remoteEP);
                }
            }
            catch (Exception excp)
            {
                logger.Error("Exception UACInviteTransaction_TransactionFinalResponseReceived. " + excp.Message);
            }
        }
        /// <summary>
        /// New transaction ACK requests are for 2xx responses, i.e. INVITE accepted and dialogue being created.
        /// </summary>
        /// <remarks>
        /// From RFC 3261 Chapter 17.1.1.3 - ACK for non-2xx final responses
        /// 
        /// IMPORTANT:
        /// an ACK for a non-2xx response will also have the same branch ID as the INVITE whose response it acknowledges.
        /// 
        /// 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.
        /// 
        /// From RFC 3261 Chapter 13.2.2.4 - ACK for 2xx final responses
        /// 
        /// IMPORTANT:
        /// an ACK for a 2xx final response is a new transaction and has a new branch ID.
        /// 
        /// The UAC core MUST generate an ACK request for each 2xx received from
        /// the transaction layer.  The header fields of the ACK are constructed
        /// in the same way as for any request sent within a dialog (see Section
        /// 12) with the exception of the CSeq and the header fields related to
        /// authentication.  The sequence number of the CSeq header field MUST be
        /// the same as the INVITE being acknowledged, but the CSeq method MUST
        /// be ACK.  The ACK MUST contain the same credentials as the INVITE.  If
        /// the 2xx contains an offer (based on the rules above), the ACK MUST
        /// carry an answer in its body.  If the offer in the 2xx response is not
        /// acceptable, the UAC core MUST generate a valid answer in the ACK and
        /// then send a BYE immediately.
        /// </remarks>
        private SIPRequest GetNewTransactionACKRequest(SIPResponse sipResponse, SIPURI ackURI, SIPEndPoint localSIPEndPoint)
        {
            SIPRequest ackRequest = new SIPRequest(SIPMethodsEnum.ACK, ackURI.ToString());
            ackRequest.LocalSIPEndPoint = localSIPEndPoint;

            SIPHeader header = new SIPHeader(TransactionRequest.Header.From, sipResponse.Header.To, sipResponse.Header.CSeq, sipResponse.Header.CallId);
            header.CSeqMethod = SIPMethodsEnum.ACK;
            header.AuthenticationHeader = TransactionRequest.Header.AuthenticationHeader;
            header.ProxySendFrom = base.TransactionRequest.Header.ProxySendFrom;

            if (sipResponse.Header.RecordRoutes != null)
            {
                header.Routes = sipResponse.Header.RecordRoutes.Reversed();
            }

            ackRequest.Header = header;

            SIPViaHeader viaHeader = new SIPViaHeader(localSIPEndPoint, CallProperties.CreateBranchId());
            ackRequest.Header.Vias.PushViaHeader(viaHeader);

            return ackRequest;
        }
 private void SIPCancelTransaction_TransactionFinalResponseReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPResponse sipResponse)
 {
     if (sipResponse.StatusCode < 200)
     {
         logger.LogWarning("A SIP CANCEL transaction received an unexpected SIP information response " + sipResponse.ReasonPhrase + ".");
     }
     else
     {
         if (CancelTransactionFinalResponseReceived != null)
         {
             CancelTransactionFinalResponseReceived(localSIPEndPoint, remoteEndPoint, sipTransaction, sipResponse);
         }
     }
 }
        private void UACInviteTransaction_TransactionInformationResponseReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPResponse sipResponse)
        {
            try
            {
                if (UACInviteTransactionInformationResponseReceived != null)
                {
                    UACInviteTransactionInformationResponseReceived(localSIPEndPoint, remoteEndPoint, sipTransaction, sipResponse);
                }

                if (CDR != null)
                {
                    SIPEndPoint localEP = SIPEndPoint.TryParse(sipResponse.Header.ProxyReceivedOn) ?? localSIPEndPoint;
                    SIPEndPoint remoteEP = SIPEndPoint.TryParse(sipResponse.Header.ProxyReceivedFrom) ?? remoteEndPoint;
                    CDR.Progress(sipResponse.Status, sipResponse.ReasonPhrase, localEP, remoteEP);
                }
            }
            catch (Exception excp)
            {
                logger.Error("Exception UACInviteTransaction_TransactionInformationResponseReceived. " + excp.Message);
            }
        }
 public bool Exists(SIPResponse sipResponse)
 {
     return(GetTransaction(sipResponse) != null);
 }
Example #37
0
        private void SendResponse(SIPChannel sipChannel, SIPResponse sipResponse)
        {
            if (m_sipChannels.Count == 0)
            {
                throw new ApplicationException("No channels are configured in the SIP transport layer. The response could not be sent.");
            }

            SIPViaHeader topVia = sipResponse.Header.Vias.TopViaHeader;
            SIPDNSLookupResult lookupResult = GetHostEndPoint(topVia.ReceivedFromAddress, false);

            if (lookupResult.LookupError != null)
            {
                throw new ApplicationException("Could not resolve destination for response.\n" + sipResponse.ToString());
            }
            else if (lookupResult.Pending)
            {
                // Ignore this response transmission and wait for the transaction retransmit mechanism to try again when DNS will have hopefully resolved the end point.
                return;
            }
            else
            {
                SIPEndPoint dstEndPoint = lookupResult.GetSIPEndPoint();

                if (dstEndPoint != null && dstEndPoint.Address.Equals(BlackholeAddress))
                {
                    // Ignore packet, it's destined for the blackhole.
                    return;
                }
                else if (dstEndPoint != null)
                {
                    SendResponse(sipChannel, new SIPEndPoint(topVia.Transport, dstEndPoint.GetIPEndPoint()), sipResponse);
                }
                else
                {
                    throw new ApplicationException("SendResponse could not send a response as no end point was resolved.\n" + sipResponse.ToString());
                }
            }
        }
        private async Task <SocketError> UACInviteTransaction_TransactionInformationResponseReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPResponse sipResponse)
        {
            try
            {
                if (sipResponse.StatusCode > 100 && sipResponse.StatusCode <= 199)
                {
                    if (sipResponse.Header.RSeq > 0)
                    {
                        // Send a PRACK for this provisional response.
                        PRackRequest = GetPRackRequest(sipResponse);
                        await SendRequestAsync(PRackRequest);
                    }
                }

                if (CDR != null)
                {
                    SIPEndPoint localEP  = SIPEndPoint.TryParse(sipResponse.Header.ProxyReceivedOn) ?? localSIPEndPoint;
                    SIPEndPoint remoteEP = SIPEndPoint.TryParse(sipResponse.Header.ProxyReceivedFrom) ?? remoteEndPoint;
                    CDR.Progress(sipResponse.Status, sipResponse.ReasonPhrase, localEP, remoteEP);
                }

                return(await UACInviteTransactionInformationResponseReceived?.Invoke(localSIPEndPoint, remoteEndPoint, sipTransaction, sipResponse));;
            }
            catch (Exception excp)
            {
                logger.LogError("Exception UACInviteTransaction_TransactionInformationResponseReceived. " + excp.Message);
                return(SocketError.Fault);
            }
        }
Example #39
0
        public static SIPResponse GetResponse(SIPRequest sipRequest, SIPResponseStatusCodesEnum responseCode, string reasonPhrase)
        {
            try
            {
                SIPResponse response = new SIPResponse(responseCode, reasonPhrase, sipRequest.LocalSIPEndPoint);

                if (reasonPhrase != null)
                {
                    response.ReasonPhrase = reasonPhrase;
                }

                SIPHeader requestHeader = sipRequest.Header;
                SIPFromHeader from = (requestHeader == null || requestHeader.From != null) ? requestHeader.From : new SIPFromHeader(null, new SIPURI(sipRequest.URI.Scheme, sipRequest.LocalSIPEndPoint), null);
                SIPToHeader to = (requestHeader == null || requestHeader.To != null) ? requestHeader.To : new SIPToHeader(null, new SIPURI(sipRequest.URI.Scheme, sipRequest.LocalSIPEndPoint), null);
                int cSeq = (requestHeader == null || requestHeader.CSeq != -1) ? requestHeader.CSeq : 1;
                string callId = (requestHeader == null || requestHeader.CallId != null) ? requestHeader.CallId : CallProperties.CreateNewCallId();

                response.Header = new SIPHeader(from, to, cSeq, callId);
                response.Header.CSeqMethod = (requestHeader != null) ? requestHeader.CSeqMethod : SIPMethodsEnum.NONE;

                if (requestHeader == null || requestHeader.Vias == null || requestHeader.Vias.Length == 0)
                {
                    response.Header.Vias.PushViaHeader(new SIPViaHeader(sipRequest.RemoteSIPEndPoint, CallProperties.CreateBranchId()));
                }
                else
                {
                    response.Header.Vias = requestHeader.Vias;
                }

                response.Header.MaxForwards = Int32.MinValue;
                response.Header.Allow = ALLOWED_SIP_METHODS;

                return response;
            }
            catch (Exception excp)
            {
                logger.Error("Exception SIPTransport GetResponse. " + excp.Message);
                throw excp;
            }
        }
        private async Task <SocketError> UACInviteTransaction_TransactionFinalResponseReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPResponse sipResponse)
        {
            try
            {
                DeliveryPending = false;

                // BranchId for 2xx responses needs to be a new one, non-2xx final responses use same one as original request.
                if (sipResponse.StatusCode >= 200 && sipResponse.StatusCode < 299)
                {
                    if (_sendOkAckManually == false)
                    {
                        AckRequest = Get2xxAckRequest(null, null);
                        await SendRequestAsync(AckRequest);
                    }
                }
                else
                {
                    // ACK for non 2xx response is part of the INVITE transaction and gets routed to the same endpoint as the INVITE.
                    AckRequest = GetInTransactionACKRequest(sipResponse, m_transactionRequest.URI);
                    await SendRequestAsync(AckRequest);
                }

                if (CDR != null)
                {
                    SIPEndPoint localEP  = SIPEndPoint.TryParse(sipResponse.Header.ProxyReceivedOn) ?? localSIPEndPoint;
                    SIPEndPoint remoteEP = SIPEndPoint.TryParse(sipResponse.Header.ProxyReceivedFrom) ?? remoteEndPoint;
                    CDR.Answered(sipResponse.StatusCode, sipResponse.Status, sipResponse.ReasonPhrase, localEP, remoteEP);
                }

                return(await UACInviteTransactionFinalResponseReceived?.Invoke(localSIPEndPoint, remoteEndPoint, sipTransaction, sipResponse));
            }
            catch (Exception excp)
            {
                logger.LogError($"Exception UACInviteTransaction_TransactionFinalResponseReceived. {excp.Message}");
                return(SocketError.Fault);
            }
        }
Example #41
0
        public void SendResponse(SIPEndPoint dstEndPoint, SIPResponse sipResponse)
        {
            if (dstEndPoint != null && dstEndPoint.Address.Equals(BlackholeAddress))
            {
                // Ignore packet, it's destined for the blackhole.
            }
            else
            {
                if (m_sipChannels.Count == 0)
                {
                    throw new ApplicationException("No channels are configured in the SIP transport layer. The response could not be sent.");
                }

                SIPChannel sipChannel = FindSIPChannel(sipResponse.LocalSIPEndPoint);
                sipChannel = sipChannel ?? GetDefaultChannel(dstEndPoint.Protocol);

                if (sipChannel != null)
                {
                    SendResponse(sipChannel, dstEndPoint, sipResponse);
                }
                else
                {
                    logger.Warn("Could not find channel to send SIP Response in SendResponse.");
                }
            }
        }
        /// <summary>
        /// New transaction ACK requests are for 2xx responses, i.e. INVITE accepted and dialogue being created.
        /// </summary>
        /// <remarks>
        /// From RFC 3261 Chapter 13.2.2.4 - ACK for 2xx final responses
        ///
        /// IMPORTANT:
        /// an ACK for a 2xx final response is a new transaction and has a new branch ID.
        ///
        /// The UAC core MUST generate an ACK request for each 2xx received from
        /// the transaction layer.  The header fields of the ACK are constructed
        /// in the same way as for any request sent within a dialog (see Section
        /// 12) with the exception of the CSeq and the header fields related to
        /// authentication.  The sequence number of the CSeq header field MUST be
        /// the same as the INVITE being acknowledged, but the CSeq method MUST
        /// be ACK.  The ACK MUST contain the same credentials as the INVITE.  If
        /// the 2xx contains an offer (based on the rules above), the ACK MUST
        /// carry an answer in its body.  If the offer in the 2xx response is not
        /// acceptable, the UAC core MUST generate a valid answer in the ACK and
        /// then send a BYE immediately.
        /// </remarks>
        private SIPRequest GetNewTransactionAcknowledgeRequest(SIPMethodsEnum method, SIPResponse sipResponse, SIPURI ackURI)
        {
            SIPRequest ackRequest = new SIPRequest(method, ackURI.ToString());

            ackRequest.SetSendFromHints(sipResponse.LocalSIPEndPoint);

            SIPHeader header = new SIPHeader(TransactionRequest.Header.From, sipResponse.Header.To, sipResponse.Header.CSeq, sipResponse.Header.CallId);

            header.CSeqMethod           = method;
            header.AuthenticationHeader = TransactionRequest.Header.AuthenticationHeader;
            header.ProxySendFrom        = base.TransactionRequest.Header.ProxySendFrom;

            // If the UAS supplies a desired Record-Route list use that first. Otherwise fall back to any Route list used in the original transaction.
            if (sipResponse.Header.RecordRoutes != null)
            {
                header.Routes = sipResponse.Header.RecordRoutes.Reversed();
            }
            else if (base.TransactionRequest.Header.Routes != null)
            {
                header.Routes = base.TransactionRequest.Header.Routes;
            }

            ackRequest.Header = header;
            ackRequest.Header.Vias.PushViaHeader(SIPViaHeader.GetDefaultSIPViaHeader());

            return(ackRequest);
        }
 private void SIPNonInviteTransaction_TransactionFinalResponseReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPResponse sipResponse)
 {
     if (NonInviteTransactionFinalResponseReceived != null)
     {
         NonInviteTransactionFinalResponseReceived(localSIPEndPoint, remoteEndPoint, this, sipResponse);
     }
 }
        private void ServerResponseReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPResponse sipResponse)
        {
            try
            {
                string reasonPhrase = (sipResponse.ReasonPhrase.IsNullOrBlank()) ? sipResponse.Status.ToString() : sipResponse.ReasonPhrase;
                Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentClient, SIPMonitorEventTypesEnum.DialPlan, "Server response " + sipResponse.StatusCode + " " + reasonPhrase + " received for " + sipTransaction.TransactionRequest.Method +" to "  + m_callDescriptor.Uri + ".", m_owner));

                if (sipResponse.Status == SIPResponseStatusCodesEnum.ProxyAuthenticationRequired || sipResponse.Status == SIPResponseStatusCodesEnum.Unauthorised)
                {
                    if (sipResponse.Header.AuthenticationHeader != null)
                    {
                        if ((m_callDescriptor.Username != null || m_callDescriptor.AuthUsername != null) && m_callDescriptor.Password != null)
                        {
                            SIPRequest authenticatedRequest = GetAuthenticatedRequest(sipTransaction.TransactionRequest, sipResponse);
                            SIPNonInviteTransaction authTransaction = m_sipTransport.CreateNonInviteTransaction(authenticatedRequest, sipTransaction.RemoteEndPoint, localSIPEndPoint, m_outboundProxy);
                            authTransaction.NonInviteTransactionFinalResponseReceived += AuthResponseReceived;
                            authTransaction.NonInviteTransactionTimedOut += RequestTimedOut;
                            m_sipTransport.SendSIPReliable(authTransaction);
                        }
                        else
                        {
                            Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentClient, SIPMonitorEventTypesEnum.DialPlan, "Send request received an authentication required response but no credentials were available.", m_owner));

                            if (ResponseReceived != null)
                            {
                                ResponseReceived(sipResponse);
                            }
                        }
                    }
                    else
                    {
                        Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentClient, SIPMonitorEventTypesEnum.DialPlan, "Send request failed with " + sipResponse.StatusCode + " but no authentication header was supplied for " + sipTransaction.TransactionRequest.Method + " to " + m_callDescriptor.Uri + ".", m_owner));

                        if (ResponseReceived != null)
                        {
                            ResponseReceived(sipResponse);
                        }
                    }
                }
                else
                {
                    if (ResponseReceived != null)
                    {
                        ResponseReceived(sipResponse);
                    }
                }
            }
            catch (Exception excp)
            {
                logger.Error("Exception SIPNonInviteClientUserAgent ServerResponseReceived (" + remoteEndPoint + "). " + excp.Message);
            }
        }
 private void LogSIPResponseOut(SIPEndPoint localSIPEndPoint, SIPEndPoint endPoint, SIPResponse sipResponse)
 {
     string message = "App Svr Sent: " + localSIPEndPoint.ToString() + "->" + endPoint.ToString() + "\r\n" + sipResponse.ToString();
     //logger.Debug("as: response out " + sipResponse.Header.CSeqMethod + " " + localSIPEndPoint.ToString() + "->" + endPoint.ToString() + ", callid=" + sipResponse.Header.CallId + ".");
     string fromUser = (sipResponse.Header.From != null && sipResponse.Header.From.FromURI != null) ? sipResponse.Header.From.FromURI.User : "******";
     FireSIPMonitorEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.FullSIPTrace, message, fromUser, localSIPEndPoint, endPoint));
 }
        /// <summary>
        /// The event handler for responses to the authenticated register request.
        /// </summary>
        private void AuthResponseReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPResponse sipResponse)
        {
            try
            {
                Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentClient, SIPMonitorEventTypesEnum.ContactRegisterInProgress, "Server auth response " + sipResponse.Status + " received for " + m_sipAccountAOR.ToString() + ".", m_owner));

                if (sipResponse.Status == SIPResponseStatusCodesEnum.Ok)
                {
                    if (m_expiry > 0)
                    {
                        ServiceRoute = sipResponse.Header.ServiceRoute;
                        m_isRegistered = true;
                        m_expiry = GetUpdatedExpiry(sipResponse);
                        //if (sipResponse.Header.SwitchboardToken != null && m_lastServerNonce != null)
                        //{
                        //    SwitchboardToken = Crypto.SymmetricDecrypt(m_password, m_lastServerNonce, sipResponse.Header.SwitchboardToken);
                        //}

                        if (RegistrationSuccessful != null)
                        {
                            RegistrationSuccessful(m_sipAccountAOR);
                        }
                    }
                    else
                    {
                        m_isRegistered = false;

                        if (RegistrationRemoved != null)
                        {
                            RegistrationRemoved(m_sipAccountAOR);
                        }
                    }

                    m_waitForRegistrationMRE.Set();
                }
                else if (sipResponse.Status == SIPResponseStatusCodesEnum.IntervalTooBrief && m_expiry != 0)
                {
                    m_expiry = GetUpdatedExpiryForIntervalTooBrief(sipResponse);
                    Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentClient, SIPMonitorEventTypesEnum.ContactRegisterInProgress, "Registration for " + m_sipAccountAOR.ToString() + " had a too short expiry, updated to +" + m_expiry + " and trying again.", m_owner));
                    SendInitialRegister();
                }
                else if (sipResponse.Status == SIPResponseStatusCodesEnum.Forbidden || sipResponse.Status == SIPResponseStatusCodesEnum.NotFound || sipResponse.Status == SIPResponseStatusCodesEnum.PaymentRequired)
                {
                    // SIP account does not appear to exist.
                    Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentClient, SIPMonitorEventTypesEnum.ContactRegisterFailed, "Registration failed with " + sipResponse.Status + " for " + m_sipAccountAOR.ToString() + ", no further registration attempts will be made.", m_owner));
                    string reasonPhrase = (sipResponse.ReasonPhrase.IsNullOrBlank()) ? sipResponse.Status.ToString() : sipResponse.ReasonPhrase;
                    if (RegistrationFailed != null)
                    {
                        RegistrationFailed(m_sipAccountAOR, "Registration failed with " + (int)sipResponse.Status + " " + reasonPhrase + ".");
                    }
                    m_exit = true;
                    m_waitForRegistrationMRE.Set();
                }
                else if (sipResponse.Status == SIPResponseStatusCodesEnum.ProxyAuthenticationRequired || sipResponse.Status == SIPResponseStatusCodesEnum.Unauthorised)
                {
                    // SIP account credentials failed.
                    Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentClient, SIPMonitorEventTypesEnum.ContactRegisterFailed, "Registration failed with " + sipResponse.Status + " for " + m_sipAccountAOR.ToString() + ", no further registration attempts will be made.", m_owner));
                    string reasonPhrase = (sipResponse.ReasonPhrase.IsNullOrBlank()) ? sipResponse.Status.ToString() : sipResponse.ReasonPhrase;
                    if (RegistrationFailed != null)
                    {
                        RegistrationFailed(m_sipAccountAOR, "Registration failed with " + (int)sipResponse.Status + " " + reasonPhrase + ".");
                    }
                    m_exit = true;
                    m_waitForRegistrationMRE.Set();
                }
                else
                {
                    Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentClient, SIPMonitorEventTypesEnum.ContactRegisterFailed, "Registration failed with " + sipResponse.Status + " for " + m_sipAccountAOR.ToString() + ".", m_owner));
                    m_isRegistered = false;
                    if (RegistrationTemporaryFailure != null)
                    {
                        RegistrationTemporaryFailure(m_sipAccountAOR, "Registration failed with " + sipResponse.Status + ".");
                    }
                    m_waitForRegistrationMRE.Set();
                }
            }
            catch (Exception excp)
            {
                logger.Error("Exception SIPRegistrationUserAgent AuthResponseReceived. " + excp.Message);
            }
        }
Example #47
0
        private void ProcessRedirect(ISIPClientUserAgent answeredUAC, SIPResponse answeredResponse)
        {
            try
            {
                SIPURI redirectURI = answeredResponse.Header.Contact[0].ContactURI;

                if (redirectURI == null)
                {
                    FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Redirect target could not be determined from redirect response, ignoring.", m_username));
                }
                else
                {
                    //string canincalDomain = m_dialPlanContext.GetCanonicalDomain_External(redirectURI.Host, false);

                    if (answeredUAC.CallDescriptor.RedirectMode == SIPCallRedirectModesEnum.NewDialPlan)
                    {
                        m_dialPlanContext.ExecuteDialPlanForRedirect(answeredResponse);
                    }
                    else if (answeredUAC.CallDescriptor.RedirectMode == SIPCallRedirectModesEnum.Manual)
                    {
                        FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Redirect response with URI " + redirectURI.ToString() + " was not acted on as redirect mode set to manual in dial string.", m_username));
                        CallLegCompleted();
                    }
                    else
                    {
                        // The redirect was not explicitly allowed so will be processed as an anonymous call.
                        FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Redirect response to " + redirectURI.ToString() + " accepted.", m_username));
                        var redirectCalls = m_dialStringParser.GetForwardsForRedirect(redirectURI, answeredUAC.CallDescriptor);
                        //SIPCallDescriptor redirectCallDescriptor = answeredUAC.CallDescriptor.CopyOf();
                        //redirectCallDescriptor.Uri = redirectURI.ToString();
                        //StartNewCallAsync(redirectCallDescriptor);
                        if (redirectCalls != null && redirectCalls.Count > 0)
                        {
                            foreach (var redirectCall in redirectCalls)
                            {
                                StartNewCallAsync(redirectCall);
                            }
                        }
                    }
                    //else if (answeredUAC.CallDescriptor.RedirectMode == SIPCallRedirectModesEnum.Replace)
                    //{
                    //    // In the Replace redirect mode the existing dialplan execution needs to be cancelled and the single redirect call be used to replace it.
                    //    FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Redirect response rejected as Replace mode not yet implemented.", m_username));
                    //    CallLegCompleted();
                    //}
                    //else
                    //{
                    //    FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Redirect response with URI " + redirectURI.ToString() + " was not acted on as not enabled in dial string.", m_username));
                    //    CallLegCompleted();
                    //}

                    // A redirect response was received. Create a new call leg(s) using the SIP URIs in the contact header of the response.
                    //if (m_dialStringParser != null)
                    //{
                    //    // If there is a dial string parser available it will be used to generate a list of call destination from the redirect URI.
                    //    SIPCallDescriptor redirectCallDescriptor = answeredUAC.CallDescriptor.CopyOf();
                    //    Queue<List<SIPCallDescriptor>> redirectQueue = m_dialStringParser.ParseDialString(DialPlanContextsEnum.Script, null, redirectURI.ToString(), redirectCallDescriptor.CustomHeaders,
                    //        redirectCallDescriptor.ContentType, redirectCallDescriptor.Content, null, redirectCallDescriptor.FromDisplayName, redirectCallDescriptor.FromURIUsername, redirectCallDescriptor.FromURIHost, null, CustomerServiceLevels.None);

                    //    if (redirectQueue != null && redirectQueue.Count > 0)
                    //    {
                    //        // Only the first list in the queue is used (and there should only be a single list since it's generated from a redirect SIP URI and not
                    //        // a full dial string).
                    //        List<SIPCallDescriptor> callDescriptors = redirectQueue.Dequeue();
                    //        for (int index = 0; index < callDescriptors.Count; index++)
                    //        {
                    //            callDescriptors[index].MangleIPAddress = redirectCallDescriptor.MangleIPAddress;
                    //            callDescriptors[index].MangleResponseSDP = redirectCallDescriptor.MangleResponseSDP;
                    //            callDescriptors[index].TransferMode = redirectCallDescriptor.TransferMode;
                    //        }
                    //        Start(callDescriptors);
                    //    }
                    //    else
                    //    {
                    //        FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "A redirect response to " + redirectURI.ToString() + " did not generate any new call leg destinations.", m_username));
                    //    }
                    //}
                    //else
                    //{
                    //    FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Redirect response to " + redirectURI.ToString() + " accepted.", m_username));
                    //    SIPCallDescriptor redirectCallDescriptor = answeredUAC.CallDescriptor.CopyOf();
                    //    redirectCallDescriptor.Uri = redirectURI.ToString();
                    //    StartNewCallAsync(redirectCallDescriptor);
                    //}
                }
            }
            catch (Exception excp)
            {
                logger.Error("Exception ForkCall ProcessRedirect. " + excp.Message);
            }
        }
        private SIPRequest GetAuthenticatedRegistrationRequest(SIPRequest registerRequest, SIPResponse sipResponse)
        {
            try
            {
                SIPAuthorisationDigest authRequest = sipResponse.Header.AuthenticationHeader.SIPDigest;
                m_lastServerNonce = authRequest.Nonce;
                string username = (m_authUsername != null) ? m_authUsername : m_sipAccountAOR.User;
                authRequest.SetCredentials(username, m_password, registerRequest.URI.ToString(), SIPMethodsEnum.REGISTER.ToString());

                SIPRequest regRequest = registerRequest.Copy();
                regRequest.LocalSIPEndPoint = registerRequest.LocalSIPEndPoint;
                regRequest.Header.Vias.TopViaHeader.Branch = CallProperties.CreateBranchId();
                regRequest.Header.From.FromTag = CallProperties.CreateNewTag();
                regRequest.Header.To.ToTag = null;
                regRequest.Header.CSeq = ++m_cseq;

                regRequest.Header.AuthenticationHeader = new SIPAuthenticationHeader(authRequest);
                regRequest.Header.AuthenticationHeader.SIPDigest.Response = authRequest.Digest;

                //if (RequestSwitchboardToken)
                //{
                //    regRequest.Header.SwitchboardTokenRequest = m_expiry;
                //}

                return regRequest;
            }
            catch (Exception excp)
            {
                logger.Error("Exception GetAuthenticatedRegistrationRequest. " + excp.Message);
                throw excp;
            }
        }
Example #49
0
 private void UACCallProgress(ISIPClientUserAgent uac, SIPResponse progressResponse)
 {
     try
     {
         if (m_commandCancelled)
         {
             //logger.Debug("Call " + uac.CallDescriptor.Uri + " should not be in a progress state after a cancel. Cancel again.");
             uac.Cancel();
         }
         else
         {
             CallProgress(progressResponse.Status, progressResponse.ReasonPhrase, null, progressResponse.Header.ContentType, progressResponse.Body, uac);
         }
     }
     catch (Exception excp)
     {
         logger.Error("Exception ForkCall UACCallProgress. " + excp);
     }
 }
Example #50
0
        private async Task <SocketError> UACInviteTransaction_TransactionInformationResponseReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPResponse sipResponse)
        {
            try
            {
                if (sipResponse.StatusCode > 100 && sipResponse.StatusCode <= 199)
                {
                    if (sipResponse.Header.RSeq > 0)
                    {
                        // Send a PRACK for this provisional response.
                        m_cseq++;
                        PRackRequest = GetAcknowledgeRequest(sipResponse, SIPMethodsEnum.PRACK, m_cseq, null, null);
                        await SendRequestAsync(PRackRequest).ConfigureAwait(false);
                    }
                }

                if (CDR != null)
                {
                    SIPEndPoint localEP  = SIPEndPoint.TryParse(sipResponse.Header.ProxyReceivedOn) ?? localSIPEndPoint;
                    SIPEndPoint remoteEP = SIPEndPoint.TryParse(sipResponse.Header.ProxyReceivedFrom) ?? remoteEndPoint;
                    CDR.Progress(sipResponse.Status, sipResponse.ReasonPhrase, localEP, remoteEP);
                }

                if (UACInviteTransactionInformationResponseReceived != null)
                {
                    return(await UACInviteTransactionInformationResponseReceived(localSIPEndPoint, remoteEndPoint, sipTransaction, sipResponse).ConfigureAwait(false));
                }
                else
                {
                    return(SocketError.Success);
                }
            }
            catch (Exception excp)
            {
                logger.LogError("Exception UACInviteTransaction_TransactionInformationResponseReceived. " + excp.Message);
                return(SocketError.Fault);
            }
        }