/// <summary> /// Sends in initial notification request for a new subscription where it makes sense to do so. /// </summary> /// <param name="subscribeRequest">The client request that resulted in the subscription creation.</param> /// <param name="sipAccount">The authenticated SIP account that created the subscription.</param> private void SendInitialNotification(SIPRequest subscribeRequest, ISIPAccount sipAccount) { if (SIPEventPackageType.IsValid(subscribeRequest.Header.Event)) { var eventPackage = SIPEventPackageType.Parse(subscribeRequest.Header.Event); if (eventPackage == SIPEventPackagesEnum.MessageSummary) { // Send a dummy message waiting indicator message so that a client can verify a notification request can // be received. var dstUri = subscribeRequest.Header.Contact[0].ContactURI; var accountURI = new SIPURI(sipAccount.SIPUsername, sipAccount.SIPDomain, null, dstUri.Scheme, dstUri.Protocol); var notifyReq = SIPRequest.GetRequest(SIPMethodsEnum.NOTIFY, subscribeRequest.Header.Contact[0].ContactURI, new SIPToHeader(null, accountURI.CopyOf(), CallProperties.CreateNewTag()), new SIPFromHeader(null, accountURI.CopyOf(), CallProperties.CreateNewTag())); notifyReq.Header.CallId = subscribeRequest.Header.CallId; notifyReq.Header.CSeq = subscribeRequest.Header.CSeq++; notifyReq.Header.Server = m_serverAgent; notifyReq.Header.Event = SIPEventPackageType.MESSAGE_SUMMARY_EVENT_VALUE; notifyReq.Header.SubscriptionState = "active"; notifyReq.Header.SetDateHeader(); notifyReq.Header.ContentType = SIPMIMETypes.MWI_CONTENT_TYPE; notifyReq.Body = "Messages-Waiting: no"; // A little trick here is using the remote SIP end point as the destination rather than the Contact URI. // Ideally some extra logic to check for IPv4 NAT should be applied. But since this server is known to // be operating in the cloud and only send NOTIFY requests to Internet clients it should be a reasonable // option. SIPNonInviteTransaction notifyTx = new SIPNonInviteTransaction(m_sipTransport, notifyReq, subscribeRequest.RemoteSIPEndPoint); notifyTx.SendRequest(); } } }
public SIPAccountBinding(ISIPAccount sipAccount, SIPURI contact, SIPEndPoint remote, SIPEndPoint local, int expiry) { SIPAccount = sipAccount; RegisteredContact = contact; RemoteEndPoint = remote; LocalEndPoint = local; Expiry = expiry; }
public ManualResetEvent DelayMRE; // If the call needs to be delayed DelaySeconds this MRE will be used. /// <summary> /// This constructor is for calls to a SIP account that the application recognises as belonging to it. /// </summary> /// <param name="toSIPAccount">The destination SP account for teh call.</param> /// <param name="uri">The uri can be different to the to SIP account if a dotted notation is used. For /// example [email protected].</param> /// <param name="fromHeader"></param> /// <param name="contentType"></param> /// <param name="content"></param> public SIPCallDescriptor(ISIPAccount toSIPAccount, string uri, string fromHeader, string contentType, string content) { ToSIPAccount = toSIPAccount; Uri = uri ?? toSIPAccount.SIPUsername + "@" + toSIPAccount.SIPDomain; From = fromHeader; ContentType = contentType; Content = content; }
public SIPB2BUserAgent( SIPTransport sipTransport, SIPEndPoint outboundProxy, UASInviteTransaction uasTransaction, ISIPAccount sipAccount) : base(sipTransport, outboundProxy, uasTransaction, sipAccount) { IsB2B = true; base.CallCancelled += SIPServerUserAgent_CallCancelled; }
public SIPServerUserAgent( SIPTransport sipTransport, SIPEndPoint outboundProxy, UASInviteTransaction uasTransaction, ISIPAccount sipAccount) { m_sipTransport = sipTransport; m_outboundProxy = outboundProxy; m_uasTransaction = uasTransaction; m_sipAccount = sipAccount; m_uasTransaction.UASInviteTransactionFailed += ClientTransactionFailed; m_uasTransaction.UASInviteTransactionCancelled += UASTransactionCancelled; }
public SIPServerUserAgent( SIPTransport sipTransport, SIPEndPoint outboundProxy, UASInviteTransaction uasTransaction, ISIPAccount sipAccount) { m_sipTransport = sipTransport; m_outboundProxy = outboundProxy; m_uasTransaction = uasTransaction; m_sipAccount = sipAccount; m_uasTransaction.UASInviteTransactionTimedOut += ClientTimedOut; m_uasTransaction.UASInviteTransactionCancelled += UASTransactionCancelled; m_uasTransaction.TransactionRemoved += new SIPTransactionRemovedDelegate(UASTransaction_TransactionRemoved); }
private async Task Forward(UASInviteTransaction uasTx, ISIPAccount callerSIPAccount) { var invReq = uasTx.TransactionRequest; //uasTx.TransactionStateChanged += (tx) => Logger.LogDebug($"B2B uas tx state changed to {tx.TransactionState}."); //uasTx.TransactionTraceMessage += (tx, msg) => Logger.LogDebug($"B2B uas tx trace message. {msg}"); Logger.LogDebug($"B2B commencing forward for caller {invReq.Header.From.FromURI} to {invReq.URI}."); SIPB2BUserAgent b2bua = new SIPB2BUserAgent(_sipTransport, null, uasTx, callerSIPAccount); bool isAuthenticated = false; if (callerSIPAccount != null) { isAuthenticated = b2bua.AuthenticateCall(); } if (callerSIPAccount == null || isAuthenticated == true) { b2bua.CallAnswered += (uac, resp) => ForwardCallAnswered(uac, b2bua); var dst = await _sipdialPlan.Lookup(uasTx, null); if (dst == null) { Logger.LogInformation($"B2BUA lookup did not return a destination. Rejecting UAS call."); var notFoundResp = SIPResponse.GetResponse(uasTx.TransactionRequest, SIPResponseStatusCodesEnum.NotFound, null); uasTx.SendFinalResponse(notFoundResp); OnAcceptCallFailure?.Invoke(uasTx.TransactionRequest.RemoteSIPEndPoint, CallFailureEnum.NotFound, invReq); } else { Logger.LogInformation($"B2BUA forwarding call to {dst.Uri}."); b2bua.Call(dst); } } }
#pragma warning restore public SIPNonInviteServerUserAgent( SIPTransport sipTransport, SIPEndPoint outboundProxy, string sipUsername, string sipDomain, SIPCallDirection callDirection, ISIPAccount sipAccount, SIPNonInviteTransaction transaction) { m_sipTransport = sipTransport; m_outboundProxy = outboundProxy; m_sipUsername = sipUsername; m_sipDomain = sipDomain; m_sipCallDirection = callDirection; m_sipAccount = sipAccount; m_transaction = transaction; //m_transaction.TransactionTraceMessage += TransactionTraceMessage; //m_uasTransaction.UASInviteTransactionTimedOut += ClientTimedOut; //m_uasTransaction.UASInviteTransactionCancelled += UASTransactionCancelled; //m_uasTransaction.TransactionRemoved += new SIPTransactionRemovedDelegate(UASTransaction_TransactionRemoved); //m_uasTransaction.TransactionStateChanged += (t) => { logger.Debug("Transaction state change to " + t.TransactionState + ", uri=" + t.TransactionRequestURI.ToString() + "."); }; }
/// <summary> /// This function type is to allow B2B user agents to lookup the forwarding destination /// for an accepted User Agent Server (UAS) call leg. The intent is that functions /// can implement a form of a dialplan and pass to the B2BUA core. /// </summary> /// <param name="uas">A User Agent Server (UAS) transaction that has been accepted /// for forwarding.</param> /// <returns>A call descriptor for the User Agent Client (UAC) call leg that will /// be bridged to the UAS leg.</returns> public async Task <SIPCallDescriptor> Lookup(UASInviteTransaction uasTx, ISIPAccount from) { var dialplan = await LoadDialPlan(); //_logger.LogDebug($"Our dialplan last update {TrimMilliseconds(_dialplanLastUpdated).ToString("o")}, " + // $"database last update {TrimMilliseconds(dialplan.LastUpdate).ToString("o")}."); if (dialplan != null && TrimMilliseconds(DateTime.Parse(dialplan.LastUpdate)) > TrimMilliseconds(_dialplanLastUpdated)) { _logger.LogInformation($"SIP DialPlan Manager loading updated dialplan."); CompileDialPlan(dialplan.DialPlanScript, DateTime.Parse(dialplan.LastUpdate)); } if (_dialPlanScriptRunner != null) { var result = await _dialPlanScriptRunner.Invoke(new SIPDialPlanGlobals { UasTx = uasTx, From = from }); return(result as SIPCallDescriptor); } else { return(null); } }
/// <summary> /// Authenticates a SIP request. /// </summary> public static SIPRequestAuthenticationResult AuthenticateSIPRequest( SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPRequest sipRequest, ISIPAccount sipAccount) { try { if (sipAccount == null) { return(new SIPRequestAuthenticationResult(SIPResponseStatusCodesEnum.Forbidden, null)); } else if (sipAccount.IsDisabled) { logger.LogWarning($"SIP account {sipAccount.SIPUsername}@{sipAccount.SIPDomain} is disabled for {sipRequest.Method}."); return(new SIPRequestAuthenticationResult(SIPResponseStatusCodesEnum.Forbidden, null)); } else { SIPAuthenticationHeader reqAuthHeader = sipRequest.Header.AuthenticationHeader; if (reqAuthHeader == null) { // Check for IP address authentication. //if (!sipAccount.IPAddressACL.IsNullOrBlank()) //{ // SIPEndPoint uaEndPoint = (!sipRequest.Header.ProxyReceivedFrom.IsNullOrBlank()) ? SIPEndPoint.ParseSIPEndPoint(sipRequest.Header.ProxyReceivedFrom) : remoteEndPoint; // if (Regex.Match(uaEndPoint.GetIPEndPoint().ToString(), sipAccount.IPAddressACL).Success) // { // // Successfully authenticated // return new SIPRequestAuthenticationResult(true, true); // } //} SIPAuthenticationHeader authHeader = new SIPAuthenticationHeader(SIPAuthorisationHeadersEnum.WWWAuthenticate, sipAccount.SIPDomain, GetNonce()); return(new SIPRequestAuthenticationResult(SIPResponseStatusCodesEnum.Unauthorised, authHeader)); } else { // Check for IP address authentication. //if (!sipAccount.IPAddressACL.IsNullOrBlank()) //{ // SIPEndPoint uaEndPoint = (!sipRequest.Header.ProxyReceivedFrom.IsNullOrBlank()) ? SIPEndPoint.ParseSIPEndPoint(sipRequest.Header.ProxyReceivedFrom) : remoteEndPoint; // if (Regex.Match(uaEndPoint.GetIPEndPoint().ToString(), sipAccount.IPAddressACL).Success) // { // // Successfully authenticated // return new SIPRequestAuthenticationResult(true, true); // } //} string requestNonce = reqAuthHeader.SIPDigest.Nonce; string uri = reqAuthHeader.SIPDigest.URI; string response = reqAuthHeader.SIPDigest.Response; // Check for stale nonces. if (IsNonceStale(requestNonce)) { logger.LogWarning($"Authentication failed stale nonce for realm={sipAccount.SIPDomain}, username={sipAccount.SIPUsername}, uri={uri}, nonce={requestNonce}, method={sipRequest.Method}."); SIPAuthenticationHeader authHeader = new SIPAuthenticationHeader(SIPAuthorisationHeadersEnum.WWWAuthenticate, sipAccount.SIPDomain, GetNonce()); return(new SIPRequestAuthenticationResult(SIPResponseStatusCodesEnum.Unauthorised, authHeader)); } else { SIPAuthorisationDigest checkAuthReq = reqAuthHeader.SIPDigest; if (sipAccount.SIPPassword != null) { checkAuthReq.SetCredentials(sipAccount.SIPUsername, sipAccount.SIPPassword, uri, sipRequest.Method.ToString()); } else if (sipAccount.HA1Digest != null) { checkAuthReq.SetCredentials(sipAccount.HA1Digest, uri, sipRequest.Method.ToString()); } else { throw new ApplicationException("SIP authentication cannot be attempted as neither a password or HA1 digest are available."); } string digest = checkAuthReq.Digest; if (digest == response) { // Successfully authenticated return(new SIPRequestAuthenticationResult(true, false)); } else { logger.LogWarning("Authentication token check failed for realm=" + sipAccount.SIPDomain + ", username="******", uri=" + uri + ", nonce=" + requestNonce + ", method=" + sipRequest.Method + "."); SIPAuthenticationHeader authHeader = new SIPAuthenticationHeader(SIPAuthorisationHeadersEnum.WWWAuthenticate, sipAccount.SIPDomain, GetNonce()); return(new SIPRequestAuthenticationResult(SIPResponseStatusCodesEnum.Unauthorised, authHeader)); } } } } } catch (Exception excp) { logger.LogError(0, excp, "Exception AuthoriseSIPRequest. " + excp.Message); return(new SIPRequestAuthenticationResult(SIPResponseStatusCodesEnum.InternalServerError, null)); } }