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); } } }
private void SIPNonInviteTransaction_TransactionTimedOut(SIPTransaction sipTransaction) { if (NonInviteTransactionTimedOut != null) { NonInviteTransactionTimedOut(this); } }
private void SIPCancelTransaction_TransactionRequestReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPRequest sipRequest) { try { //logger.Debug("CANCEL request received, attempting to locate and cancel transaction."); //UASInviteTransaction originalTransaction = (UASInviteTransaction)GetTransaction(GetRequestTransactionId(sipRequest.Header.Via.TopViaHeader.Branch, SIPMethodsEnum.INVITE)); SIPResponse cancelResponse; if (m_originalTransaction != null) { //logger.Debug("Transaction found to cancel " + originalTransaction.TransactionId + " type " + originalTransaction.TransactionType + "."); m_originalTransaction.CancelCall(); cancelResponse = GetCancelResponse(sipRequest, SIPResponseStatusCodesEnum.Ok); } else { cancelResponse = GetCancelResponse(sipRequest, SIPResponseStatusCodesEnum.CallLegTransactionDoesNotExist); } //UpdateTransactionState(SIPTransactionStatesEnum.Completed); SendFinalResponse(cancelResponse); } catch (Exception excp) { logger.Error("Exception SIPCancelTransaction GotRequest. " + excp.Message); } }
private void SIPNonInviteTransaction_TransactionRequestReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPRequest sipRequest) { if (NonInviteRequestReceived != null) { NonInviteRequestReceived(localSIPEndPoint, remoteEndPoint, this, sipRequest); } }
private void SIPNonInviteTransaction_TransactionRemoved(SIPTransaction transaction) { // Remove all event handlers. NonInviteTransactionInfoResponseReceived = null; NonInviteTransactionFinalResponseReceived = null; NonInviteTransactionTimedOut = null; NonInviteRequestReceived = null; }
private void UACInviteTransaction_TransactionRemoved(SIPTransaction transaction) { // Remove event handlers. UACInviteTransactionInformationResponseReceived = null; UACInviteTransactionFinalResponseReceived = null; UACInviteTransactionTimedOut = null; CDR = null; }
public void AddTransaction(SIPTransaction sipTransaction) { RemoveExpiredTransactions(); lock (m_transactions) { if (!m_transactions.ContainsKey(sipTransaction.TransactionId)) { m_transactions.Add(sipTransaction.TransactionId, sipTransaction); } else { throw new ApplicationException("An attempt was made to add a duplicate SIP transaction."); } } }
private void UASInviteTransaction_TransactionTimedOut(SIPTransaction sipTransaction) { UASInviteTransactionTimedOut?.Invoke(this); CDR?.TimedOut(); }
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); } }
/// <summary> /// The event handler for responses to the authenticated register request. /// </summary> private void AuthResponseReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPResponse sipResponse) { string reasonPhrase = (sipResponse.ReasonPhrase.IsNullOrBlank()) ? sipResponse.Status.ToString() : sipResponse.ReasonPhrase; Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentClient, SIPMonitorEventTypesEnum.DialPlan, "Server response " + sipResponse.Status + " " + reasonPhrase + " received for authenticated " + sipTransaction.TransactionRequest.Method + " to " + m_callDescriptor.Uri + ".", m_owner)); if (ResponseReceived != null) { ResponseReceived(sipResponse); } }
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); } }
/// <summary> /// Sends a SIP request/response and keeps track of whether a response/acknowledgement has been received. If no response is received then periodic retransmits are made /// for up to T1 x 64 seconds. /// </summary> public void SendSIPReliable(SIPTransaction sipTransaction) { if (sipTransaction.RemoteEndPoint != null && sipTransaction.RemoteEndPoint.Address.Equals(BlackholeAddress)) { sipTransaction.Retransmits = 1; sipTransaction.InitialTransmit = DateTime.Now; sipTransaction.LastTransmit = DateTime.Now; sipTransaction.DeliveryPending = false; return; } if (m_sipChannels.Count == 0) { throw new ApplicationException("No channels are configured in the SIP transport layer. The request could not be sent."); } else if (m_reliableTransmissions.Count >= MAX_RELIABLETRANSMISSIONS_COUNT) { throw new ApplicationException("Cannot send reliable SIP message as the reliable transmissions queue is full."); } //logger.Debug("SendSIPReliable transaction URI " + sipTransaction.TransactionRequest.URI.ToString() + "."); if (sipTransaction.TransactionType == SIPTransactionTypesEnum.Invite && sipTransaction.TransactionState == SIPTransactionStatesEnum.Completed) { // This is an INVITE transaction that wants to send a reliable response. if (sipTransaction.LocalSIPEndPoint == null) { throw new ApplicationException("The SIPTransport layer cannot send a reliable SIP response because the send from socket has not been set for the transaction."); } else { SIPViaHeader topViaHeader = sipTransaction.TransactionFinalResponse.Header.Vias.TopViaHeader; SendResponse(sipTransaction.TransactionFinalResponse); } } else { if (sipTransaction.OutboundProxy != null) { SendRequest(sipTransaction.OutboundProxy, sipTransaction.TransactionRequest); } else if (sipTransaction.RemoteEndPoint != null) { SendRequest(sipTransaction.RemoteEndPoint, sipTransaction.TransactionRequest); } else { SendRequest(sipTransaction.TransactionRequest); } } sipTransaction.Retransmits = 1; sipTransaction.InitialTransmit = DateTime.Now; sipTransaction.LastTransmit = DateTime.Now; sipTransaction.DeliveryPending = true; if (!m_reliableTransmissions.ContainsKey(sipTransaction.TransactionId)) { lock (m_reliableTransmissions) { m_reliableTransmissions.Add(sipTransaction.TransactionId, sipTransaction); } } if (!m_reliablesThreadRunning) { StartReliableTransmissionsThread(); } }
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 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); } }
public void RemoveExpiredTransactions() { try { lock (m_transactions) { List <string> expiredTransactionIds = new List <string>(); foreach (SIPTransaction transaction in m_transactions.Values) { if (transaction.TransactionType == SIPTransactionTypesEnum.Invite) { if (transaction.TransactionState == SIPTransactionStatesEnum.Confirmed) { // Need to wait until the transaction timeout period is reached in case any ACK re-transmits are received. if (DateTime.Now.Subtract(transaction.CompletedAt).TotalMilliseconds >= m_t6) { expiredTransactionIds.Add(transaction.TransactionId); } } else if (transaction.TransactionState == SIPTransactionStatesEnum.Completed) { if (DateTime.Now.Subtract(transaction.CompletedAt).TotalMilliseconds >= m_t6) { expiredTransactionIds.Add(transaction.TransactionId); } } else if (transaction.HasTimedOut) { // For INVITES need to give timed out transactions time to send the reliable repsonses and receive the ACKs. if (DateTime.Now.Subtract(transaction.TimedOutAt).TotalSeconds >= m_t6) { expiredTransactionIds.Add(transaction.TransactionId); } } else if (transaction.TransactionState == SIPTransactionStatesEnum.Proceeding) { if (DateTime.Now.Subtract(transaction.Created).TotalMilliseconds >= m_maxRingTime) { // INVITE requests that have been ringing too long. transaction.HasTimedOut = true; transaction.TimedOutAt = DateTime.Now; transaction.DeliveryPending = false; transaction.DeliveryFailed = true; transaction.FireTransactionTimedOut(); } } else if (DateTime.Now.Subtract(transaction.Created).TotalMilliseconds >= m_t6) { //logger.Debug("INVITE transaction (" + transaction.TransactionId + ") " + transaction.TransactionRequestURI.ToString() + " in " + transaction.TransactionState + " has been alive for " + DateTime.Now.Subtract(transaction.Created).TotalSeconds.ToString("0") + "."); if (transaction.TransactionState == SIPTransactionStatesEnum.Calling || transaction.TransactionState == SIPTransactionStatesEnum.Trying) { transaction.HasTimedOut = true; transaction.TimedOutAt = DateTime.Now; transaction.DeliveryPending = false; transaction.DeliveryFailed = true; transaction.FireTransactionTimedOut(); } } } else if (transaction.HasTimedOut) { expiredTransactionIds.Add(transaction.TransactionId); } else if (DateTime.Now.Subtract(transaction.Created).TotalMilliseconds >= m_t6) { if (transaction.TransactionState == SIPTransactionStatesEnum.Calling || transaction.TransactionState == SIPTransactionStatesEnum.Trying || transaction.TransactionState == SIPTransactionStatesEnum.Proceeding) { //logger.Warn("Timed out transaction in SIPTransactionEngine, should have been timed out in the SIP Transport layer. " + transaction.TransactionRequest.Method + "."); transaction.DeliveryPending = false; transaction.DeliveryFailed = true; transaction.TimedOutAt = DateTime.Now; transaction.HasTimedOut = true; transaction.FireTransactionTimedOut(); } expiredTransactionIds.Add(transaction.TransactionId); } } foreach (string transactionId in expiredTransactionIds) { if (m_transactions.ContainsKey(transactionId)) { SIPTransaction expiredTransaction = m_transactions[transactionId]; expiredTransaction.FireTransactionRemoved(); RemoveTransaction(expiredTransaction); } } } //PrintPendingTransactions(); } catch (Exception excp) { logger.Error("Exception RemoveExpiredTransaction. " + excp.Message); } }
private void RemoveTransaction(SIPTransaction transaction) { // Remove all event handlers. transaction.RemoveEventHandlers(); RemoveTransaction(transaction.TransactionId); }
private void SIPCancelTransaction_TransactionRequestReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPRequest sipRequest) { try { //logger.LogDebug("CANCEL request received, attempting to locate and cancel transaction."); //UASInviteTransaction originalTransaction = (UASInviteTransaction)GetTransaction(GetRequestTransactionId(sipRequest.Header.Via.TopViaHeader.Branch, SIPMethodsEnum.INVITE)); SIPResponse cancelResponse; if (m_originalTransaction != null) { //logger.LogDebug("Transaction found to cancel " + originalTransaction.TransactionId + " type " + originalTransaction.TransactionType + "."); m_originalTransaction.CancelCall(); cancelResponse = GetCancelResponse(sipRequest, SIPResponseStatusCodesEnum.Ok); } else { cancelResponse = GetCancelResponse(sipRequest, SIPResponseStatusCodesEnum.CallLegTransactionDoesNotExist); } //UpdateTransactionState(SIPTransactionStatesEnum.Completed); SendFinalResponse(cancelResponse); } catch (Exception excp) { logger.LogError("Exception SIPCancelTransaction GotRequest. " + excp.Message); } }
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 SIPCancelTransaction_TransactionRemoved(SIPTransaction transaction) { // Remove event handlers. CancelTransactionFinalResponseReceived = null; }
private Task <SocketError> UASInviteTransaction_TransactionRequestReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPRequest sipRequest) { try { if (TransactionState == SIPTransactionStatesEnum.Terminated) { logger.LogDebug("Request received by UASInviteTransaction for a terminated transaction, ignoring."); } else if (sipRequest.Method != SIPMethodsEnum.INVITE) { logger.LogWarning("Unexpected " + sipRequest.Method + " passed to UASInviteTransaction."); } else { if (TransactionState != SIPTransactionStatesEnum.Trying) { SIPResponse tryingResponse = GetInfoResponse(m_transactionRequest, SIPResponseStatusCodesEnum.Trying); SendProvisionalResponse(tryingResponse); } // Notify new call subscribers. if (NewCallReceived != null) { NewCallReceived(localSIPEndPoint, remoteEndPoint, this, sipRequest); } else { // Nobody wants to answer this call so return an error response. SIPResponse declinedResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Decline, "Nothing listening"); SendFinalResponse(declinedResponse); } } return(Task.FromResult(SocketError.Success)); } catch (Exception excp) { logger.LogError("Exception UASInviteTransaction GotRequest. " + excp.Message); return(Task.FromResult(SocketError.Fault)); } }
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).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); } }
void SetTransactionTraceEvents(SIPTransaction transaction) { transaction.TransactionRemoved += new SIPTransactionRemovedDelegate(transaction_TransactionRemoved); transaction.TransactionStateChanged += new SIPTransactionStateChangeDelegate(transaction_TransactionStateChanged); transaction.TransactionTraceMessage += new SIPTransactionTraceMessageDelegate(transaction_TransactionTraceMessage); }
/// <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); } }
void transaction_TransactionTraceMessage(SIPTransaction sipTransaction, string message) { //Console.WriteLine(sipTransaction.GetType() + " Trace (" + sipTransaction.TransactionId + "): " + message); }
private void UACInviteTransaction_TransactionRequestReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPRequest sipRequest) { logger.Warn("UACInviteTransaction received unexpected request, " + sipRequest.Method + " from " + remoteEndPoint.ToString() + ", ignoring."); }
void transaction_TransactionStateChanged(SIPTransaction sipTransaction) { Console.WriteLine(sipTransaction.GetType() + " State Change (" + sipTransaction.TransactionId + "): " + sipTransaction.TransactionState); }
private void SIPNonInviteTransaction_TransactionFinalResponseReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPResponse sipResponse) { if (NonInviteTransactionFinalResponseReceived != null) { NonInviteTransactionFinalResponseReceived(localSIPEndPoint, remoteEndPoint, this, sipResponse); } }
private void UASTransactionCancelled(SIPTransaction sipTransaction) { logger.Debug("SIPServerUserAgent got cancellation request."); m_isCancelled = true; if (CallCancelled != null) { CallCancelled(this); } }
void transaction_TransactionRemoved(SIPTransaction sipTransaction) { Console.WriteLine(sipTransaction.GetType() + " Removed (" + sipTransaction.TransactionId + ")"); }
private void UASInviteTransaction_TransactionResponseReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPResponse sipResponse) { logger.LogWarning("UASInviteTransaction received unexpected response, " + sipResponse.ReasonPhrase + " from " + remoteEndPoint.ToString() + ", ignoring."); }
private void RequestTimedOut(SIPTransaction sipTransaction) { Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentClient, SIPMonitorEventTypesEnum.DialPlan, "Attempt to send " + sipTransaction.TransactionRequest.Method +" to " + m_callDescriptor.Uri + " timed out.", m_owner)); }
private void UASInviteTransaction_TransactionRemoved(SIPTransaction transaction) { // Remove event handlers. UASInviteTransactionCancelled = null; NewCallReceived = null; UASInviteTransactionTimedOut = null; CDR = null; }
private Task <SocketError> UACInviteTransaction_TransactionRequestReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPRequest sipRequest) { logger.LogWarning("UACInviteTransaction received unexpected request, " + sipRequest.Method + " from " + remoteEndPoint.ToString() + ", ignoring."); return(Task.FromResult(SocketError.Fault)); }
private void UASInviteTransaction_TransactionRequestReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPRequest sipRequest) { try { if (TransactionState == SIPTransactionStatesEnum.Terminated) { logger.Debug("Request received by UASInviteTransaction for a terminated transaction, ignoring."); } else if (sipRequest.Method != SIPMethodsEnum.INVITE) { logger.Warn("Unexpected " + sipRequest.Method + " passed to UASInviteTransaction."); } else { if (TransactionState != SIPTransactionStatesEnum.Trying) { SIPResponse tryingResponse = GetInfoResponse(m_transactionRequest, SIPResponseStatusCodesEnum.Trying); SendInformationalResponse(tryingResponse); } // Notify new call subscribers. if (NewCallReceived != null) { NewCallReceived(localSIPEndPoint, remoteEndPoint, this, sipRequest); } else { // Nobody wants the call so return an error response. SIPResponse declinedResponse = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Decline, "Nothing listening"); SendFinalResponse(declinedResponse); } } } catch (Exception excp) { logger.Error("Exception UASInviteTransaction GotRequest. " + excp.Message); } }
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)); }
private void UASInviteTransaction_TransactionResponseReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPResponse sipResponse) { logger.Warn("UASInviteTransaction received unexpected response, " + sipResponse.ReasonPhrase + " from " + remoteEndPoint.ToString() + ", ignoring."); }
private Task <SocketError> UASInviteTransaction_OnAckRequestReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPRequest sipRequest) { return(OnAckReceived?.Invoke(localSIPEndPoint, remoteEndPoint, this, sipRequest)); }
private void UASInviteTransaction_TransactionTimedOut(SIPTransaction sipTransaction) { if (UASInviteTransactionTimedOut != null) { UASInviteTransactionTimedOut(this); } if (CDR != null) { CDR.TimedOut(); } }
private async Task <SocketError> UACInviteTransaction_TransactionFinalResponseReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPResponse sipResponse) { try { DeliveryPending = false; base.UpdateTransactionState(SIPTransactionStatesEnum.Confirmed); // 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).ConfigureAwait(false); } } 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).ConfigureAwait(false); } 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); } if (UACInviteTransactionFinalResponseReceived != null) { return(await UACInviteTransactionFinalResponseReceived(localSIPEndPoint, remoteEndPoint, sipTransaction, sipResponse).ConfigureAwait(false)); } else { return(SocketError.Success); } } catch (Exception excp) { logger.LogError($"Exception UACInviteTransaction_TransactionFinalResponseReceived. {excp.Message}"); return(SocketError.Fault); } }
private void UASInviteTransaction_TransactionFailed(SIPTransaction sipTransaction, SocketError failureReason) { UASInviteTransactionFailed?.Invoke(this, failureReason); CDR?.TimedOut(); }
private void RegistrationTimedOut(SIPTransaction sipTransaction) { m_isRegistered = false; if (RegistrationTemporaryFailure != null) { RegistrationTemporaryFailure(m_sipAccountAOR, "Registration transaction to " + m_registrarHost + " for " + m_sipAccountAOR.ToString() + " timed out."); } m_waitForRegistrationMRE.Set(); }
private void SIPNonInviteTransaction_TransactionTimedOut(SIPTransaction sipTransaction) { NonInviteTransactionTimedOut?.Invoke(this); }
private RegisterResultEnum Register(SIPTransaction registerTransaction) { try { SIPRequest sipRequest = registerTransaction.TransactionRequest; SIPURI registerURI = sipRequest.URI; SIPToHeader toHeader = sipRequest.Header.To; string toUser = toHeader.ToURI.User; string canonicalDomain = (m_strictRealmHandling) ? GetCanonicalDomain_External(toHeader.ToURI.Host, true) : toHeader.ToURI.Host; int requestedExpiry = GetRequestedExpiry(sipRequest); if (canonicalDomain == null) { FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Registrar, SIPMonitorEventTypesEnum.Warn, "Register request for " + toHeader.ToURI.Host + " rejected as no matching domain found.", null)); SIPResponse noDomainResponse = GetErrorResponse(sipRequest, SIPResponseStatusCodesEnum.Forbidden, "Domain not serviced"); registerTransaction.SendFinalResponse(noDomainResponse); return RegisterResultEnum.DomainNotServiced; } SIPAccount sipAccount = GetSIPAccount_External(s => s.SIPUsername == toUser && s.SIPDomain == canonicalDomain); SIPRequestAuthenticationResult authenticationResult = SIPRequestAuthenticator_External(registerTransaction.LocalSIPEndPoint, registerTransaction.RemoteEndPoint, sipRequest, sipAccount, FireProxyLogEvent); if (!authenticationResult.Authenticated) { // 401 Response with a fresh nonce needs to be sent. SIPResponse authReqdResponse = SIPTransport.GetResponse(sipRequest, authenticationResult.ErrorResponse, null); authReqdResponse.Header.AuthenticationHeader = authenticationResult.AuthenticationRequiredHeader; registerTransaction.SendFinalResponse(authReqdResponse); if (authenticationResult.ErrorResponse == SIPResponseStatusCodesEnum.Forbidden) { FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Registrar, SIPMonitorEventTypesEnum.Warn, "Forbidden " + toUser + "@" + canonicalDomain + " does not exist, " + sipRequest.Header.ProxyReceivedFrom.ToString() + ", " + sipRequest.Header.UserAgent + ".", null)); return RegisterResultEnum.Forbidden; } else { FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Registrar, SIPMonitorEventTypesEnum.Registrar, "Authentication required for " + toUser + "@" + canonicalDomain + " from " + sipRequest.Header.ProxyReceivedFrom.ToString() + ".", toUser)); return RegisterResultEnum.AuthenticationRequired; } } else { // Authenticated. if (sipRequest.Header.Contact == null || sipRequest.Header.Contact.Count == 0) { // No contacts header to update bindings with, return a list of the current bindings. List<SIPRegistrarBinding> bindings = m_registrarBindingsManager.GetBindings(sipAccount.Id); //List<SIPContactHeader> contactsList = m_registrarBindingsManager.GetContactHeader(); // registration.GetContactHeader(true, null); if (bindings != null) { sipRequest.Header.Contact = GetContactHeader(bindings); } SIPResponse okResponse = GetOkResponse(sipRequest); registerTransaction.SendFinalResponse(okResponse); FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Registrar, SIPMonitorEventTypesEnum.RegisterSuccess, "Empty registration request successful for " + toUser + "@" + canonicalDomain + " from " + sipRequest.Header.ProxyReceivedFrom.ToString() + ".", toUser)); } else { SIPEndPoint uacRemoteEndPoint = (!sipRequest.Header.ProxyReceivedFrom.IsNullOrBlank()) ? SIPEndPoint.ParseSIPEndPoint(sipRequest.Header.ProxyReceivedFrom) : registerTransaction.RemoteEndPoint; SIPEndPoint proxySIPEndPoint = (!sipRequest.Header.ProxyReceivedOn.IsNullOrBlank()) ? SIPEndPoint.ParseSIPEndPoint(sipRequest.Header.ProxyReceivedOn) : null; SIPEndPoint registrarEndPoint = registerTransaction.LocalSIPEndPoint; SIPResponseStatusCodesEnum updateResult = SIPResponseStatusCodesEnum.Ok; string updateMessage = null; DateTime startTime = DateTime.Now; List<SIPRegistrarBinding> bindingsList = m_registrarBindingsManager.UpdateBindings( sipAccount, proxySIPEndPoint, uacRemoteEndPoint, registrarEndPoint, //sipRequest.Header.Contact[0].ContactURI.CopyOf(), sipRequest.Header.Contact, sipRequest.Header.CallId, sipRequest.Header.CSeq, //sipRequest.Header.Contact[0].Expires, sipRequest.Header.Expires, sipRequest.Header.UserAgent, out updateResult, out updateMessage); //int bindingExpiry = GetBindingExpiry(bindingsList, sipRequest.Header.Contact[0].ContactURI.ToString()); TimeSpan duration = DateTime.Now.Subtract(startTime); FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Registrar, SIPMonitorEventTypesEnum.RegistrarTiming, "Binding update time for " + toUser + "@" + canonicalDomain + " took " + duration.TotalMilliseconds + "ms.", null)); if (updateResult == SIPResponseStatusCodesEnum.Ok) { string proxySocketStr = (proxySIPEndPoint != null) ? " (proxy=" + proxySIPEndPoint.ToString() + ")" : null; int bindingCount = 1; foreach (SIPRegistrarBinding binding in bindingsList) { string bindingIndex = (bindingsList.Count == 1) ? String.Empty : " (" + bindingCount + ")"; //FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Registrar, SIPMonitorEventTypesEnum.RegisterSuccess, "Registration successful for " + toUser + "@" + canonicalDomain + " from " + uacRemoteEndPoint + proxySocketStr + ", binding " + binding.ContactSIPURI.ToParameterlessString() + ";expiry=" + binding.Expiry + bindingIndex + ".", toUser)); FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Registrar, SIPMonitorEventTypesEnum.RegisterSuccess, "Registration successful for " + toUser + "@" + canonicalDomain + " from " + uacRemoteEndPoint + ", binding " + binding.ContactSIPURI.ToParameterlessString() + ";expiry=" + binding.Expiry + bindingIndex + ".", toUser)); //FireProxyLogEvent(new SIPMonitorMachineEvent(SIPMonitorMachineEventTypesEnum.SIPRegistrarBindingUpdate, toUser, uacRemoteEndPoint, sipAccount.Id.ToString())); bindingCount++; } // The standard states that the Ok response should contain the list of current bindings but that breaks some UAs. As a // compromise the list is returned with the Contact that UAC sent as the first one in the list. bool contactListSupported = m_userAgentConfigs.GetUserAgentContactListSupport(sipRequest.Header.UserAgent); if (contactListSupported) { sipRequest.Header.Contact = GetContactHeader(bindingsList); } else { // Some user agents can't match the contact header if the expiry is added to it. sipRequest.Header.Contact[0].Expires = GetBindingExpiry(bindingsList, sipRequest.Header.Contact[0].ContactURI.ToString()); ; } SIPResponse okResponse = GetOkResponse(sipRequest); // If a request was made for a switchboard token and a certificate is available to sign the tokens then generate it. if (sipRequest.Header.SwitchboardTokenRequest > 0 && m_switchbboardRSAProvider != null) { SwitchboardToken token = new SwitchboardToken(sipRequest.Header.SwitchboardTokenRequest, sipAccount.Owner, uacRemoteEndPoint.Address.ToString()); lock (m_switchbboardRSAProvider) { token.SignedHash = Convert.ToBase64String(m_switchbboardRSAProvider.SignHash(Crypto.GetSHAHash(token.GetHashString()), null)); } string tokenXML = token.ToXML(true); logger.Debug("Switchboard token set for " + sipAccount.Owner + " with expiry of " + token.Expiry + "s."); okResponse.Header.SwitchboardToken = Crypto.SymmetricEncrypt(sipAccount.SIPPassword, sipRequest.Header.AuthenticationHeader.SIPDigest.Nonce, tokenXML); } registerTransaction.SendFinalResponse(okResponse); } else { // The binding update failed even though the REGISTER request was authorised. This is probably due to a // temporary problem connecting to the bindings data store. Send Ok but set the binding expiry to the minimum so // that the UA will try again as soon as possible. FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Registrar, SIPMonitorEventTypesEnum.Error, "Registration request successful but binding update failed for " + toUser + "@" + canonicalDomain + " from " + registerTransaction.RemoteEndPoint + ".", toUser)); sipRequest.Header.Contact[0].Expires = m_minimumBindingExpiry; SIPResponse okResponse = GetOkResponse(sipRequest); registerTransaction.SendFinalResponse(okResponse); } } return RegisterResultEnum.Authenticated; } } catch (Exception excp) { string regErrorMessage = "Exception registrarcore registering. " + excp.Message + "\r\n" + registerTransaction.TransactionRequest.ToString(); logger.Error(regErrorMessage); FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Registrar, SIPMonitorEventTypesEnum.Error, regErrorMessage, null)); try { SIPResponse errorResponse = GetErrorResponse(registerTransaction.TransactionRequest, SIPResponseStatusCodesEnum.InternalServerError, null); registerTransaction.SendFinalResponse(errorResponse); } catch { } return RegisterResultEnum.Error; } }
private Task <SocketError> SIPNonInviteTransaction_TransactionFinalResponseReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPResponse sipResponse) { return(NonInviteTransactionFinalResponseReceived?.Invoke(localSIPEndPoint, remoteEndPoint, this, 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); } }
private void SIPNonInviteTransaction_TransactionRequestRetransmit(SIPTransaction sipTransaction, SIPRequest sipRequest, int retransmitNumber) { NonInviteTransactionRequestRetransmit?.Invoke(sipTransaction, sipRequest, retransmitNumber); }
private void UACInviteTransaction_TransactionTimedOut(SIPTransaction sipTransaction) { try { if (UACInviteTransactionTimedOut != null) { UACInviteTransactionTimedOut(sipTransaction); } if (CDR != null) { CDR.TimedOut(); } } catch (Exception excp) { logger.Error("Exception UACInviteTransaction_TransactionTimedOut. " + excp.Message); throw; } }
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.LogError("Exception UACInviteTransaction_TransactionFinalResponseReceived. " + excp.Message); } }
private void SIPNonInviteTransaction_TransactionRequestRetransmit(SIPTransaction sipTransaction, SIPRequest sipRequest, int retransmitNumber) { if (NonInviteTransactionRequestRetransmit != null) { NonInviteTransactionRequestRetransmit(sipTransaction, sipRequest, retransmitNumber); } }
private void ClientTimedOut(SIPTransaction sipTransaction) { try { Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentServer, SIPMonitorEventTypesEnum.DialPlan, "UAS for " + m_uasTransaction.TransactionRequest.URI.ToString() + " timed out in transaction state " + m_uasTransaction.TransactionState + ".", null)); //SIPResponse rejectResponse = SIPTransport.GetResponse(m_uasTransaction.TransactionRequest, SIPResponseStatusCodesEnum.ServerTimeout, "No info or final response received within timeout"); //m_uasTransaction.SendFinalResponse(rejectResponse); if (m_uasTransaction.TransactionState == SIPTransactionStatesEnum.Calling && NoRingTimeout != null) { NoRingTimeout(this); } } catch (Exception excp) { logger.Error("Exception ClientTimedOut. " + excp.Message); } }
private void UACInviteTransaction_TransactionRequestReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPRequest sipRequest) { logger.LogWarning("UACInviteTransaction received unexpected request, " + sipRequest.Method + " from " + remoteEndPoint.ToString() + ", ignoring."); }
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.LogError("Exception UACInviteTransaction_TransactionInformationResponseReceived. " + excp.Message); } }
private void TransactionTraceMessage(SIPTransaction sipTransaction, string message) { Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentServer, SIPMonitorEventTypesEnum.SIPTransaction, message, null)); }
/// <summary> /// Transaction matching see RFC3261 17.1.3 & 17.2.3 for matching client and server transactions respectively. /// IMPORTANT NOTE this transaction matching applies to all requests and responses EXCEPT ACK requests to 2xx responses see 13.2.2.4. /// For ACK's to 2xx responses the ACK represents a separate transaction. However for a UAS sending an INVITE response the ACK still /// has to be matched to an existing server transaction in order to transition it to a Confirmed state. /// /// ACK's: /// - The ACK for a 2xx response will have the same CallId, From Tag and To Tag. /// - An ACK for a non-2xx response will have the same branch ID as the INVITE whose response it acknowledges. /// /// PRACK Requests: /// (From RFC3262) /// A matching PRACK is defined as one within the same dialog as the response, and /// whose method, CSeq-num, and response-num in the RAck header field /// match, respectively, the method from the CSeq, the sequence number /// from the CSeq, and the sequence number from the RSeq of the reliable /// provisional response. /// </summary> /// <param name="sipRequest">The request to attempt to locate a matching transaction for.</param> /// <returns>A matching transaction or null if no match found.</returns> public SIPTransaction GetTransaction(SIPRequest sipRequest) { // The branch is mandatory but it doesn't stop some UA's not setting it. if (sipRequest.Header.Vias.TopViaHeader.Branch == null || sipRequest.Header.Vias.TopViaHeader.Branch.Trim().Length == 0) { return(null); } SIPMethodsEnum transactionMethod = (sipRequest.Method != SIPMethodsEnum.ACK) ? sipRequest.Method : SIPMethodsEnum.INVITE; string transactionId = SIPTransaction.GetRequestTransactionId(sipRequest.Header.Vias.TopViaHeader.Branch, transactionMethod); lock (m_pendingTransactions) { if (transactionId != null && m_pendingTransactions.ContainsKey(transactionId)) { return(m_pendingTransactions[transactionId]); } else { // No normal match found so look of a 2xx INVITE response waiting for an ACK. if (sipRequest.Method == SIPMethodsEnum.ACK) { //logger.LogDebug("Looking for ACK transaction, branchid=" + sipRequest.Header.Via.TopViaHeader.Branch + "."); foreach (var(_, transaction) in m_pendingTransactions) { // According to the standard an ACK should only not get matched by the branchid on the original INVITE for a non-2xx response. However // my Cisco phone created a new branchid on ACKs to 487 responses and since the Cisco also used the same Call-ID and From tag on the initial // unauthenticated request and the subsequent authenticated request the condition below was found to be the best way to match the ACK. /*if (transaction.TransactionType == SIPTransactionTypesEnum.Invite && transaction.TransactionFinalResponse != null && transaction.TransactionState == SIPTransactionStatesEnum.Completed) * { * if (transaction.TransactionFinalResponse.Header.CallId == sipRequest.Header.CallId && * transaction.TransactionFinalResponse.Header.To.ToTag == sipRequest.Header.To.ToTag && * transaction.TransactionFinalResponse.Header.From.FromTag == sipRequest.Header.From.FromTag) * { * return transaction; * } * }*/ // As an experiment going to try matching on the Call-ID. This field seems to be unique and therefore the chance // of collisions seemingly very slim. As a safeguard if there happen to be two transactions with the same Call-ID in the list the match will not be made. // One case where the Call-Id match breaks down is for in-Dialogue requests in that case there will be multiple transactions with the same Call-ID and tags. //if (transaction.TransactionType == SIPTransactionTypesEnum.Invite && transaction.TransactionFinalResponse != null && transaction.TransactionState == SIPTransactionStatesEnum.Completed) if ((transaction.TransactionType == SIPTransactionTypesEnum.InviteClient || transaction.TransactionType == SIPTransactionTypesEnum.InviteServer) && transaction.TransactionFinalResponse != null) { if (transaction.TransactionRequest.Header.CallId == sipRequest.Header.CallId && transaction.TransactionFinalResponse.Header.To.ToTag == sipRequest.Header.To.ToTag && transaction.TransactionFinalResponse.Header.From.FromTag == sipRequest.Header.From.FromTag && transaction.TransactionFinalResponse.Header.CSeq == sipRequest.Header.CSeq) { //logger.LogInformation("ACK for contact=" + contactAddress + ", cseq=" + sipRequest.Header.CSeq + " was matched by callid, tags and cseq."); return(transaction); } else if (transaction.TransactionRequest.Header.CallId == sipRequest.Header.CallId && transaction.TransactionFinalResponse.Header.CSeq == sipRequest.Header.CSeq && IsCallIdUniqueForPending(sipRequest.Header.CallId)) { //string requestEndPoint = (sipRequest.RemoteSIPEndPoint != null) ? sipRequest.RemoteSIPEndPoint.ToString() : " ? "; //logger.LogInformation("ACK for contact=" + contactAddress + ", cseq=" + sipRequest.Header.CSeq + " was matched using Call-ID mechanism (to tags: " + transaction.TransactionFinalResponse.Header.To.ToTag + "=" + sipRequest.Header.To.ToTag + ", from tags:" + transaction.TransactionFinalResponse.Header.From.FromTag + "=" + sipRequest.Header.From.FromTag + ")."); return(transaction); } } } } else if (sipRequest.Method == SIPMethodsEnum.PRACK) { foreach (var(_, transaction) in m_pendingTransactions) { if (transaction.TransactionType == SIPTransactionTypesEnum.InviteServer && transaction.ReliableProvisionalResponse != null) { if (transaction.TransactionRequest.Header.CallId == sipRequest.Header.CallId && transaction.ReliableProvisionalResponse.Header.From.FromTag == sipRequest.Header.From.FromTag && transaction.ReliableProvisionalResponse.Header.CSeq == sipRequest.Header.RAckCSeq && transaction.ReliableProvisionalResponse.Header.RSeq == sipRequest.Header.RAckRSeq && transaction.ReliableProvisionalResponse.Header.CSeqMethod == sipRequest.Header.RAckCSeqMethod) { //logger.LogDebug("PRACK for contact=" + contactAddress + ", cseq=" + sipRequest.Header.CSeq + " was matched by callid, tags and cseq."); return(transaction); } } } } return(null); } } }
private void UASTransaction_TransactionRemoved(SIPTransaction sipTransaction) { if (TransactionComplete != null) { TransactionComplete(this); } }
private void RemoveExpiredTransactions() { try { List <string> expiredTransactionIds = new List <string>(); var now = DateTime.Now; foreach (var(_, transaction) in m_pendingTransactions) { if (transaction.TransactionType == SIPTransactionTypesEnum.InviteClient || transaction.TransactionType == SIPTransactionTypesEnum.InviteServer) { if (transaction.TransactionState == SIPTransactionStatesEnum.Confirmed) { // Need to wait until the transaction timeout period is reached in case any ACK re-transmits are received. // No proactive actions need to be undertaken in the Confirmed state. If any ACK requests are received // we use this tx to ensure they get matched and not detected as orphans. if (now.Subtract(transaction.CompletedAt).TotalMilliseconds >= m_t6) { expiredTransactionIds.Add(transaction.TransactionId); } } else if (transaction.TransactionState == SIPTransactionStatesEnum.Completed) { // If a server INVITE transaction is in the following state: // - Completed it means we sent a final response but did not receive an ACK // (which is what transitions the tx to the Confirmed state). if (now.Subtract(transaction.CompletedAt).TotalMilliseconds >= m_t6) { // It's important that an un-Confirmed server INVITE tx fires the event to // inform the application that the tx timed out. This allows it to make a decision // on whether to clean up resources such as RTP and media or whether to give the // caller the benefit of the doubt and see if it was an ACK only problem and // give them a chance to send RTP. transaction.Expire(now); expiredTransactionIds.Add(transaction.TransactionId); } } else if (transaction.DeliveryFailed && transaction.TransactionFinalResponse == null) { // This transaction timed out attempting to send the initial request. No // final response was received so it does not need to be kept alive for ACK // re-transmits. expiredTransactionIds.Add(transaction.TransactionId); } else if (transaction.TransactionState == SIPTransactionStatesEnum.Proceeding) { if (now.Subtract(transaction.Created).TotalMilliseconds >= m_maxRingTime) { // INVITE requests that have been ringing too long. This can apply to both // client and server INVITE transactions. transaction.Expire(now); expiredTransactionIds.Add(transaction.TransactionId); } } else if (now.Subtract(transaction.Created).TotalMilliseconds >= m_t6) { //logger.LogDebug("INVITE transaction (" + transaction.TransactionId + ") " + transaction.TransactionRequestURI.ToString() + " in " + transaction.TransactionState + " has been alive for " + DateTime.Now.Subtract(transaction.Created).TotalSeconds.ToString("0") + "."); // If a client INVITE transaction is in the following states: // - Calling: it means no response of any kind (provisional or final) was received from the server in time. // - Trying: it means all we got was a "100 Trying" response without any follow up progress indications or final response. if (transaction.TransactionState == SIPTransactionStatesEnum.Calling || transaction.TransactionState == SIPTransactionStatesEnum.Trying) { transaction.Expire(now); expiredTransactionIds.Add(transaction.TransactionId); } else { // The INVITE transaction has ended up in some other state and should be removed. expiredTransactionIds.Add(transaction.TransactionId); } } } else if (transaction.HasTimedOut) { expiredTransactionIds.Add(transaction.TransactionId); } else if (now.Subtract(transaction.Created).TotalMilliseconds >= m_t6) { if (transaction.TransactionState == SIPTransactionStatesEnum.Calling || transaction.TransactionState == SIPTransactionStatesEnum.Trying || transaction.TransactionState == SIPTransactionStatesEnum.Proceeding) { //logger.LogWarning("Timed out transaction in SIPTransactionEngine, should have been timed out in the SIP Transport layer. " + transaction.TransactionRequest.Method + "."); transaction.Expire(now); } expiredTransactionIds.Add(transaction.TransactionId); } } foreach (string transactionId in expiredTransactionIds) { if (m_pendingTransactions.ContainsKey(transactionId)) { SIPTransaction expiredTransaction = m_pendingTransactions[transactionId]; RemoveTransaction(expiredTransaction.TransactionId); } } } catch (Exception excp) { logger.LogError("Exception RemoveExpiredTransaction. " + excp.Message); } }