private void ServerTransactionFailed(SIPTransaction sipTransaction, SocketError failureReason)
 {
     if (!m_callCancelled)
     {
         CallFailed?.Invoke(this, failureReason.ToString(), null);
     }
 }
        public void Reject(SIPResponseStatusCodesEnum rejectCode, string rejectReason, string[] customHeaders)
        {
            logger.Debug("SIPB2BUserAgent Reject.");

            UASStateChanged?.Invoke(this, rejectCode, rejectReason);

            SIPResponse uasfailureResponse =
                SIPTransport.GetResponse(m_uasTransaction.TransactionRequest, rejectCode, rejectReason);

            m_uasTransaction.SendFinalResponse(uasfailureResponse);

            SIPResponse uacfailureResponse =
                SIPTransport.GetResponse(m_uacTransaction.TransactionRequest, rejectCode, rejectReason);

            if (customHeaders != null && customHeaders.Length > 0)
            {
                foreach (string header in customHeaders)
                {
                    uacfailureResponse.Header.UnknownHeaders.Add(header);
                }
            }

            m_uacTransaction.GotResponse(m_blackhole, m_blackhole, uacfailureResponse);
            CallAnswered(this, uacfailureResponse);
            CallFailed.Invoke(this, "failed");
        }
        /// <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);
            }
        }
Example #4
0
        private void ClientCallFailed(ISIPClientUserAgent uac, string error, SIPResponse errResponse)
        {
            if (!base.IsCancelled)
            {
                logger.LogDebug($"B2BUserAgent client call failed {error}.");

                var status  = (errResponse != null) ? errResponse.Status : SIPResponseStatusCodesEnum.Decline;
                var errResp = SIPResponse.GetResponse(m_uasTransaction.TransactionRequest, status, errResponse?.ReasonPhrase);
                m_uasTransaction.SendFinalResponse(errResp);

                CallFailed?.Invoke(uac, error, errResponse);
            }
        }
Example #5
0
        private void ClientCallAnswered(ISIPClientUserAgent uac, SIPResponse resp)
        {
            logger.LogDebug($"B2BUserAgent client call answered {resp.ShortDescription}.");

            if (resp.Status == SIPResponseStatusCodesEnum.Ok)
            {
                base.Answer(resp.Header.ContentType, resp.Body, SIPDialogueTransferModesEnum.NotAllowed);

                CallAnswered?.Invoke(uac, resp);
            }
            else
            {
                var failureResponse = SIPResponse.GetResponse(m_uasTransaction.TransactionRequest, resp.Status, resp.ReasonPhrase);
                m_uasTransaction.SendFinalResponse(failureResponse);

                CallFailed?.Invoke(uac, failureResponse.ReasonPhrase, failureResponse);
            }
        }
 private void CallFailed(CallFailed call)
 {
     _dayPayment.Remove(call.PayPenalty);
 }
        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>
        /// Initiates the call to the remote user agent server.
        /// </summary>
        /// <param name="sipCallDescriptor">The descriptor for the call that describes how to reach the user agent server and other properties.</param>
        /// <param name="serverEndPoint">Optional. If the server end point for the call is known or has been resolved in advance. If
        /// not set the SIP transport layer will attempt to resolve the destination at sending time.</param>
        public SIPRequest Call(SIPCallDescriptor sipCallDescriptor, SIPEndPoint serverEndPoint)
        {
            try
            {
                m_sipCallDescriptor = sipCallDescriptor;
                SIPURI      callURI  = SIPURI.ParseSIPURI(sipCallDescriptor.Uri);
                SIPRouteSet routeSet = null;

                logger.LogDebug($"UAC commencing call to {SIPURI.ParseSIPURI(m_sipCallDescriptor.Uri).CanonicalAddress}.");

                // A custom route set may have been specified for the call.
                if (m_sipCallDescriptor.RouteSet != null && m_sipCallDescriptor.RouteSet.IndexOf(OUTBOUNDPROXY_AS_ROUTESET_CHAR) != -1)
                {
                    try
                    {
                        routeSet = new SIPRouteSet();
                        routeSet.PushRoute(new SIPRoute(m_sipCallDescriptor.RouteSet, true));
                    }
                    catch
                    {
                        logger.LogDebug("Error an outbound proxy value was not recognised in SIPClientUserAgent Call. " + m_sipCallDescriptor.RouteSet + ".");
                    }
                }

                string content = sipCallDescriptor.Content;

                if (content.IsNullOrBlank())
                {
                    logger.LogDebug("Body on UAC call was empty.");
                }

                if (this.m_sipCallDescriptor.BranchId.IsNullOrBlank())
                {
                    this.m_sipCallDescriptor.BranchId = CallProperties.CreateBranchId();
                }

                if (this.m_sipCallDescriptor.CallId.IsNullOrBlank())
                {
                    this.m_sipCallDescriptor.CallId = CallProperties.CreateNewCallId();
                }

                SIPRequest inviteRequest = GetInviteRequest(m_sipCallDescriptor, m_sipCallDescriptor.BranchId, m_sipCallDescriptor.CallId, routeSet, content, sipCallDescriptor.ContentType);

                // Now that we have a destination socket create a new UAC transaction for forwarded leg of the call.
                m_serverTransaction = new UACInviteTransaction(m_sipTransport, inviteRequest, m_outboundProxy);

                m_serverTransaction.UACInviteTransactionInformationResponseReceived += ServerInformationResponseReceived;
                m_serverTransaction.UACInviteTransactionFinalResponseReceived       += ServerFinalResponseReceived;
                m_serverTransaction.UACInviteTransactionFailed += ServerTransactionFailed;

                m_serverTransaction.SendInviteRequest();

                return(inviteRequest);
            }
            catch (ApplicationException appExcp)
            {
                m_serverTransaction?.CancelCall(appExcp.Message);
                CallFailed?.Invoke(this, appExcp.Message, null);
                return(null);
            }
            catch (Exception excp)
            {
                logger.LogError("Exception UserAgentClient Call. " + excp);
                m_serverTransaction?.CancelCall("Unknown exception");
                CallFailed?.Invoke(this, excp.Message, null);
                return(null);
            }
        }
Example #9
0
 public static void NotifyCallFailed(Exception exception)
 {
     MainThread.BeginInvokeOnMainThread(() => CallFailed?.Invoke(null, exception));
 }