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); } }
/// <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; } }
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; } }
/// <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; } } }
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); } }
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)); }
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); } } }
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); } } }
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); } }
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); } }
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 + "."); } } }
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; }
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); }
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); }
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); }
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); } }
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); } }
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); } }
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; } }
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); } }
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); } }