Beispiel #1
0
        private Task <SocketError> ByeServerFinalResponseReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPResponse sipResponse)
        {
            try
            {
                logger.LogDebug("Response " + sipResponse.StatusCode + " " + sipResponse.ReasonPhrase + " for " + sipTransaction.TransactionRequest.URI.ToString() + ".");

                SIPNonInviteTransaction byeTransaction = sipTransaction as SIPNonInviteTransaction;

                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 authByeTransaction = new SIPNonInviteTransaction(m_sipTransport, authByeRequest, null);
                    authByeTransaction.SendRequest();
                }

                return(Task.FromResult(SocketError.Success));
            }
            catch (Exception excp)
            {
                logger.LogError("Exception ByServerFinalResponseReceived. " + excp.Message);
                return(Task.FromResult(SocketError.Fault));
            }
        }
        private Task <SocketError> ByeServerFinalResponseReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPResponse sipResponse)
        {
            try
            {
                logger.LogDebug("Response " + sipResponse.StatusCode + " " + sipResponse.ReasonPhrase + " for " + sipTransaction.TransactionRequest.URI.ToString() + ".");

                SIPNonInviteTransaction transaction = sipTransaction as SIPNonInviteTransaction;
                transaction.NonInviteTransactionFinalResponseReceived -= ByeServerFinalResponseReceived;

                if (sipResponse.Status == SIPResponseStatusCodesEnum.ProxyAuthenticationRequired || sipResponse.Status == SIPResponseStatusCodesEnum.Unauthorised)
                {
                    string username    = (m_sipCallDescriptor.AuthUsername == null || m_sipCallDescriptor.AuthUsername.Trim().Length <= 0 ? m_sipCallDescriptor.Username : m_sipCallDescriptor.AuthUsername);
                    var    authRequest = transaction.TransactionRequest.DuplicateAndAuthenticate(sipResponse.Header.AuthenticationHeaders,
                                                                                                 username, m_sipCallDescriptor.Password);

                    SIPNonInviteTransaction authByeTransaction = new SIPNonInviteTransaction(m_sipTransport, authRequest, m_outboundProxy);
                    authByeTransaction.NonInviteTransactionFailed += (tx, reason) => logger.LogWarning($"Authenticated Bye request for {m_sipCallDescriptor.Uri} failed with {reason}.");
                    authByeTransaction.SendRequest();
                }

                return(Task.FromResult(SocketError.Success));
            }
            catch (Exception excp)
            {
                logger.LogError($"Exception ByServerFinalResponseReceived. {excp.Message}");
                return(Task.FromResult(SocketError.Fault));
            }
        }
Beispiel #3
0
        /// <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();
                }
            }
        }
        /// <summary>
        /// Cancels an in progress call. This method should be called prior to the remote user agent server answering the call.
        /// </summary>
        public void Cancel()
        {
            try
            {
                m_callCancelled = true;

                // Cancel server call.
                if (m_serverTransaction == null)
                {
                    logger.LogDebug("Cancelling forwarded call leg " + m_sipCallDescriptor.Uri + ", server transaction has not been created yet no CANCEL request required.");
                }
                else if (m_cancelTransaction != null)
                {
                    if (m_cancelTransaction.TransactionState != SIPTransactionStatesEnum.Completed)
                    {
                        logger.LogDebug("Call " + m_serverTransaction.TransactionRequest.URI.ToString() + " has already been cancelled once, trying again.");
                        m_cancelTransaction.SendRequest();
                    }
                    else
                    {
                        logger.LogDebug("Call " + m_serverTransaction.TransactionRequest.URI.ToString() + " has already responded to CANCEL, probably overlap in messages not re-sending.");
                    }
                }
                else //if (m_serverTransaction.TransactionState == SIPTransactionStatesEnum.Proceeding || m_serverTransaction.TransactionState == SIPTransactionStatesEnum.Trying)
                {
                    logger.LogDebug("Cancelling forwarded call leg, sending CANCEL to " + m_serverTransaction.TransactionRequest.URI.ToString() + ".");

                    // No response has been received from the server so no CANCEL request necessary, stop any retransmits of the INVITE.
                    m_serverTransaction.CancelCall();

                    SIPRequest cancelRequest = GetCancelRequest(m_serverTransaction.TransactionRequest);

                    // If auth header is included inside INVITE request, we re-include them inside CANCEL request
                    if (m_serverTransaction.TransactionRequest.Header.HasAuthenticationHeader)
                    {
                        string username = (m_sipCallDescriptor.AuthUsername == null || m_sipCallDescriptor.AuthUsername.Trim().Length <= 0 ? m_sipCallDescriptor.Username : m_sipCallDescriptor.AuthUsername);
                        SIPAuthorisationDigest authDigest = m_serverTransaction.TransactionRequest.Header.AuthenticationHeaders.First().SIPDigest;
                        authDigest.SetCredentials(username, m_sipCallDescriptor.Password, m_sipCallDescriptor.Uri, SIPMethodsEnum.CANCEL.ToString());

                        var authHeader = new SIPAuthenticationHeader(authDigest);
                        authHeader.SIPDigest.IncrementNonceCount();
                        authHeader.SIPDigest.Response = authDigest.GetDigest();

                        cancelRequest.Header.AuthenticationHeaders.Clear();
                        cancelRequest.Header.AuthenticationHeaders.Add(authHeader);
                    }

                    m_cancelTransaction = new SIPNonInviteTransaction(m_sipTransport, cancelRequest, m_outboundProxy);
                    m_cancelTransaction.SendRequest();
                }

                CallFailed?.Invoke(this, "Call cancelled by user.", null);
            }
            catch (Exception excp)
            {
                logger.LogError("Exception CancelServerCall. " + excp.Message);
            }
        }
        private void SendInitialRegister()
        {
            try
            {
                if (m_attempts >= m_maxRegisterAttempts)
                {
                    logger.LogWarning($"Registration to {m_sipAccountAOR} reached the maximum number of allowed attempts without a failure condition.");
                    m_isRegistered = false;
                    RegistrationTemporaryFailure?.Invoke(m_sipAccountAOR, "Registration reached the maximum number of allowed attempts.");
                    m_waitForRegistrationMRE.Set();
                }
                else
                {
                    m_attempts++;

                    SIPEndPoint registrarSIPEndPoint = m_outboundProxy;
                    if (registrarSIPEndPoint == null)
                    {
                        SIPURI uri          = SIPURI.ParseSIPURIRelaxed(m_registrarHost);
                        var    lookupResult = m_sipTransport.ResolveSIPUriAsync(uri).Result;
                        if (lookupResult == null || lookupResult == SIPEndPoint.Empty)
                        {
                            logger.LogWarning("Could not resolve " + m_registrarHost + " when sending initial registration request.");
                        }
                        else
                        {
                            registrarSIPEndPoint = lookupResult;
                        }
                    }

                    if (registrarSIPEndPoint == null)
                    {
                        logger.LogWarning($"SIPRegistrationAgent could not resolve {m_registrarHost}.");
                        RegistrationFailed?.Invoke(m_sipAccountAOR, $"Could not resolve {m_registrarHost}.");
                    }
                    else
                    {
                        logger.LogDebug($"Initiating registration to {m_registrarHost} at {registrarSIPEndPoint} for {m_sipAccountAOR}.");
                        SIPRequest regRequest = GetRegistrationRequest();

                        SIPNonInviteTransaction regTransaction = new SIPNonInviteTransaction(m_sipTransport, regRequest, registrarSIPEndPoint);
                        regTransaction.NonInviteTransactionFinalResponseReceived += (lep, rep, tn, rsp) => { ServerResponseReceived(lep, rep, tn, rsp); return(Task.FromResult(SocketError.Success)); };
                        regTransaction.NonInviteTransactionFailed += RegistrationTransactionFailed;

                        regTransaction.SendRequest();
                    }
                }
            }
            catch (Exception excp)
            {
                logger.LogError("Exception SendInitialRegister to " + m_registrarHost + ". " + excp.Message);
                RegistrationFailed?.Invoke(m_sipAccountAOR, "Exception SendInitialRegister to " + m_registrarHost + ". " + excp.Message);
            }
        }
Beispiel #6
0
        /// <summary>
        /// Processes a transfer once the REFER request has been determined.
        /// </summary>
        /// <param name="referRequest">The REFER request for the transfer.</param>
        /// <param name="timeout">Timeout for the transfer request to get accepted.</param>
        /// <param name="ct">Cancellation token. Can be set to cancel the transfer prior to it being
        /// accepted or timing out.</param>
        /// <returns>True if the transfer was accepted by the Transferee or false if not.</returns>
        private async Task <bool> Transfer(SIPRequest referRequest, TimeSpan timeout, CancellationToken ct)
        {
            if (Dialogue == null)
            {
                logger.LogWarning("Transfer was called on the SIPUserAgent when no dialogue was available.");
                return(false);
            }
            else
            {
                TaskCompletionSource <bool> transferAccepted = new TaskCompletionSource <bool>();

                SIPNonInviteTransaction referTx = new SIPNonInviteTransaction(m_transport, referRequest, null);

                SIPTransactionResponseReceivedDelegate referTxStatusHandler = (localSIPEndPoint, remoteEndPoint, sipTransaction, sipResponse) =>
                {
                    // This handler has to go on a separate thread or the SIPTransport "ProcessInMessage" thread will be blocked.
                    Task.Run(() =>
                    {
                        if (sipResponse.Header.CSeqMethod == SIPMethodsEnum.REFER && sipResponse.Status == SIPResponseStatusCodesEnum.Accepted)
                        {
                            logger.LogInformation("Call transfer was accepted by remote server.");
                            transferAccepted.SetResult(true);
                        }
                        else
                        {
                            transferAccepted.SetResult(false);
                        }
                    }, ct);

                    return(Task.FromResult(SocketError.Success));
                };

                referTx.NonInviteTransactionFinalResponseReceived += referTxStatusHandler;
                referTx.SendRequest();

                await Task.WhenAny(transferAccepted.Task, Task.Delay((int)timeout.TotalMilliseconds, ct)).ConfigureAwait(false);

                referTx.NonInviteTransactionFinalResponseReceived -= referTxStatusHandler;

                if (transferAccepted.Task.IsCompleted)
                {
                    return(transferAccepted.Task.Result);
                }
                else
                {
                    logger.LogWarning($"Call transfer request timed out after {timeout.TotalMilliseconds}ms.");
                    return(false);
                }
            }
        }
Beispiel #7
0
        private Task <SocketError> ServerResponseReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPResponse sipResponse)
        {
            try
            {
                string reasonPhrase = (sipResponse.ReasonPhrase.IsNullOrBlank()) ? sipResponse.Status.ToString() : sipResponse.ReasonPhrase;
                logger.LogDebug("Server response " + sipResponse.StatusCode + " " + reasonPhrase + " received for " + sipTransaction.TransactionRequest.Method + " to " + m_callDescriptor.Uri + ".");

                if (sipResponse.Status == SIPResponseStatusCodesEnum.ProxyAuthenticationRequired || sipResponse.Status == SIPResponseStatusCodesEnum.Unauthorised)
                {
                    if (sipResponse.Header.HasAuthenticationHeader)
                    {
                        if ((m_callDescriptor.Username != null || m_callDescriptor.AuthUsername != null) && m_callDescriptor.Password != null)
                        {
                            string     username             = (m_callDescriptor.AuthUsername != null) ? m_callDescriptor.AuthUsername : m_callDescriptor.Username;
                            SIPRequest authenticatedRequest = sipTransaction.TransactionRequest.DuplicateAndAuthenticate(
                                sipResponse.Header.AuthenticationHeaders, username, m_callDescriptor.Password);

                            SIPNonInviteTransaction authTransaction = new SIPNonInviteTransaction(m_sipTransport, authenticatedRequest, m_outboundProxy);
                            authTransaction.NonInviteTransactionFinalResponseReceived += AuthResponseReceived;
                            authTransaction.NonInviteTransactionFailed += TransactionFailed;
                            authTransaction.SendRequest();
                        }
                        else
                        {
                            logger.LogDebug("Send request received an authentication required response but no credentials were available.");
                            ResponseReceived?.Invoke(sipResponse);
                        }
                    }
                    else
                    {
                        logger.LogDebug("Send request failed with " + sipResponse.StatusCode + " but no authentication header was supplied for " + sipTransaction.TransactionRequest.Method + " to " + m_callDescriptor.Uri + ".");
                        ResponseReceived?.Invoke(sipResponse);
                    }
                }
                else
                {
                    ResponseReceived?.Invoke(sipResponse);
                }
            }
            catch (Exception excp)
            {
                logger.LogError("Exception SIPNonInviteClientUserAgent ServerResponseReceived (" + remoteEndPoint + "). " + excp.Message);
            }

            return(Task.FromResult(SocketError.Success));
        }
        public void SendRequest(SIPMethodsEnum method)
        {
            try
            {
                SIPRequest req = GetRequest(method);
                SIPNonInviteTransaction tran = new SIPNonInviteTransaction(m_sipTransport, req, m_outboundProxy);

                ManualResetEvent waitForResponse = new ManualResetEvent(false);
                tran.NonInviteTransactionFailed += TransactionFailed;
                tran.NonInviteTransactionFinalResponseReceived += ServerResponseReceived;
                tran.SendRequest();
            }
            catch (Exception excp)
            {
                logger.LogError("Exception SIPNonInviteClientUserAgent SendRequest to " + m_callDescriptor.Uri + ". " + excp.Message);
                throw;
            }
        }
Beispiel #9
0
        /// <summary>
        /// Used to hangup the call or indicate that the client hungup.
        /// </summary>
        /// <param name="clientHungup">True if the BYE request was received from the client. False if the hangup
        /// needs to originate from this agent.</param>
        public void Hangup(bool clientHungup)
        {
            if (!m_isHungup)
            {
                m_isHungup = true;

                if (SIPDialogue == null)
                {
                    return;
                }

                // Only need to send a BYE request if the client didn't already do so.
                if (clientHungup == false)
                {
                    try
                    {
                        // Cases found where the Contact in the INVITE was to a different protocol than the original request.
                        var inviteContact = m_uasTransaction.TransactionRequest.Header.Contact.FirstOrDefault();
                        if (inviteContact == null)
                        {
                            logger.LogWarning(
                                "The Contact header on the INVITE request was missing, BYE request cannot be generated.");
                        }
                        else
                        {
                            //SIPRequest byeRequest = GetByeRequest();
                            var byeRequest = SIPDialogue.GetInDialogRequest(SIPMethodsEnum.BYE);
                            SIPNonInviteTransaction byeTransaction =
                                new SIPNonInviteTransaction(m_sipTransport, byeRequest, m_outboundProxy);
                            byeTransaction.NonInviteTransactionFinalResponseReceived += ByeServerFinalResponseReceived;
                            byeTransaction.SendRequest();
                        }
                    }
                    catch (Exception excp)
                    {
                        logger.LogError("Exception SIPServerUserAgent Hangup. " + excp.Message);
                        throw;
                    }
                }
            }
        }
        public void Hangup()
        {
            if (m_sipDialogue == null)
            {
                return;
            }

            try
            {
                //SIPRequest byeRequest = GetByeRequest(m_serverTransaction.TransactionFinalResponse, m_sipDialogue.RemoteTarget);
                SIPRequest byeRequest = m_sipDialogue.GetInDialogRequest(SIPMethodsEnum.BYE);
                byeRequest.SetSendFromHints(m_serverTransaction.TransactionRequest.LocalSIPEndPoint);
                m_byeTransaction = new SIPNonInviteTransaction(m_sipTransport, byeRequest, m_outboundProxy);
                m_byeTransaction.NonInviteTransactionFinalResponseReceived += ByeServerFinalResponseReceived;
                m_byeTransaction.NonInviteTransactionFailed += (tx, reason) => logger.LogWarning($"Bye request for {m_sipCallDescriptor.Uri} failed with {reason}.");
                m_byeTransaction.SendRequest();
            }
            catch (Exception excp)
            {
                logger.LogError("Exception SIPClientUserAgent Hangup. " + excp.Message);
            }
        }
        private Task <SocketError> ByeServerFinalResponseReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPResponse sipResponse)
        {
            try
            {
                logger.LogDebug("Response " + sipResponse.StatusCode + " " + sipResponse.ReasonPhrase + " for " + sipTransaction.TransactionRequest.URI.ToString() + ".");

                SIPNonInviteTransaction byeTransaction = sipTransaction as SIPNonInviteTransaction;

                if ((sipResponse.Status == SIPResponseStatusCodesEnum.ProxyAuthenticationRequired || sipResponse.Status == SIPResponseStatusCodesEnum.Unauthorised) && SIPAccount != null)
                {
                    var authRequest = sipTransaction.TransactionRequest.DuplicateAndAuthenticate(sipResponse.Header.AuthenticationHeaders,
                                                                                                 SIPAccount.SIPUsername, SIPAccount.SIPPassword);
                    SIPNonInviteTransaction authByeTransaction = new SIPNonInviteTransaction(m_sipTransport, authRequest, null);
                    authByeTransaction.SendRequest();
                }

                return(Task.FromResult(SocketError.Success));
            }
            catch (Exception excp)
            {
                logger.LogError("Exception ByServerFinalResponseReceived. " + excp.Message);
                return(Task.FromResult(SocketError.Fault));
            }
        }
Beispiel #12
0
        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?.Invoke(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?.Invoke(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?.Invoke(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?.Invoke(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?.Invoke(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.NonInviteTransactionFailed += SubscribeTransactionFailed;

                            //m_sipTransport.SendTransaction(subscribeTransaction);
                            subscribeTransaction.SendRequest();
                        }
                    }
                    else
                    {
                        SubscriptionFailed?.Invoke(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?.Invoke(m_resourceURI);
                    m_waitForSubscribeResponse.Set();
                }
                else
                {
                    SubscriptionFailed?.Invoke(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?.Invoke(m_resourceURI, SIPResponseStatusCodesEnum.InternalServerError, "Exception processing subscribe response. " + excp.Message);
                m_waitForSubscribeResponse.Set();

                return(Task.FromResult(SocketError.Fault));
            }
        }
Beispiel #13
0
        /// <summary>
        /// Initiates a SUBSCRIBE request to a notification server.
        /// </summary>
        /// <param name="subscribeURI">The SIP user that dialog notifications are being subscribed to.</param>
        public void Subscribe(SIPURI subscribeURI, int expiry, SIPEventPackagesEnum sipEventPackage, string subscribeCallID, SIPURI contactURI)
        {
            try
            {
                if (m_attempts >= MAX_SUBSCRIBE_ATTEMPTS)
                {
                    logger.LogWarning($"Subscription to {subscribeURI} reached the maximum number of allowed attempts without a failure condition.");
                    m_subscribed = false;
                    SubscriptionFailed?.Invoke(subscribeURI, SIPResponseStatusCodesEnum.InternalServerError, "Subscription reached the maximum number of allowed attempts.");
                    m_waitForSubscribeResponse.Set();
                }
                else
                {
                    m_attempts++;
                    m_localCSeq++;

                    SIPRequest subscribeRequest = SIPRequest.GetRequest(
                        SIPMethodsEnum.SUBSCRIBE,
                        m_resourceURI,
                        new SIPToHeader(null, subscribeURI, m_subscriptionToTag),
                        new SIPFromHeader(null, new SIPURI(m_authUsername, m_authDomain, null, m_resourceURI.Scheme, SIPProtocolsEnum.udp), m_subscriptionFromTag));


                    if (contactURI != null)
                    {
                        subscribeRequest.Header.Contact = new List <SIPContactHeader>()
                        {
                            new SIPContactHeader(null, contactURI)
                        };
                    }
                    else
                    {
                        subscribeRequest.Header.Contact = new List <SIPContactHeader>()
                        {
                            SIPContactHeader.GetDefaultSIPContactHeader(subscribeRequest.URI.Scheme)
                        };
                    }

                    subscribeRequest.Header.CSeq    = m_localCSeq;
                    subscribeRequest.Header.Expires = expiry;
                    subscribeRequest.Header.Event   = SIPEventPackageType.GetEventHeader(sipEventPackage);
                    subscribeRequest.Header.CallId  = subscribeCallID;

                    if (!m_filter.IsNullOrBlank())
                    {
                        subscribeRequest.Body = m_filter;
                        subscribeRequest.Header.ContentLength = m_filter.Length;
                        subscribeRequest.Header.ContentType   = m_filterTextType;
                    }

                    SIPNonInviteTransaction subscribeTransaction = new SIPNonInviteTransaction(m_sipTransport, subscribeRequest, m_outboundProxy);
                    subscribeTransaction.NonInviteTransactionFinalResponseReceived += SubscribeTransactionFinalResponseReceived;
                    subscribeTransaction.NonInviteTransactionFailed += SubscribeTransactionFailed;

                    LastSubscribeAttempt = DateTime.Now;

                    subscribeTransaction.SendRequest();
                }
            }
            catch (Exception excp)
            {
                logger.LogError("Exception SIPNotifierClient Subscribe. " + excp.Message);
                SubscriptionFailed?.Invoke(m_resourceURI, SIPResponseStatusCodesEnum.InternalServerError, "Exception Subscribing. " + excp.Message);
                m_waitForSubscribeResponse.Set();
            }
        }
        private Task <SocketError> ServerFinalResponseReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPResponse sipResponse)
        {
            try
            {
                logger.LogDebug("Response " + sipResponse.StatusCode + " " + sipResponse.ReasonPhrase + " for " + m_serverTransaction.TransactionRequest.URI.ToString() + ".");

                m_serverTransaction.UACInviteTransactionInformationResponseReceived -= ServerInformationResponseReceived;
                m_serverTransaction.UACInviteTransactionFinalResponseReceived       -= ServerFinalResponseReceived;

                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)
                    {
                        logger.LogDebug("A cancelled call to " + m_sipCallDescriptor.Uri + " has been answered AND has already been hungup, no further action being taken.");
                    }
                    else
                    {
                        m_hungupOnCancel = true;

                        logger.LogDebug("A cancelled call to " + m_sipCallDescriptor.Uri + " has been answered, hanging up.");

                        if (sipResponse.Header.Contact != null && sipResponse.Header.Contact.Count > 0)
                        {
                            SIPURI     byeURI     = sipResponse.Header.Contact[0].ContactURI;
                            SIPRequest byeRequest = GetByeRequest(sipResponse, byeURI);
                            SIPNonInviteTransaction byeTransaction = new SIPNonInviteTransaction(m_sipTransport, byeRequest, m_outboundProxy);
                            byeTransaction.SendRequest();
                        }
                        else
                        {
                            logger.LogDebug("No contact header provided on response for cancelled call to " + m_sipCallDescriptor.Uri + " no further action.");
                        }
                    }

                    #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.
                            logger.LogDebug("Forward leg failed, authentication was requested but no credentials were available.");
                            CallFailed?.Invoke(this, "Authentication requested when no credentials available", sipResponse);
                        }
                        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;
                            var    authRequest = m_serverTransaction.TransactionRequest.DuplicateAndAuthenticate(sipResponse.Header.AuthenticationHeaders,
                                                                                                                 username, m_sipCallDescriptor.Password);

                            // Create a new UAC transaction to establish the authenticated server call.
                            m_serverTransaction = new UACInviteTransaction(m_sipTransport, authRequest, m_outboundProxy);
                            if (m_serverTransaction.CDR != null)
                            {
                                m_serverTransaction.CDR.Updated();
                            }
                            m_serverTransaction.UACInviteTransactionInformationResponseReceived += ServerInformationResponseReceived;
                            m_serverTransaction.UACInviteTransactionFinalResponseReceived       += ServerFinalResponseReceived;
                            m_serverTransaction.UACInviteTransactionFailed += ServerTransactionFailed;

                            m_serverTransaction.SendInviteRequest();
                        }
                        else
                        {
                            CallFailed?.Invoke(this, "Authentication with provided credentials failed", sipResponse);
                        }
                    }

                    #endregion
                }
                else
                {
                    if (sipResponse.StatusCode >= 200 && sipResponse.StatusCode <= 299)
                    {
                        m_sipDialogue = new SIPDialogue(m_serverTransaction);
                        m_sipDialogue.CallDurationLimit = m_sipCallDescriptor.CallDurationLimit;
                    }

                    CallAnswered?.Invoke(this, sipResponse);
                }

                return(Task.FromResult(SocketError.Success));
            }
            catch (Exception excp)
            {
                logger.LogDebug("Exception ServerFinalResponseReceived. " + excp);
                return(Task.FromResult(SocketError.Fault));
            }
        }
        /// <summary>
        /// The event handler for responses to the initial register request.
        /// </summary>
        private void ServerResponseReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPResponse sipResponse)
        {
            try
            {
                logger.LogDebug($"Server response {sipResponse.Status} received for {m_sipAccountAOR}.");

                if (sipResponse.Status == SIPResponseStatusCodesEnum.ProxyAuthenticationRequired || sipResponse.Status == SIPResponseStatusCodesEnum.Unauthorised)
                {
                    if (sipResponse.Header.HasAuthenticationHeader)
                    {
                        if (m_attempts >= m_maxRegisterAttempts)
                        {
                            logger.LogDebug("Registration to " + m_sipAccountAOR.ToString() + " reached the maximum number of allowed attempts without a failure condition.");
                            m_isRegistered = false;
                            RegistrationTemporaryFailure?.Invoke(m_sipAccountAOR, "Registration reached the maximum number of allowed attempts.");
                            m_waitForRegistrationMRE.Set();
                        }
                        else
                        {
                            m_attempts++;

                            string username             = (m_authUsername != null) ? m_authUsername : m_sipAccountAOR.User;
                            var    authenticatedRequest = sipTransaction.TransactionRequest.DuplicateAndAuthenticate(
                                sipResponse.Header.AuthenticationHeaders, username, m_password);

                            SIPEndPoint registrarSIPEndPoint = m_outboundProxy;
                            if (registrarSIPEndPoint == null)
                            {
                                SIPURI uri          = SIPURI.ParseSIPURIRelaxed(m_registrarHost);
                                var    lookupResult = m_sipTransport.ResolveSIPUriAsync(uri).Result;
                                if (lookupResult == null)
                                {
                                    logger.LogWarning("Could not resolve " + m_registrarHost + ".");
                                }
                                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) =>
                                {
                                    AuthResponseReceived(lep, rep, tn, rsp);
                                    return(Task.FromResult(SocketError.Success));
                                };
                                regAuthTransaction.NonInviteTransactionFailed += RegistrationTransactionFailed;
                                regAuthTransaction.SendRequest();
                            }
                        }
                    }
                    else
                    {
                        logger.LogWarning($"Registration failed with {sipResponse.Status} but no authentication header was supplied for {m_sipAccountAOR}.");
                        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.
                        m_exit = m_exitOnUnequivocalFailure;

                        logger.LogWarning($"Registration unequivocal failure with {sipResponse.Status} for {m_sipAccountAOR}{(m_exit ? ", no further registration attempts will be made" : "")}.");
                        string reasonPhrase = (sipResponse.ReasonPhrase.IsNullOrBlank()) ? sipResponse.Status.ToString() : sipResponse.ReasonPhrase;
                        RegistrationFailed?.Invoke(m_sipAccountAOR, "Registration failed with " + (int)sipResponse.Status + " " + reasonPhrase + ".");

                        m_waitForRegistrationMRE.Set();
                    }
                    else if (sipResponse.Status == SIPResponseStatusCodesEnum.IntervalTooBrief && m_expiry != 0)
                    {
                        m_expiry = GetUpdatedExpiryForIntervalTooBrief(sipResponse);
                        logger.LogWarning("Registration for " + m_sipAccountAOR.ToString() + " had a too short expiry, updated to +" + m_expiry + " and trying again.");
                        SendInitialRegister();
                    }
                    else
                    {
                        logger.LogWarning($"Registration failed with {sipResponse.Status} for {m_sipAccountAOR}.");
                        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}");
            }
        }