private void Answered(SDP sdp) { Console.WriteLine("XMPP client call answered."); IsUACAnswered = true; SIPResponse okResponse = new SIPResponse(SIPResponseStatusCodesEnum.Ok, "Ok", new SIPEndPoint(new IPEndPoint(IPAddress.Loopback, 0))); okResponse.Header.ContentType = SDP.SDP_MIME_CONTENTTYPE; okResponse.Body = sdp.ToString(); SIPDialogue = new SIPDialogue(null, null, null, null, -1, null, null, null, Guid.NewGuid(), Owner, AdminMemberId, null, sdp.ToString()); SIPDialogue.CallDurationLimit = CallDescriptor.CallDurationLimit; CallAnswered(this, okResponse); }
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 = toHeader.ToURI.Host; int requestedExpiry = GetRequestedExpiry(sipRequest); if (canonicalDomain == null) { SIPResponse noDomainResponse = GetErrorResponse(sipRequest, SIPResponseStatusCodesEnum.Forbidden, "Domain not serviced"); registerTransaction.SendFinalResponse(noDomainResponse); return(RegisterResultEnum.DomainNotServiced); } SIPAccount sipAccount = new SIPAccount { Id = Guid.NewGuid(), Owner = "admin", SIPUsername = toUser, SIPDomain = canonicalDomain }; SIPRequestAuthenticationResult authenticationResult = _sipRequestAuthenticator_External?.Invoke(registerTransaction.LocalSIPEndPoint, registerTransaction.RemoteEndPoint, sipRequest, sipAccount); if (!_needAuthentication) { SIPResponse okRes = GetOkResponse(sipRequest); registerTransaction.SendFinalResponse(okRes); if (requestedExpiry > 0) { CacheDeviceItem(sipRequest); RegisterReceived?.Invoke(sipRequest, _localSipAccount); } if (requestedExpiry == 0) { RemoveDeviceItem(sipRequest); UnRegisterReceived?.Invoke(sipRequest, _localSipAccount); } return(RegisterResultEnum.AuthenticationRequired); } 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) { return(RegisterResultEnum.Forbidden); } else { return(RegisterResultEnum.AuthenticationRequired); } } else { if (sipRequest.Header.Contact == null || sipRequest.Header.Contact.Count == 0) { SIPResponse okResponse = GetOkResponse(sipRequest); registerTransaction.SendFinalResponse(okResponse); if (requestedExpiry > 0) { CacheDeviceItem(sipRequest); RegisterReceived?.Invoke(sipRequest, _localSipAccount); } if (requestedExpiry == 0) { RemoveDeviceItem(sipRequest); UnRegisterReceived?.Invoke(sipRequest, _localSipAccount); } } else { SIPEndPoint uacRemoteEndPoint = SIPEndPoint.TryParse(sipRequest.Header.ProxyReceivedFrom) ?? registerTransaction.RemoteEndPoint; SIPEndPoint proxySIPEndPoint = SIPEndPoint.TryParse(sipRequest.Header.ProxyReceivedOn); SIPEndPoint registrarEndPoint = registerTransaction.LocalSIPEndPoint; SIPResponseStatusCodesEnum updateResult = SIPResponseStatusCodesEnum.Ok; DateTime startTime = DateTime.Now; TimeSpan duration = DateTime.Now.Subtract(startTime); if (updateResult == SIPResponseStatusCodesEnum.Ok) { string proxySocketStr = (proxySIPEndPoint != null) ? " (proxy=" + proxySIPEndPoint.ToString() + ")" : null; SIPResponse okResponse = GetOkResponse(sipRequest); registerTransaction.SendFinalResponse(okResponse); if (requestedExpiry > 0) { CacheDeviceItem(sipRequest); RegisterReceived?.Invoke(sipRequest, _localSipAccount); } if (requestedExpiry == 0) { RemoveDeviceItem(sipRequest); UnRegisterReceived?.Invoke(sipRequest, _localSipAccount); } } else { 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 + "->" + registerTransaction.TransactionRequest.ToString(); Logger.Logger.Error(regErrorMessage); try { SIPResponse errorResponse = GetErrorResponse(registerTransaction.TransactionRequest, SIPResponseStatusCodesEnum.InternalServerError, null); registerTransaction.SendFinalResponse(errorResponse); } catch { } return(RegisterResultEnum.Error); } }
/// <summary> /// A ringing response has been received from the remote SIP UAS on an outgoing call. /// </summary> private void CallRinging(ISIPClientUserAgent uac, SIPResponse sipResponse) { StatusMessage(this, "Call ringing: " + sipResponse.StatusCode + " " + sipResponse.ReasonPhrase + "."); }
/// <summary> /// Handles responses to our re-INVITE requests. /// </summary> /// <param name="localSIPEndPoint">The local end point the response was received on.</param> /// <param name="remoteEndPoint">The remote end point the response came from.</param> /// <param name="sipTransaction">The UAS transaction the response is part of.</param> /// <param name="sipResponse">The SIP response.</param> private Task <SocketError> ReinviteRequestFinalResponseReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPResponse sipResponse) { if (sipResponse.Status == SIPResponseStatusCodesEnum.Ok) { // Update the remote party's SDP. Dialogue.RemoteSDP = sipResponse.Body; MediaSession.setRemoteDescription(new RTCSessionDescription { sdp = SDP.ParseSDPDescription(sipResponse.Body), type = RTCSdpType.answer }); } else { logger.LogWarning($"Re-INVITE request failed with response {sipResponse.ShortDescription}."); } return(Task.FromResult(SocketError.Success)); }
private void FireCallAnswered(SIPClientUserAgent uac, SIPResponse answeredResponse) { if (CallAnswered != null) { CallAnswered(uac, answeredResponse); } }
/// <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> /// 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); } }
static void Main(string[] args) { Console.WriteLine("SIPSorcery user agent server example."); Console.WriteLine("Press h to hangup a call or ctrl-c to exit."); EnableConsoleLogger(); IPAddress listenAddress = IPAddress.Any; IPAddress listenIPv6Address = IPAddress.IPv6Any; if (args != null && args.Length > 0) { if (!IPAddress.TryParse(args[0], out var customListenAddress)) { Log.LogWarning($"Command line argument could not be parsed as an IP address \"{args[0]}\""); listenAddress = IPAddress.Any; } else { if (customListenAddress.AddressFamily == AddressFamily.InterNetwork) { listenAddress = customListenAddress; } if (customListenAddress.AddressFamily == AddressFamily.InterNetworkV6) { listenIPv6Address = customListenAddress; } } } // Set up a default SIP transport. var sipTransport = new SIPTransport(); var localhostCertificate = new X509Certificate2("localhost.pfx"); // IPv4 channels. sipTransport.AddSIPChannel(new SIPUDPChannel(new IPEndPoint(listenAddress, SIP_LISTEN_PORT))); sipTransport.AddSIPChannel(new SIPTCPChannel(new IPEndPoint(listenAddress, SIP_LISTEN_PORT))); sipTransport.AddSIPChannel(new SIPTLSChannel(localhostCertificate, new IPEndPoint(listenAddress, SIPS_LISTEN_PORT))); sipTransport.AddSIPChannel(new SIPWebSocketChannel(IPAddress.Any, SIP_WEBSOCKET_LISTEN_PORT)); sipTransport.AddSIPChannel(new SIPWebSocketChannel(IPAddress.Any, SIP_SECURE_WEBSOCKET_LISTEN_PORT, localhostCertificate)); // IPv6 channels. sipTransport.AddSIPChannel(new SIPUDPChannel(new IPEndPoint(listenIPv6Address, SIP_LISTEN_PORT))); sipTransport.AddSIPChannel(new SIPTCPChannel(new IPEndPoint(listenIPv6Address, SIP_LISTEN_PORT))); sipTransport.AddSIPChannel(new SIPTLSChannel(localhostCertificate, new IPEndPoint(listenIPv6Address, SIPS_LISTEN_PORT))); sipTransport.AddSIPChannel(new SIPWebSocketChannel(IPAddress.IPv6Any, SIP_WEBSOCKET_LISTEN_PORT)); sipTransport.AddSIPChannel(new SIPWebSocketChannel(IPAddress.IPv6Any, SIP_SECURE_WEBSOCKET_LISTEN_PORT, localhostCertificate)); EnableTraceLogs(sipTransport); // To keep things a bit simpler this example only supports a single call at a time and the SIP server user agent // acts as a singleton SIPServerUserAgent uas = null; CancellationTokenSource rtpCts = null; // Cancellation token to stop the RTP stream. RTPMediaSession rtpSession = null; // Because this is a server user agent the SIP transport must start listening for client user agents. sipTransport.SIPTransportRequestReceived += async(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPRequest sipRequest) => { try { if (sipRequest.Method == SIPMethodsEnum.INVITE) { SIPSorcery.Sys.Log.Logger.LogInformation($"Incoming call request: {localSIPEndPoint}<-{remoteEndPoint} {sipRequest.URI}."); // Check there's a codec we support in the INVITE offer. var offerSdp = SDP.ParseSDPDescription(sipRequest.Body); IPEndPoint dstRtpEndPoint = SDP.GetSDPRTPEndPoint(sipRequest.Body); string audioFile = null; if (offerSdp.Media.Any(x => x.Media == SDPMediaTypesEnum.audio && x.HasMediaFormat((int)SDPMediaFormatsEnum.G722))) { Log.LogDebug($"Using G722 RTP media type and audio file {AUDIO_FILE_G722}."); rtpSession = new RTPMediaSession(SDPMediaTypesEnum.audio, (int)SDPMediaFormatsEnum.G722, dstRtpEndPoint.AddressFamily); audioFile = AUDIO_FILE_G722; } else if (offerSdp.Media.Any(x => x.Media == SDPMediaTypesEnum.audio && x.HasMediaFormat((int)SDPMediaFormatsEnum.PCMU))) { Log.LogDebug($"Using PCMU RTP media type and audio file {AUDIO_FILE_PCMU}."); rtpSession = new RTPMediaSession(SDPMediaTypesEnum.audio, (int)SDPMediaFormatsEnum.PCMU, dstRtpEndPoint.AddressFamily); audioFile = AUDIO_FILE_PCMU; } if (rtpSession == null) { // Didn't get a match on the codecs we support. SIPResponse noMatchingCodecResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.NotAcceptableHere, null); await sipTransport.SendResponseAsync(noMatchingCodecResponse); } else { // If there's already a call in progress hang it up. Of course this is not ideal for a real softphone or server but it // means this example can be kept simpler. if (uas?.IsHungup == false) { uas?.Hangup(false); } rtpCts?.Cancel(); rtpCts = new CancellationTokenSource(); UASInviteTransaction uasTransaction = new UASInviteTransaction(sipTransport, sipRequest, null); uas = new SIPServerUserAgent(sipTransport, null, null, null, SIPCallDirection.In, null, null, null, uasTransaction); uas.CallCancelled += (uasAgent) => { rtpCts?.Cancel(); rtpSession.CloseSession(null); }; rtpSession.OnRtpClosed += (reason) => uas?.Hangup(false); uas.Progress(SIPResponseStatusCodesEnum.Trying, null, null, null, null); uas.Progress(SIPResponseStatusCodesEnum.Ringing, null, null, null, null); // The RTP socket is listening on IPAddress.Any but the IP address placed into the SDP needs to be one the caller can reach. IPAddress rtpAddress = NetServices.GetLocalAddressForRemote(dstRtpEndPoint.Address); // Only set the remote RTP end point if there hasn't already been a packet received on it. if (rtpSession.DestinationEndPoint == null) { rtpSession.SetRemoteSDP(SDP.ParseSDPDescription(sipRequest.Body)); Log.LogDebug($"Remote RTP socket {rtpSession.DestinationEndPoint}."); } rtpSession.SetRemoteSDP(SDP.ParseSDPDescription(sipRequest.Body)); _ = Task.Run(() => SendRtp(rtpSession, dstRtpEndPoint, audioFile, rtpCts)) .ContinueWith(_ => { if (uas?.IsHungup == false) { uas?.Hangup(false); rtpSession?.CloseSession(null); } }); uas.Answer(SDP.SDP_MIME_CONTENTTYPE, rtpSession.GetSDP(rtpAddress).ToString(), null, SIPDialogueTransferModesEnum.NotAllowed); } } else if (sipRequest.Method == SIPMethodsEnum.BYE) { SIPSorcery.Sys.Log.Logger.LogInformation("Call hungup."); SIPResponse byeResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null); await sipTransport.SendResponseAsync(byeResponse); uas?.Hangup(true); rtpSession?.CloseSession(null); rtpCts?.Cancel(); } else if (sipRequest.Method == SIPMethodsEnum.SUBSCRIBE) { SIPResponse notAllowededResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.MethodNotAllowed, null); await sipTransport.SendResponseAsync(notAllowededResponse); } else if (sipRequest.Method == SIPMethodsEnum.OPTIONS || sipRequest.Method == SIPMethodsEnum.REGISTER) { SIPResponse optionsResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null); await sipTransport.SendResponseAsync(optionsResponse); } } catch (Exception reqExcp) { SIPSorcery.Sys.Log.Logger.LogWarning($"Exception handling {sipRequest.Method}. {reqExcp.Message}"); } }; ManualResetEvent exitMre = new ManualResetEvent(false); Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e) { e.Cancel = true; SIPSorcery.Sys.Log.Logger.LogInformation("Exiting..."); Hangup(uas).Wait(); rtpSession?.CloseSession(null); rtpCts?.Cancel(); if (sipTransport != null) { SIPSorcery.Sys.Log.Logger.LogInformation("Shutting down SIP transport..."); sipTransport.Shutdown(); } exitMre.Set(); }; // Task to handle user key presses. Task.Run(() => { try { while (!exitMre.WaitOne(0)) { var keyProps = Console.ReadKey(); if (keyProps.KeyChar == 'h' || keyProps.KeyChar == 'q') { Console.WriteLine(); Console.WriteLine("Hangup requested by user..."); Hangup(uas).Wait(); rtpSession?.CloseSession(null); rtpCts?.Cancel(); } if (keyProps.KeyChar == 'q') { SIPSorcery.Sys.Log.Logger.LogInformation("Quitting..."); if (sipTransport != null) { SIPSorcery.Sys.Log.Logger.LogInformation("Shutting down SIP transport..."); sipTransport.Shutdown(); } exitMre.Set(); } } } catch (Exception excp) { SIPSorcery.Sys.Log.Logger.LogError($"Exception Key Press listener. {excp.Message}."); } }); exitMre.WaitOne(); }
/*[OperationContract] public List<SIPRegistrationAgentRecord> GetRegistrationAgentRegistrations(string owner) { try { return m_regAgent.GetOwnerRegistrations(owner); } catch (Exception excp) { logger.Error("Exception GetRegistrationAgentRegistrations. " + excp.Message); throw excp; } } [OperationContract] public void RemoveRegistrationAgentContact(Guid registrationId, string contactToRemove) { try { logger.Debug("RemoveRegistrarContact webservice called for " + registrationId + " and " + contactToRemove + "."); SIPRegistrationAgentRecord registration = m_regAgent.Get(registrationId); if (registration != null) { // Look through the current contacts to try and find one to match this contact. foreach (SIPContactHeader contact in registration.ContactsList) { logger.Debug("Comparing: " + contact.ContactURI.ToString() + " to " + contactToRemove); if (contactToRemove == null || contact.ContactURI.ToString() == contactToRemove) { logger.Debug("Attempting removal of registrar contact " + contact.ContactURI.ToString() + "."); m_regAgent.SendContactRemovalRequest(registrationId, contact.ContactURI); } } } else { logger.Warn("Could not find the registration record for " + registrationId + " in RemoveSIPContact."); } } catch (Exception excp) { logger.Error("Exception RemoveRegistrarContact. " + excp.Message); throw excp; } } [OperationContract] public void RefreshRegistrationAgentContact(Guid registrationId) { try { logger.Debug("RefreshRegistrationView webservice called for " + registrationId + "."); UserRegistration registration = m_regAgent.Get(registrationId); if (registration != null) { m_regAgent.SendEmptyRegistrationRequest(registrationId); } else { logger.Warn("Could not find the registration record for " + registrationId + " in RefreshRegistrationView."); } } catch (Exception excp) { logger.Error("Exception RefreshRegistrationView. " + excp.Message); throw excp; } }*/ /// <summary> /// Send a Message Waiting Indicator request to the specified user agent URI. If setMWI is true the number of messages indicated will /// be one otherwise 0. /// </summary> /*[OperationContract] public void SendMWIRequest(string userAgentURI, bool setMWI, string username) { try { logger.Debug("Attempting SendMWIRequest for " + userAgentURI + " as " + setMWI + "."); SIPURI clientURI = SIPURI.ParseSIPURI(userAgentURI); SIPRequest mwiRequest = SIPNotificationAgent.GetNotifyRequest(m_sipTransport.GetTransportContact(null), null, clientURI, username, setMWI); SIPNonInviteTransaction mwiTransaction = m_sipTransport.CreateNonInviteTransaction(mwiRequest, clientURI.GetURIEndPoint(), m_sipTransport.GetTransportContact(null), SIPProtocolsEnum.UDP); mwiTransaction.NonInviteTransactionFinalResponseReceived += new SIPTransactionResponseReceivedDelegate(MWIFinalResponseReceived); FireProxyLogEvent(new ProxyMonitorEvent(ProxyServerTypesEnum.StatefulProxy, ProxyEventTypesEnum.MWI, "Sending " + setMWI + " mwi to " + SIPURI.ParseSIPURI(userAgentURI).CanonicalAddress, username)); m_sipTransport.SendRequest(mwiRequest, SIPProtocolsEnum.UDP); } catch (Exception excp) { logger.Error("Exception SendMWIRequest. " + excp.Message + "."); } }*/ /*private void MWIFinalResponseReceived(IPEndPoint localEndPoint, IPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPResponse sipResponse) { try { string username = sipResponse.Header.From.FromURI.User; logger.Debug("MWI response received from " + IPSocket.GetSocketString(remoteEndPoint) + " " + sipResponse.StatusCode + " " + sipResponse.ReasonPhrase + " for " + username + "."); FireProxyLogEvent(new ProxyMonitorEvent(ProxyServerTypesEnum.StatefulProxy, ProxyEventTypesEnum.MWI, "MWI response received from " + IPSocket.GetSocketString(remoteEndPoint) + " " + sipResponse.StatusCode + " " + sipResponse.ReasonPhrase, username)); } catch (Exception excp) { logger.Error("Exception MWIFinalResponseReceived. " + excp.Message); } }*/ /// <summary> /// Send a Message Waiting Indicator request to the specified user agent URI. If setMWI is true the number of messages indicated will /// be one otherwise 0. /// </summary> /*[OperationContract] public void SendInviteRequest(string userAgentURI, string callerIdName, string callerIdUser, string username) { try { logger.Debug("Attempting SendInviteRequest for " + userAgentURI + " as " + callerIdName + " and " + callerIdUser + "."); SIPURI clientURI = SIPURI.ParseSIPURI(userAgentURI); SIPRequest inviteRequest = GetInviteRequest(clientURI, callerIdName, callerIdUser, SERVER_STRING); UACInviteTransaction inviteTransaction = m_sipTransport.CreateUACTransaction(inviteRequest, clientURI.GetURIEndPoint(), m_sipTransport.GetTransportContact(null), SIPProtocolsEnum.UDP); inviteTransaction.UACInviteTransactionFinalResponseReceived += new SIPTransactionResponseReceivedDelegate(InviteFinalResponseReceived); FireProxyLogEvent(new ProxyMonitorEvent(ProxyServerTypesEnum.StatefulProxy, ProxyEventTypesEnum.NewCall, "Sending INVITE to " + SIPURI.ParseSIPURI(userAgentURI).ToString(), username)); inviteTransaction.SendInviteRequest(inviteRequest.GetRequestEndPoint(), inviteRequest); } catch (Exception excp) { logger.Error("Exception SendInviteRequest. " + excp.Message + "."); } }*/ private void InviteFinalResponseReceived(IPEndPoint localEndPoint, IPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPResponse sipResponse) { try { logger.Debug("FinalResponseReceived for INVITE to " + sipTransaction.TransactionRequest.URI.ToString() + " " + sipResponse.Status + " " + sipResponse.ReasonPhrase + "."); } catch (Exception excp) { logger.Error("Exception InviteFinalResponseReceived. " + excp.Message); } }
private void ServerInformationResponseReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPResponse sipResponse) { Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentClient, SIPMonitorEventTypesEnum.DialPlan, "Information response " + sipResponse.StatusCode + " " + sipResponse.ReasonPhrase + " for " + m_serverTransaction.TransactionRequest.URI.ToString() + ".", Owner)); if (m_callCancelled) { // Call was cancelled in the interim. Cancel(); } else { if (sipResponse.Status == SIPResponseStatusCodesEnum.Ringing || sipResponse.Status == SIPResponseStatusCodesEnum.SessionProgress) { FireCallRinging(this, sipResponse); } else { FireCallTrying(this, sipResponse); } } }
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)); } }
private SIPRequest GetByeRequest(SIPResponse inviteResponse, SIPURI byeURI, SIPEndPoint localSIPEndPoint) { SIPRequest byeRequest = new SIPRequest(SIPMethodsEnum.BYE, byeURI); byeRequest.LocalSIPEndPoint = localSIPEndPoint; SIPFromHeader byeFromHeader = inviteResponse.Header.From; SIPToHeader byeToHeader = inviteResponse.Header.To; int cseq = inviteResponse.Header.CSeq + 1; SIPHeader byeHeader = new SIPHeader(byeFromHeader, byeToHeader, cseq, inviteResponse.Header.CallId); byeHeader.CSeqMethod = SIPMethodsEnum.BYE; byeHeader.ProxySendFrom = m_serverTransaction.TransactionRequest.Header.ProxySendFrom; byeRequest.Header = byeHeader; byeRequest.Header.Routes = (inviteResponse.Header.RecordRoutes != null) ? inviteResponse.Header.RecordRoutes.Reversed() : null; SIPViaHeader viaHeader = new SIPViaHeader(localSIPEndPoint, CallProperties.CreateBranchId()); byeRequest.Header.Vias.PushViaHeader(viaHeader); return byeRequest; }
private void FireCallTrying(SIPClientUserAgent uac, SIPResponse tryingResponse) { if (CallTrying != null) { CallTrying(uac, tryingResponse); } }
private void FireCallRinging(SIPClientUserAgent uac, SIPResponse ringingResponse) { if (CallRinging != null) { CallRinging(uac, ringingResponse); } }
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 Task <SocketError> SubscribeTransactionFinalResponseReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPResponse sipResponse) { try { if (sipResponse.Status == SIPResponseStatusCodesEnum.IntervalTooBrief) { // The expiry interval used was too small. Adjust and try again. m_expiry = (sipResponse.Header.MinExpires > 0) ? sipResponse.Header.MinExpires : m_expiry * 2; logger.LogWarning("A subscribe request was rejected with IntervalTooBrief, adjusting expiry to " + m_expiry + " and trying again."); Subscribe(m_resourceURI, m_expiry, m_sipEventPackage, m_subscribeCallID, null); } else if (sipResponse.Status == SIPResponseStatusCodesEnum.Forbidden) { // The subscription is never going to succeed so cancel it. SubscriptionFailed(m_resourceURI, sipResponse.Status, "A Forbidden response was received on a subscribe attempt to " + m_resourceURI.ToString() + " for user " + m_authUsername + "."); m_exit = true; m_waitForSubscribeResponse.Set(); } else if (sipResponse.Status == SIPResponseStatusCodesEnum.BadEvent) { // The subscription is never going to succeed so cancel it. SubscriptionFailed(m_resourceURI, sipResponse.Status, "A BadEvent response was received on a subscribe attempt to " + m_resourceURI.ToString() + " for event package " + m_sipEventPackage.ToString() + "."); m_exit = true; m_waitForSubscribeResponse.Set(); } else if (sipResponse.Status == SIPResponseStatusCodesEnum.CallLegTransactionDoesNotExist) { // The notifier server does not have a record for the existing subscription. SubscriptionFailed(m_resourceURI, sipResponse.Status, "Subscribe failed with response " + sipResponse.StatusCode + " " + sipResponse.ReasonPhrase + "."); m_waitForSubscribeResponse.Set(); } else if (sipResponse.Status == SIPResponseStatusCodesEnum.ProxyAuthenticationRequired || sipResponse.Status == SIPResponseStatusCodesEnum.Unauthorised) { if (m_authUsername.IsNullOrBlank() || m_authPassword.IsNullOrBlank()) { // No point trying to authenticate if there are no credentials to use. SubscriptionFailed(m_resourceURI, sipResponse.Status, "Authentication requested on subscribe request when no credentials available."); m_waitForSubscribeResponse.Set(); } else if (sipResponse.Header.AuthenticationHeader != null) { if (m_attempts >= MAX_SUBSCRIBE_ATTEMPTS) { m_subscribed = false; SubscriptionFailed(m_resourceURI, SIPResponseStatusCodesEnum.InternalServerError, "Subscription reached the maximum number of allowed attempts."); m_waitForSubscribeResponse.Set(); } else { logger.LogDebug("Attempting authentication for subscribe request for event package " + m_sipEventPackage.ToString() + " and " + m_resourceURI.ToString() + "."); m_attempts++; // Resend SUBSCRIBE with credentials. SIPAuthorisationDigest authRequest = sipResponse.Header.AuthenticationHeader.SIPDigest; authRequest.SetCredentials(m_authUsername, m_authPassword, m_resourceURI.ToString(), SIPMethodsEnum.SUBSCRIBE.ToString()); SIPRequest authSubscribeRequest = sipTransaction.TransactionRequest; authSubscribeRequest.Header.AuthenticationHeader = new SIPAuthenticationHeader(authRequest); authSubscribeRequest.Header.AuthenticationHeader.SIPDigest.Response = authRequest.Digest; authSubscribeRequest.Header.Vias.TopViaHeader.Branch = CallProperties.CreateBranchId(); m_localCSeq = sipTransaction.TransactionRequest.Header.CSeq + 1; authSubscribeRequest.Header.CSeq = m_localCSeq; authSubscribeRequest.Header.CallId = m_subscribeCallID; if (!m_filter.IsNullOrBlank()) { authSubscribeRequest.Body = m_filter; authSubscribeRequest.Header.ContentLength = m_filter.Length; authSubscribeRequest.Header.ContentType = m_filterTextType; } // Create a new transaction to establish the authenticated server call. SIPNonInviteTransaction subscribeTransaction = new SIPNonInviteTransaction(m_sipTransport, authSubscribeRequest, m_outboundProxy); subscribeTransaction.NonInviteTransactionFinalResponseReceived += SubscribeTransactionFinalResponseReceived; subscribeTransaction.NonInviteTransactionTimedOut += SubsribeTransactionTimedOut; m_sipTransport.SendTransaction(subscribeTransaction); } } else { SubscriptionFailed(sipTransaction.TransactionRequestURI, sipResponse.Status, "Subscribe requested authentication but did not provide an authentication header."); m_waitForSubscribeResponse.Set(); } } else if (sipResponse.StatusCode >= 200 && sipResponse.StatusCode <= 299) { logger.LogDebug("Authenticating subscribe request for event package " + m_sipEventPackage.ToString() + " and " + m_resourceURI.ToString() + " was successful."); m_subscribed = true; m_subscriptionToTag = sipResponse.Header.To.ToTag; SubscriptionSuccessful(m_resourceURI); m_waitForSubscribeResponse.Set(); } else { SubscriptionFailed(m_resourceURI, sipResponse.Status, "Subscribe failed with response " + sipResponse.StatusCode + " " + sipResponse.ReasonPhrase + "."); m_waitForSubscribeResponse.Set(); } return(Task.FromResult(SocketError.Success)); } catch (Exception excp) { logger.LogError("Exception SubscribeTransactionFinalResponseReceived. " + excp.Message); SubscriptionFailed(m_resourceURI, SIPResponseStatusCodesEnum.InternalServerError, "Exception processing subscribe response. " + excp.Message); m_waitForSubscribeResponse.Set(); return(Task.FromResult(SocketError.Fault)); } }
public SIPRequest GetAuthenticatedRequest(SIPRequest origRequest, SIPResponse authReqdResponse, string username, string password) { SIPRequest authRequest = origRequest; authRequest.Header.Via.TopViaHeader.Branch = CallProperties.CreateBranchId(); authRequest.Header.From.FromTag = CallProperties.CreateNewTag(); authRequest.Header.CSeq = origRequest.Header.CSeq + 1; AuthorizationRequest authorizationRequest = authReqdResponse.Header.AuthenticationHeader.AuthRequest; authorizationRequest.SetCredentials(username, password, origRequest.URI.ToString(), origRequest.Method.ToString()); authRequest.Header.AuthenticationHeader = new SIPAuthenticationHeader(authorizationRequest); authRequest.Header.AuthenticationHeader.AuthRequest.Response = authorizationRequest.Digest; return authRequest; }
public bool AuthenticateCall() { m_isAuthenticated = false; try { if (SIPAuthenticateRequest_External == null) { // No point trying to authenticate if we haven't been given an authentication delegate. Reject(SIPResponseStatusCodesEnum.InternalServerError, null, null); } else if (GetSIPAccount_External == null) { // No point trying to authenticate if we haven't been given a delegate to load the SIP account. Reject(SIPResponseStatusCodesEnum.InternalServerError, null, null); } else { m_sipAccount = GetSIPAccount_External(m_sipUsername, m_sipDomain); if (m_sipAccount == null) { Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Rejecting authentication required call for " + m_sipUsername + "@" + m_sipDomain + ", SIP account not found.", null)); Reject(SIPResponseStatusCodesEnum.Forbidden, null, null); } else { SIPRequest sipRequest = m_uasTransaction.TransactionRequest; SIPEndPoint localSIPEndPoint = (!sipRequest.Header.ProxyReceivedOn.IsNullOrBlank()) ? SIPEndPoint.ParseSIPEndPoint(sipRequest.Header.ProxyReceivedOn) : sipRequest.LocalSIPEndPoint; SIPEndPoint remoteEndPoint = (!sipRequest.Header.ProxyReceivedFrom.IsNullOrBlank()) ? SIPEndPoint.ParseSIPEndPoint(sipRequest.Header.ProxyReceivedFrom) : sipRequest.RemoteSIPEndPoint; SIPRequestAuthenticationResult authenticationResult = SIPAuthenticateRequest_External(localSIPEndPoint, remoteEndPoint, sipRequest, m_sipAccount, Log_External); if (authenticationResult.Authenticated) { if (authenticationResult.WasAuthenticatedByIP) { Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "New call from " + remoteEndPoint.ToString() + " successfully authenticated by IP address.", m_sipAccount.Owner)); } else { Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "New call from " + remoteEndPoint.ToString() + " successfully authenticated by digest.", m_sipAccount.Owner)); } SetOwner(m_sipAccount.Owner, m_sipAccount.AdminMemberId); m_isAuthenticated = true; } else { // Send authorisation failure or required response SIPResponse authReqdResponse = SIPTransport.GetResponse(sipRequest, authenticationResult.ErrorResponse, null); authReqdResponse.Header.AuthenticationHeader = authenticationResult.AuthenticationRequiredHeader; Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Call not authenticated for " + m_sipUsername + "@" + m_sipDomain + ", responding with " + authenticationResult.ErrorResponse + ".", null)); m_uasTransaction.SendFinalResponse(authReqdResponse); } } } } catch (Exception excp) { logger.LogError("Exception SIPServerUserAgent AuthenticateCall. " + excp.Message); Reject(SIPResponseStatusCodesEnum.InternalServerError, null, null); } return(m_isAuthenticated); }
public SIPRequest GetByeRequest(SIPResponse inviteResponse) { SIPRequest byeRequest = new SIPRequest(SIPMethodsEnum.BYE, inviteResponse.Header.Contact[0].ContactURI); SIPHeader byeHeader = new SIPHeader(inviteResponse.Header.From, inviteResponse.Header.To, inviteResponse.Header.CSeq + 1, inviteResponse.Header.CallId); byeHeader.CSeqMethod = SIPMethodsEnum.BYE; IPEndPoint localSIPEndPoint = m_sipTransport.GetIPEndPointsList()[0]; SIPViaHeader viaHeader = new SIPViaHeader(localSIPEndPoint.Address.ToString(), localSIPEndPoint.Port, CallProperties.CreateBranchId()); byeHeader.Via.PushViaHeader(viaHeader); byeRequest.Header = byeHeader; return byeRequest; }
private void TransactionInformationResponseReceived(IPEndPoint localEndPoint, IPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPResponse sipResponse) { m_lastInfoResponse = sipResponse; m_waitForSIPInfoResponse.Set(); }
public SIPRequest GetReferRequest(SIPRequest inviteRequest, SIPResponse inviteResponse, string referToURI) { SIPRequest referRequest = new SIPRequest(SIPMethodsEnum.REFER, inviteRequest.URI); SIPHeader referHeader = new SIPHeader(inviteResponse.Header.From, inviteResponse.Header.To, inviteRequest.Header.CSeq + 1, inviteRequest.Header.CallId); referHeader.Contact = inviteRequest.Header.Contact; referHeader.CSeqMethod = SIPMethodsEnum.REFER; referHeader.ReferTo = referToURI; SIPFromHeader referredBy = new SIPFromHeader(inviteRequest.Header.From.FromName, inviteRequest.Header.From.FromURI, null); referHeader.ReferredBy = referredBy.ToString(); referHeader.AuthenticationHeader = inviteRequest.Header.AuthenticationHeader; IPEndPoint localSIPEndPoint = m_sipTransport.GetIPEndPointsList()[0]; SIPViaHeader viaHeader = new SIPViaHeader(localSIPEndPoint.Address.ToString(), localSIPEndPoint.Port, CallProperties.CreateBranchId()); referHeader.Via.PushViaHeader(viaHeader); referRequest.Header = referHeader; return referRequest; }
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; } }
/// <summary> /// Handler for when an in dialog request is received on an established call. /// Typical types of request will be re-INVITES for things like putting a call on or /// off hold and REFER requests for transfers. Some in dialog request types, such /// as re-INVITES have specific events so they can be bubbled up to the /// application to deal with. /// </summary> /// <param name="sipRequest">The in dialog request received.</param> private async Task DialogRequestReceivedAsync(SIPRequest sipRequest) { if (sipRequest.Method == SIPMethodsEnum.BYE) { logger.LogInformation($"Remote call party hungup {sipRequest.StatusLine}."); Dialogue.DialogueState = SIPDialogueStateEnum.Terminated; SIPNonInviteTransaction byeTx = new SIPNonInviteTransaction(m_transport, sipRequest, null); byeTx.SendResponse(SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null)); CallEnded(); } else if (sipRequest.Method == SIPMethodsEnum.INVITE) { logger.LogDebug($"Re-INVITE request received {sipRequest.StatusLine}."); UASInviteTransaction reInviteTransaction = new UASInviteTransaction(m_transport, sipRequest, m_outboundProxy); try { MediaSession.setRemoteDescription(new RTCSessionDescription { sdp = SDP.ParseSDPDescription(sipRequest.Body), type = RTCSdpType.offer }); CheckRemotePartyHoldCondition(MediaSession.remoteDescription.sdp); var answerSdp = await MediaSession.createAnswer(null).ConfigureAwait(false); Dialogue.RemoteSDP = sipRequest.Body; Dialogue.SDP = answerSdp.ToString(); Dialogue.RemoteCSeq = sipRequest.Header.CSeq; var okResponse = reInviteTransaction.GetOkResponse(SDP.SDP_MIME_CONTENTTYPE, Dialogue.SDP); reInviteTransaction.SendFinalResponse(okResponse); } catch (Exception ex) { logger.LogError(ex, "MediaSession can't process the re-INVITE request."); if (OnReinviteRequest == null) { // The application isn't prepared to accept re-INVITE requests and we can't work out what it was for. // We'll reject as gently as we can to try and not lose the call. SIPResponse notAcceptableResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.NotAcceptable, null); reInviteTransaction.SendFinalResponse(notAcceptableResponse); } else { // The application is going to handle the re-INVITE request. We'll send a Trying response as a precursor. SIPResponse tryingResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Trying, null); await reInviteTransaction.SendProvisionalResponse(tryingResponse).ConfigureAwait(false); OnReinviteRequest.Invoke(reInviteTransaction); } } } else if (sipRequest.Method == SIPMethodsEnum.OPTIONS) { //Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "OPTIONS request for established dialogue " + dialogue.DialogueName + ".", dialogue.Owner)); SIPResponse okResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null); okResponse.Body = Dialogue.RemoteSDP; okResponse.Header.ContentLength = okResponse.Body.Length; okResponse.Header.ContentType = m_sdpContentType; await SendResponseAsync(okResponse).ConfigureAwait(false); } else if (sipRequest.Method == SIPMethodsEnum.MESSAGE) { //Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "MESSAGE for call " + sipRequest.URI.ToString() + ": " + sipRequest.Body + ".", dialogue.Owner)); SIPResponse okResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null); await m_transport.SendResponseAsync(okResponse).ConfigureAwait(false); } else if (sipRequest.Method == SIPMethodsEnum.REFER) { if (sipRequest.Header.ReferTo.IsNullOrBlank()) { // A REFER request must have a Refer-To header. //Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Bad REFER request, no Refer-To header.", dialogue.Owner)); SIPResponse invalidResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.BadRequest, "Missing mandatory Refer-To header"); await SendResponseAsync(invalidResponse).ConfigureAwait(false); } else { //TODO: Add handling logic for in transfer requests from the remote call party. } } else if (sipRequest.Method == SIPMethodsEnum.NOTIFY) { SIPResponse okResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null); await SendResponseAsync(okResponse).ConfigureAwait(false); if (sipRequest.Body?.Length > 0 && sipRequest.Header.ContentType?.Contains(m_sipReferContentType) == true) { OnTransferNotify?.Invoke(sipRequest.Body); } } }
private void TransactionFinalResponseReceived(IPEndPoint localEndPoint, IPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPResponse sipResponse) { m_lastFinalResponse = sipResponse; m_waitForSIPFinalResponse.Set(); }
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; string canonicalDomain = 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); SIPAccount sipAccount = new SIPAccount { Id = Guid.NewGuid(), Owner = "admin", SIPUsername = toUser, SIPDomain = canonicalDomain }; //SIPAccount sipAccount = GetSIPAccount_External(s => s.SIPUsername == toUser); SIPRequestAuthenticationResult authenticationResult = _sipRequestAuthenticator_External?.Invoke(registerTransaction.LocalSIPEndPoint, registerTransaction.RemoteEndPoint, sipRequest, sipAccount, FireProxyLogEvent); if (!_needAuthentication) { SIPResponse okRes = GetOkResponse(sipRequest); registerTransaction.SendFinalResponse(okRes); //Add Camera Item Into Cache CacheDeviceItem(sipRequest); return(RegisterResultEnum.AuthenticationRequired); } 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 + ", " + sipRequest.Header.UserAgent + ".", null)); return(RegisterResultEnum.Forbidden); } else { FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Registrar, SIPMonitorEventTypesEnum.Registrar, "Authentication required for " + toUser + "@" + canonicalDomain + " from " + sipRequest.Header.ProxyReceivedFrom + ".", toUser)); return(RegisterResultEnum.AuthenticationRequired); } } else { // Authenticated. //if (!sipRequest.Header.UserAgent.IsNullOrBlank() && !m_switchboarduserAgentPrefix.IsNullOrBlank() && sipRequest.Header.UserAgent.StartsWith(m_switchboarduserAgentPrefix)) //{ // // Check that the switchboard user is authorised. // var customer = CustomerPersistor_External.Get(x => x.CustomerUsername == sipAccount.Owner); // if (!(customer.ServiceLevel == CustomerServiceLevels.Switchboard.ToString() || customer.ServiceLevel == CustomerServiceLevels.Gold.ToString())) // { // FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Registrar, SIPMonitorEventTypesEnum.Warn, "Register request for switchboard from " + toHeader.ToURI.Host + " rejected as not correct service level.", sipAccount.Owner)); // SIPResponse payReqdResponse = GetErrorResponse(sipRequest, SIPResponseStatusCodesEnum.PaymentRequired, "You need to purchase a Switchboard service"); // registerTransaction.SendFinalResponse(payReqdResponse); // return RegisterResultEnum.SwitchboardPaymentRequired; // } //} 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); //Add Camera Item Into Cache CacheDeviceItem(sipRequest); FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Registrar, SIPMonitorEventTypesEnum.RegisterSuccess, "Empty registration request successful for " + toUser + "@" + canonicalDomain + " from " + sipRequest.Header.ProxyReceivedFrom + ".", toUser)); } else { SIPEndPoint uacRemoteEndPoint = SIPEndPoint.TryParse(sipRequest.Header.ProxyReceivedFrom) ?? registerTransaction.RemoteEndPoint; SIPEndPoint proxySIPEndPoint = SIPEndPoint.TryParse(sipRequest.Header.ProxyReceivedOn); 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); //Add Camera Item Into Cache CacheDeviceItem(sipRequest); } 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); } }
public SIPResponse WaitForFinalResponse(int waitSeconds, SIPRequest sipRequest) { DateTime startWaitTime = DateTime.Now; m_waitForSIPFinalResponse.Reset(); m_lastFinalResponse = null; while (m_lastFinalResponse == null && DateTime.Now.Subtract(startWaitTime).TotalSeconds < waitSeconds) { m_waitForSIPFinalResponse.WaitOne(Convert.ToInt32((waitSeconds - DateTime.Now.Subtract(startWaitTime).TotalSeconds) * 1000), false); if (m_lastFinalResponse != null && m_lastFinalResponse.Header.CallId == sipRequest.Header.CallId) { break; } else { m_lastFinalResponse = null; } } return m_lastFinalResponse; }
public void AddRegisterRequest(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPRequest registerRequest) { try { if (registerRequest.Method == SIPMethodsEnum.REGISTER) { SIPSorceryPerformanceMonitor.IncrementCounter(SIPSorceryPerformanceMonitor .REGISTRAR_REGISTRATION_REQUESTS_PER_SECOND); int requestedExpiry = GetRequestedExpiry(registerRequest); if (registerRequest.Header.To == null) { Logger.Logger.Debug("Bad register request, no To header from " + remoteEndPoint + "."); SIPResponse badReqResponse = SIPTransport.GetResponse(registerRequest, SIPResponseStatusCodesEnum.BadRequest, "Missing To header"); _sipTransport.SendResponse(badReqResponse); } else if (registerRequest.Header.To.ToURI.User.IsNullOrBlank()) { Logger.Logger.Debug("Bad register request, no To user from " + remoteEndPoint + "."); SIPResponse badReqResponse = SIPTransport.GetResponse(registerRequest, SIPResponseStatusCodesEnum.BadRequest, "Missing username on To header"); _sipTransport.SendResponse(badReqResponse); } else if (registerRequest.Header.Contact == null || registerRequest.Header.Contact.Count == 0) { Logger.Logger.Debug("Bad register request, no Contact header from " + remoteEndPoint + "."); SIPResponse badReqResponse = SIPTransport.GetResponse(registerRequest, SIPResponseStatusCodesEnum.BadRequest, "Missing Contact header"); _sipTransport.SendResponse(badReqResponse); } else if (requestedExpiry > 0 && requestedExpiry < m_minimumBindingExpiry) { Logger.Logger.Debug("Bad register request, no expiry of " + requestedExpiry + " to small from " + remoteEndPoint + "."); SIPResponse tooFrequentResponse = GetErrorResponse(registerRequest, SIPResponseStatusCodesEnum.IntervalTooBrief, null); tooFrequentResponse.Header.MinExpires = m_minimumBindingExpiry; _sipTransport.SendResponse(tooFrequentResponse); } else { if (m_registerQueue.Count < MAX_REGISTER_QUEUE_SIZE) { var registrarTransaction = _sipTransport.CreateNonInviteTransaction(registerRequest, remoteEndPoint, localSIPEndPoint, null); lock (m_registerQueue) { m_registerQueue.Enqueue(registrarTransaction); } } else { Logger.Logger.Error("Register queue exceeded max queue size " + MAX_REGISTER_QUEUE_SIZE + ", overloaded response sent."); SIPResponse overloadedResponse = SIPTransport.GetResponse(registerRequest, SIPResponseStatusCodesEnum.TemporarilyUnavailable, "Registrar overloaded, please try again shortly"); _sipTransport.SendResponse(overloadedResponse); } m_registerARE.Set(); } } } catch (Exception excp) { Logger.Logger.Error("Exception AddRegisterRequest (" + remoteEndPoint.ToString() + "). ->" + excp.Message); } }
private SIPResponse GetResponse(SIPHeader requestHeader, SIPResponseStatusCodesEnum responseCode) { try { SIPResponse response = new SIPResponse(responseCode); response.Header = new SIPHeader(requestHeader.Contact, requestHeader.From, requestHeader.To, requestHeader.CSeq, requestHeader.CallId); response.Header.CSeqMethod = requestHeader.CSeqMethod; response.Header.Via = requestHeader.Via; response.Header.MaxForwards = Int32.MinValue; return response; } catch (Exception excp) { logger.Error("Exception GetResponse. " + excp.Message); 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); } }
void transport_SIPResponseInTraceEvent(SIPEndPoint localEndPoint, SIPEndPoint fromEndPoint, SIPResponse sipResponse) { logger.LogDebug("Response In: " + localEndPoint + "<-" + fromEndPoint.ToString() + "\n" + sipResponse.ToString()); }
public void ProcessNotifyRequest(SIPRequest sipRequest) { try { // Hack to work around MWI request from callcentric not having a trailing CRLF and breaking some softphones like the Bria. if (sipRequest.Header.Event == MWI_EVENT_TYPE && sipRequest.Body.NotNullOrBlank() && sipRequest.Body.Substring(sipRequest.Body.Length - 2) != m_crlf) { sipRequest.Body += m_crlf; } string fromURI = (sipRequest.Header.From != null && sipRequest.Header.From.FromURI != null) ? sipRequest.Header.From.FromURI.ToString() : "unknown"; string domain = GetCanonicalDomain_External(sipRequest.URI.Host, true); if (domain != null) { SIPAccountAsset sipAccount = GetSIPAccount_External(s => s.SIPUsername == sipRequest.URI.User && s.SIPDomain == domain); if (sipAccount != null) { List <SIPRegistrarBinding> bindings = GetSIPAccountBindings_External(b => b.SIPAccountId == sipAccount.Id, null, 0, MAX_FORWARD_BINDINGS); if (bindings != null) { foreach (SIPRegistrarBinding binding in bindings) { SIPURI dstURI = binding.MangledContactSIPURI; SIPEndPoint localSIPEndPoint = (m_outboundProxy != null) ? m_sipTransport.GetDefaultSIPEndPoint(m_outboundProxy.Protocol) : m_sipTransport.GetDefaultSIPEndPoint(dstURI.Protocol); SIPEndPoint dstSIPEndPoint = null; // If the outbound proxy is a loopback address, as it will normally be for local deployments, then it cannot be overriden. if (m_outboundProxy != null && IPAddress.IsLoopback(m_outboundProxy.Address)) { dstSIPEndPoint = m_outboundProxy; } else if (binding.ProxySIPEndPoint != null) { // If the binding has a specific proxy end point sent then the request needs to be forwarded to the proxy's default end point for it to take care of. dstSIPEndPoint = new SIPEndPoint(SIPProtocolsEnum.udp, new IPEndPoint(binding.ProxySIPEndPoint.Address, m_defaultSIPPort)); } else if (m_outboundProxy != null) { dstSIPEndPoint = m_outboundProxy; } else { SIPDNSLookupResult lookupResult = m_sipTransport.GetURIEndPoint(dstURI, false); if (lookupResult.LookupError != null) { Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Notifier, SIPMonitorEventTypesEnum.MWI, "A NOTIFY request from " + fromURI + " was not forwarded due to DNS failure for " + dstURI.Host + ", " + lookupResult.LookupError + ".", sipAccount.Owner)); } else { dstSIPEndPoint = lookupResult.GetSIPEndPoint(); } } if (dstSIPEndPoint != null) { // Rather than create a brand new request copy the received one and modify the headers that need to be unique. SIPRequest notifyRequest = sipRequest.Copy(); notifyRequest.URI = dstURI; notifyRequest.Header.Contact = SIPContactHeader.CreateSIPContactList(new SIPURI(dstURI.Scheme, localSIPEndPoint)); notifyRequest.Header.To = new SIPToHeader(null, dstURI, null); notifyRequest.Header.CallId = CallProperties.CreateNewCallId(); SIPViaHeader viaHeader = new SIPViaHeader(localSIPEndPoint, CallProperties.CreateBranchId()); notifyRequest.Header.Vias = new SIPViaSet(); notifyRequest.Header.Vias.PushViaHeader(viaHeader); // If the binding has a proxy socket defined set the header to ask the upstream proxy to use it. if (binding.ProxySIPEndPoint != null) { notifyRequest.Header.ProxySendFrom = binding.ProxySIPEndPoint.ToString(); // If the binding has a specific proxy end point sent then the request needs to be forwarded to the proxy's default end point for it to take care of. dstSIPEndPoint = new SIPEndPoint(SIPProtocolsEnum.udp, new IPEndPoint(binding.ProxySIPEndPoint.Address, m_defaultSIPPort)); } Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Notifier, SIPMonitorEventTypesEnum.MWI, "Forwarding NOTIFY request from " + fromURI + " to registered binding at " + dstURI.ToString() + ", proxy " + dstSIPEndPoint.ToString() + ".", sipAccount.Owner)); SIPNonInviteTransaction notifyTransaction = m_sipTransport.CreateNonInviteTransaction(notifyRequest, dstSIPEndPoint, localSIPEndPoint, dstSIPEndPoint); notifyTransaction.SendReliableRequest(); } else { Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Notifier, SIPMonitorEventTypesEnum.MWI, "A NOTIFY request from " + fromURI + " was not forwarded as no destination end point was resolved.", sipAccount.Owner)); } } // Send OK response to server. SIPResponse okResponse = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null); m_sipTransport.SendResponse(okResponse); } else { // Send unavailable response to server. Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Notifier, SIPMonitorEventTypesEnum.MWI, "NOTIFY request from " + fromURI + " for " + sipAccount.SIPUsername + "@" + sipAccount.SIPDomain + " but no bindings available, responding with temporarily unavailable.", sipAccount.Owner)); SIPResponse notAvailableResponse = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.TemporarilyUnavailable, null); m_sipTransport.SendResponse(notAvailableResponse); } } else { // Send Not found response to server. Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Notifier, SIPMonitorEventTypesEnum.MWI, "NOTIFY request from " + fromURI + " for " + sipRequest.URI.ToString() + " but no matching SIP account, responding with not found.", null)); SIPResponse notFoundResponse = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.NotFound, null); m_sipTransport.SendResponse(notFoundResponse); } } else { // Send Not Serviced response to server. Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Notifier, SIPMonitorEventTypesEnum.MWI, "NOTIFY request from " + fromURI + " for a non-serviced domain responding with not found.", null)); SIPResponse notServicedResponse = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.NotFound, "Domain not serviced"); m_sipTransport.SendResponse(notServicedResponse); } } catch (Exception excp) { logger.Error("Exception SIPNotifyManager ProcessNotifyRequest. " + excp.Message); } }
static void Main(string[] args) { Console.WriteLine("SIPSorcery SIP to WebRTC example."); Console.WriteLine("Press ctrl-c to exit."); // Plumbing code to facilitate a graceful exit. CancellationTokenSource exitCts = new CancellationTokenSource(); // Cancellation token to stop the SIP transport and RTP stream. AddConsoleLogger(); // Start web socket. Console.WriteLine("Starting web socket server..."); _webSocketServer = new WebSocketServer(IPAddress.Any, WEBSOCKET_PORT, true); _webSocketServer.SslConfiguration.ServerCertificate = new X509Certificate2(WEBSOCKET_CERTIFICATE_PATH); _webSocketServer.SslConfiguration.CheckCertificateRevocation = false; //_webSocketServer.Log.Level = WebSocketSharp.LogLevel.Debug; _webSocketServer.AddWebSocketService <SDPExchange>("/", (sdpExchanger) => { sdpExchanger.WebSocketOpened += SendSDPOffer; sdpExchanger.SDPAnswerReceived += SDPAnswerReceived; }); _webSocketServer.Start(); Console.WriteLine($"Waiting for browser web socket connection to {_webSocketServer.Address}:{_webSocketServer.Port}..."); // Set up a default SIP transport. var sipTransport = new SIPTransport(); sipTransport.AddSIPChannel(new SIPUDPChannel(new IPEndPoint(IPAddress.Any, SIP_LISTEN_PORT))); //EnableTraceLogs(sipTransport); RTPMediaSession RtpMediaSession = null; // Create a SIP user agent to receive a call from a remote SIP client. // Wire up event handlers for the different stages of the call. var userAgent = new SIPUserAgent(sipTransport, null); // We're only answering SIP calls, not placing them. userAgent.OnCallHungup += () => { Log.LogInformation($"Call hungup by remote party."); exitCts.Cancel(); }; userAgent.ServerCallCancelled += (uas) => Log.LogInformation("Incoming call cancelled by caller."); sipTransport.SIPTransportRequestReceived += async(localEndPoint, remoteEndPoint, sipRequest) => { if (sipRequest.Header.From != null && sipRequest.Header.From.FromTag != null && sipRequest.Header.To != null && sipRequest.Header.To.ToTag != null) { // This is an in-dialog request that will be handled directly by a user agent instance. } else if (sipRequest.Method == SIPMethodsEnum.INVITE) { if (userAgent?.IsCallActive == true) { Log.LogWarning($"Busy response returned for incoming call request from {remoteEndPoint}: {sipRequest.StatusLine}."); // If we are already on a call return a busy response. UASInviteTransaction uasTransaction = new UASInviteTransaction(sipTransport, sipRequest, null); SIPResponse busyResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.BusyHere, null); uasTransaction.SendFinalResponse(busyResponse); } else { Log.LogInformation($"Incoming call request from {remoteEndPoint}: {sipRequest.StatusLine}."); var incomingCall = userAgent.AcceptCall(sipRequest); RtpMediaSession = new RTPMediaSession(SDPMediaTypesEnum.audio, new SDPMediaFormat(SDPMediaFormatsEnum.PCMU), AddressFamily.InterNetwork); await userAgent.Answer(incomingCall, RtpMediaSession); RtpMediaSession.OnRtpPacketReceived += (mediaType, rtpPacket) => OnMediaSampleReady?.Invoke(mediaType, rtpPacket.Header.Timestamp, rtpPacket.Payload); Log.LogInformation($"Answered incoming call from {sipRequest.Header.From.FriendlyDescription()} at {remoteEndPoint}."); } } else { Log.LogDebug($"SIP {sipRequest.Method} request received but no processing has been set up for it, rejecting."); SIPResponse notAllowedResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.MethodNotAllowed, null); await sipTransport.SendResponseAsync(notAllowedResponse); } }; // Ctrl-c will gracefully exit the call at any point. Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e) { e.Cancel = true; exitCts.Cancel(); }; // Wait for a signal saying the call failed, was cancelled with ctrl-c or completed. exitCts.Token.WaitHandle.WaitOne(); #region Cleanup. Log.LogInformation("Exiting..."); RtpMediaSession?.Close(); if (userAgent != null) { if (userAgent.IsCallActive) { Log.LogInformation($"Hanging up call to {userAgent?.CallDescriptor?.To}."); userAgent.Hangup(); } // Give the BYE or CANCEL request time to be transmitted. Log.LogInformation("Waiting 1s for call to clean up..."); Task.Delay(1000).Wait(); } SIPSorcery.Net.DNSManager.Stop(); if (sipTransport != null) { Log.LogInformation("Shutting down SIP transport..."); sipTransport.Shutdown(); } #endregion }
public SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum serverType, SIPMonitorEventTypesEnum eventType, string message, SIPRequest sipRequest, SIPResponse sipResponse, SIPEndPoint localEndPoint, SIPEndPoint remoteEndPoint, SIPCallDirection callDirection) { m_serialisationPrefix = SERIALISATION_PREFIX; ClientType = SIPMonitorClientTypesEnum.Console; ServerType = serverType; EventType = eventType; Message = message; RemoteEndPoint = remoteEndPoint; ServerEndPoint = localEndPoint; Created = DateTimeOffset.UtcNow; #if !SILVERLIGHT ProcessID = Process.GetCurrentProcess().Id; #endif string dirn = (callDirection == SIPCallDirection.In) ? CALLDIRECTION_IN_STRING : CALLDIRECTION_OUT_STRING; if (sipRequest != null) { Message = "REQUEST (" + Created.ToString("HH:mm:ss:fff") + "): " + localEndPoint + dirn + remoteEndPoint + "\r\n" + sipRequest.ToString(); } else if (sipResponse != null) { Message = "RESPONSE (" + Created.ToString("HH:mm:ss:fff") + "): " + localEndPoint + dirn + remoteEndPoint + "\r\n" + sipResponse.ToString(); } }
/// <summary> /// Handler for processing incoming SIP requests. /// </summary> /// <param name="localSIPEndPoint">The end point the request was received on.</param> /// <param name="remoteEndPoint">The end point the request came from.</param> /// <param name="sipRequest">The SIP request received.</param> private void SIPTransportRequestReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPRequest sipRequest) { if (sipRequest.Method == SIPMethodsEnum.BYE) { if (m_uac != null && m_uac.SIPDialogue != null && sipRequest.Header.CallId == m_uac.SIPDialogue.CallId) { // Call has been hungup by remote end. StatusMessage("Call hungup by remote end."); SIPNonInviteTransaction byeTransaction = m_sipTransport.CreateNonInviteTransaction(sipRequest, remoteEndPoint, localSIPEndPoint, null); SIPResponse byeResponse = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null); byeTransaction.SendFinalResponse(byeResponse); CallFinished(); } else if (m_uas != null && m_uas.SIPDialogue != null && sipRequest.Header.CallId == m_uas.SIPDialogue.CallId) { // Call has been hungup by remote end. StatusMessage("Call hungup."); SIPNonInviteTransaction byeTransaction = m_sipTransport.CreateNonInviteTransaction(sipRequest, remoteEndPoint, localSIPEndPoint, null); SIPResponse byeResponse = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null); byeTransaction.SendFinalResponse(byeResponse); CallFinished(); } else { logger.Debug("Unmatched BYE request received for " + sipRequest.URI.ToString() + "."); SIPResponse noCallLegResponse = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.CallLegTransactionDoesNotExist, null); m_sipTransport.SendResponse(noCallLegResponse); } } else if (sipRequest.Method == SIPMethodsEnum.INVITE) { StatusMessage("Incoming call request: " + localSIPEndPoint + "<-" + remoteEndPoint + " " + sipRequest.URI.ToString() + "."); UASInviteTransaction uasTransaction = m_sipTransport.CreateUASTransaction(sipRequest, remoteEndPoint, localSIPEndPoint, null); m_uas = new SIPServerUserAgent(m_sipTransport, null, null, null, SIPCallDirection.In, null, null, null, uasTransaction); m_uas.CallCancelled += UASCallCancelled; m_uas.Progress(SIPResponseStatusCodesEnum.Trying, null, null, null, null); m_uas.Progress(SIPResponseStatusCodesEnum.Ringing, null, null, null, null); IncomingCall(); } else if (sipRequest.Method == SIPMethodsEnum.CANCEL) { UASInviteTransaction inviteTransaction = (UASInviteTransaction)m_sipTransport.GetTransaction(SIPTransaction.GetRequestTransactionId(sipRequest.Header.Vias.TopViaHeader.Branch, SIPMethodsEnum.INVITE)); if (inviteTransaction != null) { StatusMessage("Call was cancelled by remote end."); SIPCancelTransaction cancelTransaction = m_sipTransport.CreateCancelTransaction(sipRequest, remoteEndPoint, localSIPEndPoint, inviteTransaction); cancelTransaction.GotRequest(localSIPEndPoint, remoteEndPoint, sipRequest); } else { logger.Debug("No matching transaction was found for CANCEL to " + sipRequest.URI.ToString() + "."); SIPResponse noCallLegResponse = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.CallLegTransactionDoesNotExist, null); m_sipTransport.SendResponse(noCallLegResponse); } CallFinished(); } else { logger.Debug("SIP " + sipRequest.Method + " request received but no processing has been set up for it, rejecting."); SIPResponse notAllowedResponse = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.MethodNotAllowed, null); m_sipTransport.SendResponse(notAllowedResponse); } }
static void Main() { Console.WriteLine("SIPSorcery client user agent example."); Console.WriteLine("Press ctrl-c to exit."); // Plumbing code to facilitate a graceful exit. CancellationTokenSource rtpCts = new CancellationTokenSource(); // Cancellation token to stop the RTP stream. bool isCallHungup = false; bool hasCallFailed = false; AddConsoleLogger(); SIPURI callUri = SIPURI.ParseSIPURI(DEFAULT_DESTINATION_SIP_URI); Log.LogInformation($"Call destination {callUri}."); // Set up a default SIP transport. var sipTransport = new SIPTransport(); sipTransport.AddSIPChannel(new SIPUDPChannel(new IPEndPoint(IPAddress.Any, 0))); // Un/comment this line to see/hide each SIP message sent and received. EnableTraceLogs(sipTransport); // Note this relies on the callURI host being an IP address. If it's a hostname a DNS lookup is required. IPAddress localIPAddress = NetServices.GetLocalAddressForRemote(callUri.ToSIPEndPoint().Address); // Initialise an RTP session to receive the RTP packets from the remote SIP server. var rtpSession = new RTPMediaSession(SDPMediaTypesEnum.audio, (int)SDPMediaFormatsEnum.PCMU, localIPAddress.AddressFamily); var offerSDP = rtpSession.GetSDP(localIPAddress); // Create a client user agent to place a call to a remote SIP server along with event handlers for the different stages of the call. var uac = new SIPClientUserAgent(sipTransport); uac.CallTrying += (uac, resp) => { Log.LogInformation($"{uac.CallDescriptor.To} Trying: {resp.StatusCode} {resp.ReasonPhrase}."); }; uac.CallRinging += (uac, resp) => Log.LogInformation($"{uac.CallDescriptor.To} Ringing: {resp.StatusCode} {resp.ReasonPhrase}."); uac.CallFailed += (uac, err) => { Log.LogWarning($"{uac.CallDescriptor.To} Failed: {err}"); hasCallFailed = true; }; uac.CallAnswered += (uac, resp) => { if (resp.Status == SIPResponseStatusCodesEnum.Ok) { Log.LogInformation($"{uac.CallDescriptor.To} Answered: {resp.StatusCode} {resp.ReasonPhrase}."); rtpSession.SetRemoteSDP(SDP.ParseSDPDescription(resp.Body)); Log.LogDebug($"Remote RTP socket {rtpSession.DestinationEndPoint}."); } else { Log.LogWarning($"{uac.CallDescriptor.To} Answered: {resp.StatusCode} {resp.ReasonPhrase}."); } }; // The only incoming request that needs to be explicitly handled for this example is if the remote end hangs up the call. sipTransport.SIPTransportRequestReceived += async(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPRequest sipRequest) => { if (sipRequest.Method == SIPMethodsEnum.BYE) { SIPResponse okResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null); await sipTransport.SendResponseAsync(okResponse); if (uac.IsUACAnswered) { Log.LogInformation("Call was hungup by remote server."); isCallHungup = true; rtpCts.Cancel(); } } }; // Wire up the RTP receive session to the default speaker. var(audioOutEvent, audioOutProvider) = GetAudioOutputDevice(); rtpSession.OnRtpPacketReceived += (rtpPacket) => { var sample = rtpPacket.Payload; for (int index = 0; index < sample.Length; index++) { short pcm = NAudio.Codecs.MuLawDecoder.MuLawToLinearSample(sample[index]); byte[] pcmSample = new byte[] { (byte)(pcm & 0xFF), (byte)(pcm >> 8) }; audioOutProvider.AddSamples(pcmSample, 0, 2); } }; // Send audio packets (in this case silence) to the callee. Task.Run(() => SendSilence(rtpSession, rtpCts)); // Start the thread that places the call. SIPCallDescriptor callDescriptor = new SIPCallDescriptor( SIPConstants.SIP_DEFAULT_USERNAME, null, callUri.ToString(), SIPConstants.SIP_DEFAULT_FROMURI, null, null, null, null, SIPCallDirection.Out, SDP.SDP_MIME_CONTENTTYPE, offerSDP.ToString(), null); uac.Call(callDescriptor); // Ctrl-c will gracefully exit the call at any point. Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e) { e.Cancel = true; rtpCts.Cancel(); }; // Give the call some time to answer. Task.Delay(3000).Wait(); // Send some DTMF key presses via RTP events. var dtmf5 = new RTPEvent(0x05, false, RTPEvent.DEFAULT_VOLUME, 1200, RTPMediaSession.DTMF_EVENT_PAYLOAD_ID); rtpSession.SendDtmfEvent(dtmf5, rtpCts.Token).Wait(); Task.Delay(2000, rtpCts.Token).Wait(); var dtmf9 = new RTPEvent(0x09, false, RTPEvent.DEFAULT_VOLUME, 1200, RTPMediaSession.DTMF_EVENT_PAYLOAD_ID); rtpSession.SendDtmfEvent(dtmf9, rtpCts.Token).Wait(); Task.Delay(2000, rtpCts.Token).Wait(); var dtmf2 = new RTPEvent(0x02, false, RTPEvent.DEFAULT_VOLUME, 1200, RTPMediaSession.DTMF_EVENT_PAYLOAD_ID); rtpSession.SendDtmfEvent(dtmf2, rtpCts.Token).Wait(); Task.Delay(2000, rtpCts.Token).ContinueWith((task) => { }).Wait(); // Don't care about the exception if the cancellation token is set. Log.LogInformation("Exiting..."); rtpCts.Cancel(); audioOutEvent?.Stop(); rtpSession.CloseSession(null); if (!isCallHungup && uac != null) { if (uac.IsUACAnswered) { Log.LogInformation($"Hanging up call to {uac.CallDescriptor.To}."); uac.Hangup(); } else if (!hasCallFailed) { Log.LogInformation($"Cancelling call to {uac.CallDescriptor.To}."); uac.Cancel(); } // Give the BYE or CANCEL request time to be transmitted. Log.LogInformation("Waiting 1s for call to clean up..."); Task.Delay(1000).Wait(); } SIPSorcery.Net.DNSManager.Stop(); if (sipTransport != null) { Log.LogInformation("Shutting down SIP transport..."); sipTransport.Shutdown(); } }
private void SIPResponseOutTraceEvent(SIPEndPoint localEP, SIPEndPoint remoteEP, SIPResponse sipResponse) { logger.LogDebug($"Response Sent {localEP}<-{remoteEP}: {sipResponse.ShortDescription}."); if (_homerSIPClient != null) { var hepBuffer = HepPacket.GetBytes(localEP, remoteEP, DateTime.Now, 333, "myHep", sipResponse.ToString()); _homerSIPClient.SendAsync(hepBuffer, hepBuffer.Length, HOMER_SERVER_ADDRESS, HOMER_SERVER_PORT); } }
private void ByeServerFinalResponseReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPResponse sipResponse) { try { Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentServer, SIPMonitorEventTypesEnum.DialPlan, "Response " + sipResponse.StatusCode + " " + sipResponse.ReasonPhrase + " for " + sipTransaction.TransactionRequest.URI.ToString() + ".", Owner)); SIPNonInviteTransaction byeTransaction = sipTransaction as SIPNonInviteTransaction; byeTransaction.NonInviteTransactionFinalResponseReceived -= ByeServerFinalResponseReceived; if ((sipResponse.Status == SIPResponseStatusCodesEnum.ProxyAuthenticationRequired || sipResponse.Status == SIPResponseStatusCodesEnum.Unauthorised) && SIPAccount != null) { // Resend BYE with credentials. SIPAuthorisationDigest authRequest = sipResponse.Header.AuthenticationHeader.SIPDigest; SIPURI contactUri = sipResponse.Header.Contact.Any() ? sipResponse.Header.Contact[0].ContactURI : sipResponse.Header.From.FromURI; authRequest.SetCredentials(SIPAccount.SIPUsername, SIPAccount.SIPPassword, contactUri.ToString(), SIPMethodsEnum.BYE.ToString()); SIPRequest authByeRequest = byeTransaction.TransactionRequest; authByeRequest.Header.AuthenticationHeader = new SIPAuthenticationHeader(authRequest); authByeRequest.Header.AuthenticationHeader.SIPDigest.Response = authRequest.Digest; authByeRequest.Header.Vias.TopViaHeader.Branch = CallProperties.CreateBranchId(); authByeRequest.Header.CSeq = authByeRequest.Header.CSeq + 1; SIPNonInviteTransaction bTransaction = m_sipTransport.CreateNonInviteTransaction(authByeRequest, null, localSIPEndPoint, null); bTransaction.SendReliableRequest(); } } catch (Exception excp) { Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentClient, SIPMonitorEventTypesEnum.Error, "Exception ByServerFinalResponseReceived. " + excp.Message, Owner)); } }
/// <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() + ".", null)); if (sipResponse.Status == SIPResponseStatusCodesEnum.ProxyAuthenticationRequired || sipResponse.Status == SIPResponseStatusCodesEnum.Unauthorised) { if (sipResponse.Header.AuthenticationHeader != null) { if (m_attempts >= m_maxRegisterAttempts) { Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentClient, SIPMonitorEventTypesEnum.ContactRegisterFailed, "Registration to " + m_sipAccountAOR.ToString() + " reached the maximum number of allowed attempts without a failure condition.", null)); m_isRegistered = false; RegistrationTemporaryFailure?.Invoke(m_sipAccountAOR, "Registration reached the maximum number of allowed attempts."); m_waitForRegistrationMRE.Set(); } else { m_attempts++; SIPRequest authenticatedRequest = GetAuthenticatedRegistrationRequest(sipTransaction.TransactionRequest, sipResponse); SIPEndPoint registrarSIPEndPoint = m_outboundProxy; if (registrarSIPEndPoint == null) { //SIPDNSLookupResult lookupResult = m_sipTransport.GetHostEndPoint(m_registrarHost, false); SIPURI uri = SIPURI.ParseSIPURIRelaxed(m_registrarHost); var lookupResult = m_sipTransport.ResolveSIPUriAsync(uri).ConfigureAwait(false).GetAwaiter().GetResult(); if (lookupResult == null) { Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentClient, SIPMonitorEventTypesEnum.ContactRegisterFailed, "Could not resolve " + m_registrarHost + ".", null)); } else { registrarSIPEndPoint = lookupResult; } } if (registrarSIPEndPoint == null) { logger.LogWarning("SIPRegistrationAgent could not resolve " + m_registrarHost + "."); RegistrationFailed?.Invoke(m_sipAccountAOR, "Could not resolve " + m_registrarHost + "."); } else { SIPNonInviteTransaction regAuthTransaction = new SIPNonInviteTransaction(m_sipTransport, authenticatedRequest, registrarSIPEndPoint); regAuthTransaction.NonInviteTransactionFinalResponseReceived += (lep, rep, tn, rsp) => { ThreadPool.QueueUserWorkItem(delegate { AuthResponseReceived(lep, rep, tn, rsp); }); return(Task.FromResult(SocketError.Success)); }; regAuthTransaction.NonInviteTransactionTimedOut += (tn) => { ThreadPool.QueueUserWorkItem(delegate { RegistrationTimedOut(tn); }); }; m_sipTransport.SendTransaction(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() + ".", null)); m_isRegistered = false; RegistrationTemporaryFailure?.Invoke(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); RegistrationSuccessful?.Invoke(m_sipAccountAOR); } else { m_isRegistered = false; RegistrationRemoved?.Invoke(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.", null)); string reasonPhrase = (sipResponse.ReasonPhrase.IsNullOrBlank()) ? sipResponse.Status.ToString() : sipResponse.ReasonPhrase; RegistrationFailed?.Invoke(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.", null)); SendInitialRegister(); } else { Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentClient, SIPMonitorEventTypesEnum.ContactRegisterFailed, "Registration failed with " + sipResponse.Status + " for " + m_sipAccountAOR.ToString() + ".", null)); m_isRegistered = false; RegistrationTemporaryFailure?.Invoke(m_sipAccountAOR, "Registration failed with " + sipResponse.Status + "."); m_waitForRegistrationMRE.Set(); } } } catch (Exception excp) { logger.LogError("Exception SIPRegistrationUserAgent ServerResponseReceived (" + remoteEndPoint + "). " + excp.Message); } }
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 SIPRequest GetAuthenticatedRegistrationRequest(SIPRequest registerRequest, SIPResponse sipResponse) { try { SIPAuthorisationDigest authRequest = sipResponse.Header.AuthenticationHeader.SIPDigest; string username = (m_authUsername != null) ? m_authUsername : m_sipAccountAOR.User; authRequest.SetCredentials(username, m_password, registerRequest.URI.ToString(), SIPMethodsEnum.REGISTER.ToString()); if (!this.m_realm.IsNullOrBlank()) { authRequest.Realm = this.m_realm; } SIPRequest regRequest = registerRequest.Copy(); regRequest.SetSendFromHints(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; return(regRequest); } catch (Exception excp) { logger.LogError("Exception GetAuthenticatedRegistrationRequest. " + excp.Message); throw excp; } }
static void Main() { Console.WriteLine("SIPSorcery client user agent example."); Console.WriteLine("Press ctrl-c to exit."); CancellationTokenSource exitCts = new CancellationTokenSource(); // Cancellation token to stop the SIP transport and RTP stream. AddConsoleLogger(); // Set up a default SIP transport. var sipTransport = new SIPTransport(); sipTransport.AddSIPChannel(new SIPUDPChannel(new IPEndPoint(IPAddress.Any, SIP_LISTEN_PORT))); // Un/comment this line to see/hide each SIP message sent and received. EnableTraceLogs(sipTransport); // To keep things a bit simpler this example only supports a single call at a time and the SIP server user agent // acts as a singleton SIPUserAgent userAgent = new SIPUserAgent(sipTransport, null); CancellationTokenSource rtpCts = null; // Cancellation token to stop the RTP stream. Socket rtpSocket = null; Socket controlSocket = null; // Because this is a server user agent the SIP transport must start listening for client user agents. sipTransport.SIPTransportRequestReceived += (SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPRequest sipRequest) => { try { if (sipRequest.Header.From != null && sipRequest.Header.From.FromTag != null && sipRequest.Header.To != null && sipRequest.Header.To.ToTag != null) { userAgent.InDialogRequestReceivedAsync(sipRequest).Wait(); } if (sipRequest.Method == SIPMethodsEnum.INVITE) { SIPSorcery.Sys.Log.Logger.LogInformation($"Incoming call request: {localSIPEndPoint}<-{remoteEndPoint} {sipRequest.URI}."); // Check there's a codec we support in the INVITE offer. var offerSdp = SDP.ParseSDPDescription(sipRequest.Body); IPEndPoint dstRtpEndPoint = SDP.GetSDPRTPEndPoint(sipRequest.Body); RTPSession rtpSession = null; string audioFile = null; if (offerSdp.Media.Any(x => x.Media == SDPMediaTypesEnum.audio && x.HasMediaFormat((int)RTPPayloadTypesEnum.PCMU))) { Log.LogDebug($"Using PCMU RTP media type and audio file {AUDIO_FILE_PCMU}."); rtpSession = new RTPSession((int)RTPPayloadTypesEnum.PCMU, null, null); audioFile = AUDIO_FILE_PCMU; } if (rtpSession == null) { // Didn't get a match on the codecs we support. SIPResponse noMatchingCodecResponse = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.NotAcceptableHere, null); sipTransport.SendResponse(noMatchingCodecResponse); } else { // If there's already a call in progress hang it up. Of course this is not ideal for a real softphone or server but it // means this example can be kept simpler. if (userAgent?.IsAnswered == true) { userAgent?.Hangup(); } rtpCts?.Cancel(); UASInviteTransaction uasTransaction = sipTransport.CreateUASTransaction(sipRequest, null); if (userAgent.AcceptCall(uasTransaction)) { rtpCts = new CancellationTokenSource(); // The RTP socket is listening on IPAddress.Any but the IP address placed into the SDP needs to be one the caller can reach. IPAddress rtpAddress = NetServices.GetLocalAddressForRemote(dstRtpEndPoint.Address); // Initialise an RTP session to receive the RTP packets from the remote SIP server. NetServices.CreateRtpSocket(rtpAddress, RTP_PORT_START, RTP_PORT_END, false, out rtpSocket, out controlSocket); var rtpRecvSession = new RTPSession((int)RTPPayloadTypesEnum.PCMU, null, null); var rtpSendSession = new RTPSession((int)RTPPayloadTypesEnum.PCMU, null, null); rtpSendSession.DestinationEndPoint = dstRtpEndPoint; rtpRecvSession.OnReceiveFromEndPointChanged += (oldEP, newEP) => { Log.LogDebug($"RTP destination end point changed from {oldEP} to {newEP}."); rtpSendSession.DestinationEndPoint = newEP; }; Task.Run(() => RecvRtp(rtpSocket, rtpRecvSession, rtpCts)); Task.Run(() => SendRtp(rtpSocket, rtpSendSession, rtpCts)); userAgent.Answer(GetSDP(rtpSocket.LocalEndPoint as IPEndPoint)); } } } else if (sipRequest.Method == SIPMethodsEnum.SUBSCRIBE) { SIPResponse notAllowededResponse = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.MethodNotAllowed, null); sipTransport.SendResponse(notAllowededResponse); } else if (sipRequest.Method == SIPMethodsEnum.OPTIONS || sipRequest.Method == SIPMethodsEnum.REGISTER) { SIPResponse optionsResponse = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null); sipTransport.SendResponse(optionsResponse); } } catch (Exception reqExcp) { SIPSorcery.Sys.Log.Logger.LogWarning($"Exception handling {sipRequest.Method}. {reqExcp.Message}"); } }; // Ctrl-c will gracefully exit the call at any point. Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e) { e.Cancel = true; exitCts.Cancel(); rtpCts?.Cancel(); }; // At this point the call has been initiated and everything will be handled in an event handler. Task.Run(async() => { try { while (!exitCts.Token.WaitHandle.WaitOne(0)) { var keyProps = Console.ReadKey(); if (keyProps.KeyChar == 't') { // Initiate a transfer. bool transferResult = await userAgent.Transfer(SIPURI.ParseSIPURI(TRANSFER_DESTINATION_SIP_URI), new TimeSpan(0, 0, TRANSFER_TIMEOUT_SECONDS), exitCts.Token); if (transferResult) { // If the transfer was accepted the original call will already have been hungup. userAgent = null; exitCts.Cancel(); } else { Log.LogWarning($"Transfer to {TRANSFER_DESTINATION_SIP_URI} failed."); } } else if (keyProps.KeyChar == 'q') { // Quit application. exitCts.Cancel(); } } } catch (Exception excp) { Log.LogError($"Exception Key Press listener. {excp.Message}."); } }); // Wait for a signal saying the call failed, was cancelled with ctrl-c or completed. exitCts.Token.WaitHandle.WaitOne(); Log.LogInformation("Exiting..."); rtpSocket?.Close(); controlSocket?.Close(); if (userAgent != null) { if (userAgent.IsAnswered) { Log.LogInformation($"Hanging up call to {userAgent?.CallDescriptor?.To}."); userAgent.Hangup(); } // Give the final request time to be transmitted. Log.LogInformation("Waiting 1s for call to clean up..."); Task.Delay(1000).Wait(); } SIPSorcery.Net.DNSManager.Stop(); if (sipTransport != null) { Log.LogInformation("Shutting down SIP transport..."); sipTransport.Shutdown(); } }
/// <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) { 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); } }
static void Main() { Console.WriteLine("SIPSorcery Attended Transfer example."); Console.WriteLine("Press 'c' to place a call to the default destination."); Console.WriteLine("Place two simultaneous SIP calls to this program and then press 't'."); Console.WriteLine("Press 'q' or ctrl-c to exit."); // Plumbing code to facilitate a graceful exit. CancellationTokenSource exitCts = new CancellationTokenSource(); // Cancellation token to stop the SIP transport and RTP stream. AddConsoleLogger(); // Set up a default SIP transport. var sipTransport = new SIPTransport(); sipTransport.AddSIPChannel(new SIPUDPChannel(new IPEndPoint(IPAddress.Any, SIP_LISTEN_PORT))); //EnableTraceLogs(sipTransport); // Create two user agents. Each gets configured to answer an incoming call. var userAgent1 = new SIPUserAgent(sipTransport, null); var userAgent2 = new SIPUserAgent(sipTransport, null); userAgent1.OnCallHungup += (dialog) => Log.LogInformation($"UA1: Call hungup by remote party."); userAgent1.ServerCallCancelled += (uas) => Log.LogInformation("UA1: Incoming call cancelled by caller."); userAgent2.OnCallHungup += (dialog) => Log.LogInformation($"UA2: Call hungup by remote party."); userAgent2.ServerCallCancelled += (uas) => Log.LogInformation("UA2: Incoming call cancelled by caller."); userAgent2.OnTransferNotify += (sipFrag) => { if (!string.IsNullOrEmpty(sipFrag)) { Log.LogInformation($"UA2: Transfer status update: {sipFrag.Trim()}."); if (sipFrag?.Contains("SIP/2.0 200") == true) { // The transfer attempt got a successful answer. Can hangup the call. userAgent2.Hangup(); exitCts.Cancel(); } } }; sipTransport.SIPTransportRequestReceived += async(localEndPoint, remoteEndPoint, sipRequest) => { if (sipRequest.Header.From != null && sipRequest.Header.From.FromTag != null && sipRequest.Header.To != null && sipRequest.Header.To.ToTag != null) { // This is an in-dialog request that will be handled directly by a user agent instance. } else if (sipRequest.Method == SIPMethodsEnum.INVITE) { if (!userAgent1.IsCallActive || !userAgent2.IsCallActive) { SIPUserAgent activeAgent = (!userAgent1.IsCallActive) ? userAgent1 : userAgent2; string agentDesc = (!userAgent1.IsCallActive) ? "UA1" : "UA2"; Log.LogInformation($"{agentDesc}: Incoming call request from {remoteEndPoint}: {sipRequest.StatusLine}."); var incomingCall = activeAgent.AcceptCall(sipRequest); var rtpAVSession = new RtpAVSession(new AudioOptions { AudioSource = AudioSourcesEnum.CaptureDevice }, null); await activeAgent.Answer(incomingCall, rtpAVSession); Log.LogInformation($"{agentDesc}: Answered incoming call from {sipRequest.Header.From.FriendlyDescription()} at {remoteEndPoint}."); } else { // If both user agents are already on a call return a busy response. Log.LogWarning($"Busy response returned for incoming call request from {remoteEndPoint}: {sipRequest.StatusLine}."); UASInviteTransaction uasTransaction = new UASInviteTransaction(sipTransport, sipRequest, null); SIPResponse busyResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.BusyHere, null); uasTransaction.SendFinalResponse(busyResponse); } } else { Log.LogDebug($"SIP {sipRequest.Method} request received but no processing has been set up for it, rejecting."); SIPResponse notAllowedResponse = SIPResponse.GetResponse(sipRequest, SIPResponseStatusCodesEnum.MethodNotAllowed, null); await sipTransport.SendResponseAsync(notAllowedResponse); } }; // At this point the call has been initiated and everything will be handled in an event handler. Task.Run(async() => { try { while (!exitCts.Token.WaitHandle.WaitOne(0)) { var keyProps = Console.ReadKey(); if (keyProps.KeyChar == 'c') { // Place an outgoing call using the first free user agent. SIPUserAgent freeAgent = (!userAgent1.IsCallActive) ? userAgent1 : (!userAgent2.IsCallActive) ? userAgent2 : null; if (freeAgent != null) { var rtpAVSession = new RtpAVSession(new AudioOptions { AudioSource = AudioSourcesEnum.CaptureDevice }, null); bool callResult = await freeAgent.Call(DEFAULT_DESTINATION_SIP_URI, null, null, rtpAVSession); Log.LogInformation($"Call attempt {((callResult) ? "successfull" : "failed")}."); } else { Log.LogWarning("Both user agents are already on calls."); } } if (keyProps.KeyChar == 't') { // Initiate the attended transfer. if (userAgent1.IsCallActive && userAgent2.IsCallActive) { bool result = await userAgent2.AttendedTransfer(userAgent1.Dialogue, TimeSpan.FromSeconds(TRANSFER_TIMEOUT_SECONDS), exitCts.Token); if (!result) { Log.LogWarning($"Attended transfer failed."); } } else { Log.LogWarning("There need to be two active calls before the attended transfer can occur."); } } else if (keyProps.KeyChar == 'q') { // Quit application. exitCts.Cancel(); } } } catch (Exception excp) { SIPSorcery.Sys.Log.Logger.LogError($"Exception Key Press listener. {excp.Message}."); } }); // Ctrl-c will gracefully exit the call at any point. Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e) { e.Cancel = true; exitCts.Cancel(); }; // Wait for a signal saying the call failed, was cancelled with ctrl-c or completed. exitCts.Token.WaitHandle.WaitOne(); #region Cleanup. Log.LogInformation("Exiting..."); userAgent1?.Hangup(); userAgent2?.Hangup(); // Give any BYE or CANCEL requests time to be transmitted. Log.LogInformation("Waiting 1s for calls to be cleaned up..."); Task.Delay(1000).Wait(); if (sipTransport != null) { Log.LogInformation("Shutting down SIP transport..."); sipTransport.Shutdown(); } #endregion }
void m_serverTransaction_NonInviteTransactionFinalResponseReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPResponse sipResponse) { if (sipResponse.Status == SIPResponseStatusCodesEnum.Accepted) { FireReferAccepted(); } else if (sipResponse.Status == SIPResponseStatusCodesEnum.Decline) { FireReferDenied(); } else if (sipResponse.Status == SIPResponseStatusCodesEnum.MethodNotAllowed) { FireReferDenied(); } }