private void ServerFinalResponseReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPResponse sipResponse)
{
try
{
//if (Thread.CurrentThread.Name.IsNullOrBlank())
//{
// Thread.CurrentThread.Name = THREAD_NAME + DateTime.Now.ToString("HHmmss") + "-" + Crypto.GetRandomString(3);
//}
Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentClient, SIPMonitorEventTypesEnum.DialPlan, "Response " + sipResponse.StatusCode + " " + sipResponse.ReasonPhrase + " for " + m_serverTransaction.TransactionRequest.URI.ToString() + ".", Owner));
//m_sipTrace += "Received " + DateTime.Now.ToString("dd MMM yyyy HH:mm:ss") + " " + localEndPoint + "<-" + remoteEndPoint + "\r\n" + sipResponse.ToString();
m_serverTransaction.UACInviteTransactionInformationResponseReceived -= ServerInformationResponseReceived;
m_serverTransaction.UACInviteTransactionFinalResponseReceived -= ServerFinalResponseReceived;
m_serverTransaction.TransactionTraceMessage -= TransactionTraceMessage;
if (m_callCancelled && sipResponse.Status == SIPResponseStatusCodesEnum.RequestTerminated)
{
// No action required. Correctly received request terminated on an INVITE we cancelled.
}
else if (m_callCancelled)
{
#region Call has been cancelled, hangup.
if (m_hungupOnCancel)
{
Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentClient, SIPMonitorEventTypesEnum.DialPlan, "A cancelled call to " + m_sipCallDescriptor.Uri + " has been answered AND has already been hungup, no further action being taken.", Owner));
}
else
{
m_hungupOnCancel = true;
Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentClient, SIPMonitorEventTypesEnum.DialPlan, "A cancelled call to " + m_sipCallDescriptor.Uri + " has been answered, hanging up.", Owner));
if (sipResponse.Header.Contact != null && sipResponse.Header.Contact.Count > 0)
{
SIPURI byeURI = sipResponse.Header.Contact[0].ContactURI;
SIPRequest byeRequest = GetByeRequest(sipResponse, byeURI, localSIPEndPoint);
//SIPEndPoint byeEndPoint = m_sipTransport.GetRequestEndPoint(byeRequest, m_outboundProxy, true);
// if (byeEndPoint != null)
// {
SIPNonInviteTransaction byeTransaction = m_sipTransport.CreateNonInviteTransaction(byeRequest, null, localSIPEndPoint, m_outboundProxy);
byeTransaction.SendReliableRequest();
// }
// else
// {
// Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentClient, SIPMonitorEventTypesEnum.DialPlan, "Could not end BYE on cancelled call as request end point could not be determined " + byeRequest.URI.ToString(), Owner));
//}
}
else
{
Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentClient, SIPMonitorEventTypesEnum.DialPlan, "No contact header provided on response for cancelled call to " + m_sipCallDescriptor.Uri + " no further action.", Owner));
}
}
#endregion
}
else if (sipResponse.Status == SIPResponseStatusCodesEnum.ProxyAuthenticationRequired || sipResponse.Status == SIPResponseStatusCodesEnum.Unauthorised)
{
#region Authenticate client call to third party server.
if (!m_callCancelled)
{
if (m_sipCallDescriptor.Password.IsNullOrBlank())
{
// No point trying to authenticate if there is no password to use.
Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentClient, SIPMonitorEventTypesEnum.DialPlan, "Forward leg failed, authentication was requested but no credentials were available.", Owner));
FireCallFailed(this, "Authentication requested when no credentials available");
}
else if (m_serverAuthAttempts == 0)
{
m_serverAuthAttempts = 1;
// Resend INVITE with credentials.
string username = (m_sipCallDescriptor.AuthUsername != null && m_sipCallDescriptor.AuthUsername.Trim().Length > 0) ? m_sipCallDescriptor.AuthUsername : m_sipCallDescriptor.Username;
SIPAuthorisationDigest authRequest = sipResponse.Header.AuthenticationHeader.SIPDigest;
authRequest.SetCredentials(username, m_sipCallDescriptor.Password, m_sipCallDescriptor.Uri, SIPMethodsEnum.INVITE.ToString());
SIPRequest authInviteRequest = m_serverTransaction.TransactionRequest;
authInviteRequest.Header.AuthenticationHeader = new SIPAuthenticationHeader(authRequest);
authInviteRequest.Header.AuthenticationHeader.SIPDigest.Response = authRequest.Digest;
authInviteRequest.Header.Vias.TopViaHeader.Branch = CallProperties.CreateBranchId();
authInviteRequest.Header.CSeq = authInviteRequest.Header.CSeq + 1;
// Create a new UAC transaction to establish the authenticated server call.
var originalCallTransaction = m_serverTransaction;
m_serverTransaction = m_sipTransport.CreateUACTransaction(authInviteRequest, m_serverEndPoint, localSIPEndPoint, m_outboundProxy);
if (m_serverTransaction.CDR != null)
{
m_serverTransaction.CDR.Owner = Owner;
m_serverTransaction.CDR.AdminMemberId = AdminMemberId;
m_serverTransaction.CDR.DialPlanContextID = m_sipCallDescriptor.DialPlanContextID;
m_serverTransaction.CDR.Updated();
if (AccountCode != null)
{
#if !SILVERLIGHT
RtccUpdateCdr_External?.Invoke(originalCallTransaction.CDR?.CDRId.ToString(), m_serverTransaction.CDR);
#endif
}
logger.Debug("RTCC reservation was reallocated from CDR " + originalCallTransaction.CDR?.CDRId + " to " + m_serverTransaction.CDR?.CDRId + " for owner " + Owner + ".");
}
m_serverTransaction.UACInviteTransactionInformationResponseReceived += ServerInformationResponseReceived;
m_serverTransaction.UACInviteTransactionFinalResponseReceived += ServerFinalResponseReceived;
m_serverTransaction.UACInviteTransactionTimedOut += ServerTimedOut;
m_serverTransaction.TransactionTraceMessage += TransactionTraceMessage;
m_serverTransaction.SendInviteRequest(m_serverEndPoint, authInviteRequest);
}
else
{
FireCallFailed(this, "Authentication with provided credentials failed");
}
}
#endregion
}
else
{
if (sipResponse.StatusCode >= 200 && sipResponse.StatusCode <= 299)
{
if (sipResponse.Body.IsNullOrBlank())
{
Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Body on UAC response was empty.", Owner));
}
else if (m_sipCallDescriptor.ContentType == m_sdpContentType)
{
if (!m_sipCallDescriptor.MangleResponseSDP)
{
IPEndPoint sdpEndPoint = SDP.GetSDPRTPEndPoint(sipResponse.Body);
string sdpSocket = (sdpEndPoint != null) ? sdpEndPoint.ToString() : "could not determine";
Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "SDP on UAC response was set to NOT mangle, RTP socket " + sdpEndPoint.ToString() + ".", Owner));
}
else
{
//m_callInProgress = false; // the call is now established
//logger.Debug("Final response " + sipResponse.StatusCode + " " + sipResponse.ReasonPhrase + " for " + ForwardedTransaction.TransactionRequest.URI.ToString() + ".");
// Determine of response SDP should be mangled.
IPEndPoint sdpEndPoint = SDP.GetSDPRTPEndPoint(sipResponse.Body);
//Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "UAC response SDP was mangled from sdp=" + sdpEndPoint.Address.ToString() + ", proxyfrom=" + sipResponse.Header.ProxyReceivedFrom + ", mangle=" + m_sipCallDescriptor.MangleResponseSDP + ".", null));
if (sdpEndPoint != null)
{
if (!IPSocket.IsPrivateAddress(sdpEndPoint.Address.ToString()))
{
Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "SDP on UAC response had public IP not mangled, RTP socket " + sdpEndPoint.ToString() + ".", Owner));
}
else
{
bool wasSDPMangled = false;
string publicIPAddress = null;
if (!sipResponse.Header.ProxyReceivedFrom.IsNullOrBlank())
{
IPAddress remoteUASAddress = SIPEndPoint.ParseSIPEndPoint(sipResponse.Header.ProxyReceivedFrom).Address;
if (IPSocket.IsPrivateAddress(remoteUASAddress.ToString()) && m_sipCallDescriptor.MangleIPAddress != null)
{
// If the response has arrived here on a private IP address then it must be
// for a local version install and an incoming call that needs it's response mangled.
if(!IPSocket.IsPrivateAddress(m_sipCallDescriptor.MangleIPAddress.ToString()))
{
publicIPAddress = m_sipCallDescriptor.MangleIPAddress.ToString();
}
}
else
{
publicIPAddress = remoteUASAddress.ToString();
}
}
else if (!IPSocket.IsPrivateAddress(remoteEndPoint.Address.ToString()) && remoteEndPoint.Address != IPAddress.Any)
{
publicIPAddress = remoteEndPoint.Address.ToString();
}
else if (m_sipCallDescriptor.MangleIPAddress != null)
{
publicIPAddress = m_sipCallDescriptor.MangleIPAddress.ToString();
}
if (publicIPAddress != null)
{
sipResponse.Body = SIPPacketMangler.MangleSDP(sipResponse.Body, publicIPAddress, out wasSDPMangled);
}
if (wasSDPMangled)
{
Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "SDP on UAC response had RTP socket mangled from " + sdpEndPoint.ToString() + " to " + publicIPAddress + ":" + sdpEndPoint.Port + ".", Owner));
}
else if (sdpEndPoint != null)
{
Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "SDP on UAC response could not be mangled, RTP socket " + sdpEndPoint.ToString() + ".", Owner));
}
}
}
else
{
Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "SDP RTP socket on UAC response could not be determined.", Owner));
}
}
}
m_sipDialogue = new SIPDialogue(m_serverTransaction, Owner, AdminMemberId);
m_sipDialogue.CallDurationLimit = m_sipCallDescriptor.CallDurationLimit;
// Set switchboard dialogue values from the answered response or from dialplan set values.
//m_sipDialogue.SwitchboardCallerDescription = sipResponse.Header.SwitchboardCallerDescription;
m_sipDialogue.SwitchboardLineName = sipResponse.Header.SwitchboardLineName;
m_sipDialogue.CRMPersonName = sipResponse.Header.CRMPersonName;
m_sipDialogue.CRMCompanyName = sipResponse.Header.CRMCompanyName;
m_sipDialogue.CRMPictureURL = sipResponse.Header.CRMPictureURL;
if (m_sipCallDescriptor.SwitchboardHeaders != null)
{
//if (!m_sipCallDescriptor.SwitchboardHeaders.SwitchboardDialogueDescription.IsNullOrBlank())
//{
// m_sipDialogue.SwitchboardDescription = m_sipCallDescriptor.SwitchboardHeaders.SwitchboardDialogueDescription;
//}
m_sipDialogue.SwitchboardLineName = m_sipCallDescriptor.SwitchboardHeaders.SwitchboardLineName;
m_sipDialogue.SwitchboardOwner = m_sipCallDescriptor.SwitchboardHeaders.SwitchboardOwner;
}
}
FireCallAnswered(this, sipResponse);
}
}
catch (Exception excp)
{
Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentClient, SIPMonitorEventTypesEnum.Error, "Exception ServerFinalResponseReceived. " + excp.Message, Owner));
}
}