Example #1
0
        /// <summary>
        /// Attempts to place a new outgoing call.
        /// </summary>
        /// <param name="sipCallDescriptor">A call descriptor containing the information about how
        /// and where to place the call.</param>
        /// <param name="mediaSession">The media session used for this call</param>
        public async Task InitiateCall(SIPCallDescriptor sipCallDescriptor, IMediaSession mediaSession)
        {
            m_uac               = new SIPClientUserAgent(m_transport);
            m_uac.CallTrying   += ClientCallTryingHandler;
            m_uac.CallRinging  += ClientCallRingingHandler;
            m_uac.CallAnswered += ClientCallAnsweredHandler;
            m_uac.CallFailed   += ClientCallFailedHandler;

            SIPEndPoint serverEndPoint = m_uac.GetCallDestination(sipCallDescriptor);

            if (serverEndPoint != null)
            {
                MediaSession = mediaSession;
                MediaSession.SessionMediaChanged += MediaSessionOnSessionMediaChanged;

                var sdp = await MediaSession.CreateOffer(serverEndPoint.Address).ConfigureAwait(false);

                sipCallDescriptor.Content = sdp;

                m_uac.Call(sipCallDescriptor);
            }
            else
            {
                ClientCallFailed?.Invoke(m_uac, $"Could not resolve destination when placing call to {sipCallDescriptor.Uri}.");
                CallEnded();
            }
        }
Example #2
0
        /// <summary>
        /// Attempts to place a new outgoing call.
        /// </summary>
        /// <param name="dst">The destination SIP URI to call.</param>
        /// <param name="username">Optional Username if authentication is required.</param>
        /// <param name="password">Optional. Password if authentication is required.</param>
        /// <param name="mediaSession">The RTP session for the call.</param>
        public async Task <bool> Call(string dst, string username, string password, IMediaSession mediaSession)
        {
            if (!SIPURI.TryParse(dst, out var dstUri))
            {
                throw new ApplicationException("The destination was not recognised as a valid SIP URI.");
            }

            SIPCallDescriptor callDescriptor = new SIPCallDescriptor(
                username ?? SIPConstants.SIP_DEFAULT_USERNAME,
                password,
                dstUri.ToString(),
                SIPConstants.SIP_DEFAULT_FROMURI,
                dstUri.CanonicalAddress,
                null, null, null,
                SIPCallDirection.Out,
                SDP.SDP_MIME_CONTENTTYPE,
                null,
                null);

            await InitiateCall(callDescriptor, mediaSession);

            TaskCompletionSource <bool> callResult = new TaskCompletionSource <bool>();

            ClientCallAnswered += (uac, resp) => Task.Run(() => callResult.SetResult(true));
            ClientCallFailed   += (uac, errorMessage) => Task.Run(() => callResult.SetResult(false));

            return(await callResult.Task);
        }
Example #3
0
 /// <summary>
 /// Attempts to place a new outgoing call.
 /// </summary>
 /// <param name="sipCallDescriptor">A call descriptor containing the information about how and where to place the call.</param>
 public void Call(SIPCallDescriptor sipCallDescriptor)
 {
     m_uac               = new SIPClientUserAgent(m_transport);
     m_uac.CallTrying   += ClientCallTryingHandler;
     m_uac.CallRinging  += ClientCallRingingHandler;
     m_uac.CallAnswered += ClientCallAnsweredHandler;
     m_uac.CallFailed   += ClientCallFailedHandler;
     m_uac.Call(sipCallDescriptor);
 }
 public SIPNonInviteClientUserAgent(
     SIPTransport sipTransport,
     SIPEndPoint outboundProxy,
     SIPCallDescriptor callDescriptor)
 {
     m_sipTransport   = sipTransport;
     m_outboundProxy  = outboundProxy;
     m_callDescriptor = callDescriptor;
 }
Example #5
0
        /// <summary>
        /// Attempts to place a new outgoing call.
        /// </summary>
        /// <param name="sipCallDescriptor">A call descriptor containing the information about how
        /// and where to place the call.</param>
        /// <param name="mediaSession">The media session used for this call</param>
        public async Task InitiateCallAsync(SIPCallDescriptor sipCallDescriptor, IMediaSession mediaSession)
        {
            m_cts = new CancellationTokenSource();

            m_uac               = new SIPClientUserAgent(m_transport);
            m_uac.CallTrying   += ClientCallTryingHandler;
            m_uac.CallRinging  += ClientCallRingingHandler;
            m_uac.CallAnswered += ClientCallAnsweredHandler;
            m_uac.CallFailed   += ClientCallFailedHandler;

            // Can be DNS lookups involved in getting the call destination.
            SIPEndPoint serverEndPoint = await Task.Run <SIPEndPoint>(() => { return(m_uac.GetCallDestination(sipCallDescriptor)); }).ConfigureAwait(false);

            if (serverEndPoint != null)
            {
                MediaSession             = mediaSession;
                MediaSession.OnRtpEvent += OnRemoteRtpEvent;
                //MediaSession.OnRtpClosed += (reason) => Hangup();
                MediaSession.OnRtpClosed += (reason) =>
                {
                    if (!MediaSession.IsClosed)
                    {
                        logger.LogWarning($"RTP channel was closed with reason {reason}.");
                    }
                };

                RTCOfferOptions offerOptions = new RTCOfferOptions {
                    RemoteSignallingAddress = serverEndPoint.Address
                };

                var sdp = await mediaSession.createOffer(offerOptions).ConfigureAwait(false);

                mediaSession.setLocalDescription(new RTCSessionDescription {
                    sdp = sdp, type = RTCSdpType.offer
                });

                if (mediaSession.localDescription == null)
                {
                    ClientCallFailed?.Invoke(m_uac, $"Could not create a local SDP offer.");
                    CallEnded();
                }
                else
                {
                    sipCallDescriptor.Content = mediaSession.localDescription.sdp.ToString();
                    // This initiates the call but does not wait for an answer.
                    m_uac.Call(sipCallDescriptor);
                }
            }
            else
            {
                ClientCallFailed?.Invoke(m_uac, $"Could not resolve destination when placing call to {sipCallDescriptor.Uri}.");
                CallEnded();
            }
        }
Example #6
0
        public SIPRequest Call(SIPCallDescriptor sipCallDescriptor, SIPEndPoint serverEndPoint)
        {
            m_uacCallDescriptor = sipCallDescriptor;

            m_uac               = new SIPClientUserAgent(m_sipTransport, m_outboundProxy);
            m_uac.CallFailed   += ClientCallFailed;
            m_uac.CallTrying   += (uac, resp) => CallTrying?.Invoke(uac, resp);
            m_uac.CallRinging  += (uac, resp) => CallRinging?.Invoke(uac, resp);
            m_uac.CallAnswered += ClientCallAnswered;

            return(m_uac.Call(m_uacCallDescriptor));
        }
Example #7
0
        private SIPRequest GetInviteRequest(string callURI, SIPCallDescriptor sipCallDescriptor)
        {
            SIPFromHeader fromHeader = sipCallDescriptor.GetFromHeader();

            SIPRequest inviteRequest = new SIPRequest(SIPMethodsEnum.INVITE, SIPURI.ParseSIPURI(callURI));

            inviteRequest.LocalSIPEndPoint = m_blackhole;

            SIPHeader inviteHeader = new SIPHeader(fromHeader, new SIPToHeader(null, inviteRequest.URI, null), 1, CallProperties.CreateNewCallId());

            inviteHeader.From.FromTag = CallProperties.CreateNewTag();

            // For incoming calls forwarded via the dial plan the username needs to go into the Contact header.
            inviteHeader.Contact = new List <SIPContactHeader>()
            {
                new SIPContactHeader(null, new SIPURI(inviteRequest.URI.Scheme, m_blackhole))
            };
            inviteHeader.CSeqMethod = SIPMethodsEnum.INVITE;
            inviteRequest.Header    = inviteHeader;

            SIPViaHeader viaHeader = new SIPViaHeader(m_blackhole, CallProperties.CreateBranchId());

            inviteRequest.Header.Vias.PushViaHeader(viaHeader);

            try
            {
                if (sipCallDescriptor.CustomHeaders != null && sipCallDescriptor.CustomHeaders.Count > 0)
                {
                    foreach (string customHeader in sipCallDescriptor.CustomHeaders)
                    {
                        if (customHeader.IsNullOrBlank())
                        {
                            continue;
                        }
                        else if (customHeader.Trim().StartsWith(SIPHeaders.SIP_HEADER_USERAGENT))
                        {
                            inviteRequest.Header.UserAgent = customHeader.Substring(customHeader.IndexOf(":") + 1).Trim();
                        }
                        else
                        {
                            inviteRequest.Header.UnknownHeaders.Add(customHeader);
                        }
                    }
                }
            }
            catch (Exception excp)
            {
                logger.LogError("Exception Parsing CustomHeader for GetInviteRequest. " + excp.Message + sipCallDescriptor.CustomHeaders);
            }

            return(inviteRequest);
        }
Example #8
0
        public void Call(SIPCallDescriptor sipCallDescriptor)
        {
            try
            {
                m_uacCallDescriptor = sipCallDescriptor;
                SIPRequest uacInviteRequest = GetInviteRequest(m_uacCallDescriptor.Uri, sipCallDescriptor);
                if (sipCallDescriptor.MangleResponseSDP && sipCallDescriptor.MangleIPAddress != null)
                {
                    uacInviteRequest.Header.ProxyReceivedFrom = sipCallDescriptor.MangleIPAddress.ToString();
                }
                uacInviteRequest.Body = sipCallDescriptor.Content;
                uacInviteRequest.Header.ContentType = sipCallDescriptor.ContentType;
                uacInviteRequest.LocalSIPEndPoint   = m_blackhole;
                uacInviteRequest.RemoteSIPEndPoint  = m_blackhole;

                // Now that we have a destination socket create a new UAC transaction for forwarded leg of the call.
                m_uacTransaction = m_sipTransport.CreateUACTransaction(uacInviteRequest, m_blackhole, m_blackhole, null);
                if (m_uacTransaction.CDR != null)
                {
                    m_uacTransaction.CDR.Owner             = m_uacOwner;
                    m_uacTransaction.CDR.AdminMemberId     = m_uacAdminMemberId;
                    m_uacTransaction.CDR.DialPlanContextID = (m_uacCallDescriptor != null) ? m_uacCallDescriptor.DialPlanContextID : Guid.Empty;
                }

                //uacTransaction.UACInviteTransactionInformationResponseReceived += ServerInformationResponseReceived;
                //uacTransaction.UACInviteTransactionFinalResponseReceived += ServerFinalResponseReceived;
                //uacTransaction.UACInviteTransactionTimedOut += ServerTimedOut;
                //uacTransaction.TransactionTraceMessage += TransactionTraceMessage;

                m_uacTransaction.SendInviteRequest(m_blackhole, m_uacTransaction.TransactionRequest);

                SIPRequest uasInviteRequest = uacInviteRequest.Copy();
                uasInviteRequest.LocalSIPEndPoint  = m_blackhole;
                uasInviteRequest.RemoteSIPEndPoint = m_blackhole;
                uasInviteRequest.Header.Vias.TopViaHeader.Branch = CallProperties.CreateBranchId();
                m_uasTransaction = m_sipTransport.CreateUASTransaction(uasInviteRequest, m_blackhole, m_blackhole, null);

                SetOwner(sipCallDescriptor.ToSIPAccount.Owner, sipCallDescriptor.ToSIPAccount.AdminMemberId);
                //m_uasTransaction.TransactionTraceMessage += TransactionTraceMessage;
                //m_uasTransaction.UASInviteTransactionTimedOut += ClientTimedOut;
                //m_uasTransaction.UASInviteTransactionCancelled += (t) => { };

                QueueNewCall_External(this);
            }
            catch (Exception excp)
            {
                logger.LogError("Exception SIPB2BUserAgent Call. " + excp.Message);
            }
        }
        public void Call(SIPCallDescriptor sipCallDescriptor)
        {
            CallDescriptor = sipCallDescriptor;
            m_xmppClient = new XMPPClient("talk.google.com", 5222, "google.com", null, null);
            m_xmppClient.IsBound += IsBound;
            m_xmppClient.Answered += Answered;

            IPEndPoint sdpEndPoint = SDP.GetSDPRTPEndPoint(CallDescriptor.Content);
            if (IPSocket.IsPrivateAddress(sdpEndPoint.Address.ToString()))
            {
                bool wasSDPMangled;
                CallDescriptor.Content = SIPPacketMangler.MangleSDP(CallDescriptor.Content, CallDescriptor.MangleIPAddress.ToString(), out wasSDPMangled);
            }

            ThreadPool.QueueUserWorkItem(delegate { m_xmppClient.Connect(); });
        }
        public SIPNonInviteClientUserAgent(
            SIPTransport sipTransport,
            SIPEndPoint outboundProxy,
            SIPCallDescriptor callDescriptor,
            string owner,
            string adminMemberID,
            SIPMonitorLogDelegate logDelegate)
        {
            m_sipTransport = sipTransport;
            m_outboundProxy = outboundProxy;
            m_callDescriptor = callDescriptor;
            m_owner = owner;
            m_adminMemberID = adminMemberID;

            Log_External = logDelegate;
        }
        public SIPNonInviteClientUserAgent(
            SIPTransport sipTransport,
            SIPEndPoint outboundProxy,
            SIPCallDescriptor callDescriptor,
            string owner,
            string adminMemberID,
            SIPMonitorLogDelegate logDelegate)
        {
            m_sipTransport   = sipTransport;
            m_outboundProxy  = outboundProxy;
            m_callDescriptor = callDescriptor;
            m_owner          = owner;
            m_adminMemberID  = adminMemberID;

            Log_External = logDelegate;
        }
Example #12
0
        /// <summary>
        /// Attempts to place a new outgoing call.
        /// </summary>
        /// <param name="sipCallDescriptor">A call descriptor containing the information about how
        /// and where to place the call.</param>
        /// <param name="mediaSession">The media session used for this call</param>
        public async Task InitiateCallAsync(SIPCallDescriptor sipCallDescriptor, IMediaSession mediaSession)
        {
            m_cts = new CancellationTokenSource();

            m_uac               = new SIPClientUserAgent(m_transport);
            m_uac.CallTrying   += ClientCallTryingHandler;
            m_uac.CallRinging  += ClientCallRingingHandler;
            m_uac.CallAnswered += ClientCallAnsweredHandler;
            m_uac.CallFailed   += ClientCallFailedHandler;

            // Can be DNS lookups involved in getting the call destination.
            SIPEndPoint serverEndPoint = await Task.Run <SIPEndPoint>(() => { return(m_uac.GetCallDestination(sipCallDescriptor)); }).ConfigureAwait(false);

            if (serverEndPoint != null)
            {
                MediaSession             = mediaSession;
                MediaSession.OnRtpEvent += OnRemoteRtpEvent;
                //MediaSession.OnRtpClosed += (reason) => Hangup();
                MediaSession.OnRtpClosed += (reason) =>
                {
                    if (!MediaSession.IsClosed)
                    {
                        logger.LogWarning($"RTP channel was closed with reason {reason}.");
                    }
                };

                var sdpAnnounceAddress = NetServices.GetLocalAddressForRemote(serverEndPoint.Address);

                var sdp = mediaSession.CreateOffer(sdpAnnounceAddress);
                if (sdp == null)
                {
                    ClientCallFailed?.Invoke(m_uac, $"Could not generate an offer.", null);
                    CallEnded();
                }
                else
                {
                    sipCallDescriptor.Content = sdp.ToString();
                    // This initiates the call but does not wait for an answer.
                    m_uac.Call(sipCallDescriptor);
                }
            }
            else
            {
                ClientCallFailed?.Invoke(m_uac, $"Could not resolve destination when placing call to {sipCallDescriptor.Uri}.", null);
                CallEnded();
            }
        }
Example #13
0
        /// <summary>
        /// Attempts to place a new outgoing call AND waits for the call to be answered or fail.
        /// Use <see cref="InitiateCallAsync(SIPCallDescriptor, IMediaSession)"/> to start a call without
        /// waiting for it to complete and monitor <see cref="ClientCallAnsweredHandler"/> and
        /// <see cref="ClientCallFailedHandler"/> to detect an answer or failure.
        /// </summary>
        /// <param name="callDescriptor">The full descriptor for the call destination. Allows customising
        /// of additional options above the standard username, password and destination URI.</param>
        /// <param name="mediaSession">The RTP session for the call.</param>
        public async Task <bool> Call(SIPCallDescriptor callDescriptor, IMediaSession mediaSession)
        {
            TaskCompletionSource <bool> callResult = new TaskCompletionSource <bool>(TaskCreationOptions.RunContinuationsAsynchronously);

            await InitiateCallAsync(callDescriptor, mediaSession).ConfigureAwait(false);

            ClientCallAnswered += (uac, resp) =>
            {
                callResult.TrySetResult(true);
            };
            ClientCallFailed += (uac, errorMessage) =>
            {
                callResult.TrySetResult(false);
            };

            return(callResult.Task.Result);
        }
Example #14
0
        public void Call(SIPCallDescriptor sipCallDescriptor)
        {
            CallDescriptor         = sipCallDescriptor;
            m_xmppClient           = new XMPPClient("talk.google.com", 5222, "google.com", null, null);
            m_xmppClient.IsBound  += IsBound;
            m_xmppClient.Answered += Answered;

            IPEndPoint sdpEndPoint = SDP.GetSDPRTPEndPoint(CallDescriptor.Content);

            if (IPSocket.IsPrivateAddress(sdpEndPoint.Address.ToString()))
            {
                bool wasSDPMangled;
                CallDescriptor.Content = SIPPacketMangler.MangleSDP(CallDescriptor.Content, CallDescriptor.MangleIPAddress.ToString(), out wasSDPMangled);
            }

            ThreadPool.QueueUserWorkItem(delegate { m_xmppClient.Connect(); });
        }
Example #15
0
        /// <summary>
        /// Attempts to place a new outgoing call AND waits for the call to be answered or fail.
        /// Use <see cref="InitiateCallAsync(SIPCallDescriptor, IMediaSession)"/> to start a call without
        /// waiting for it to complete and monitor <see cref="ClientCallAnsweredHandler"/> and
        /// <see cref="ClientCallFailedHandler"/> to detect an answer or failure.
        /// </summary>
        /// <param name="dst">The destination SIP URI to call.</param>
        /// <param name="username">Optional Username if authentication is required.</param>
        /// <param name="password">Optional. Password if authentication is required.</param>
        /// <param name="mediaSession">The RTP session for the call.</param>
        public Task <bool> Call(string dst, string username, string password, IMediaSession mediaSession)
        {
            if (!SIPURI.TryParse(dst, out var dstUri))
            {
                throw new ApplicationException("The destination was not recognised as a valid SIP URI.");
            }

            SIPCallDescriptor callDescriptor = new SIPCallDescriptor(
                username ?? SIPConstants.SIP_DEFAULT_USERNAME,
                password,
                dstUri.ToString(),
                SIPConstants.SIP_DEFAULT_FROMURI,
                dstUri.CanonicalAddress,
                null, null, null,
                SIPCallDirection.Out,
                SDP.SDP_MIME_CONTENTTYPE,
                null,
                null);

            return(Call(callDescriptor, mediaSession));
        }
Example #16
0
        public override void Start()
        {
            try
            {
                base.Start();

                m_activeAppServerEntry = GetActiveAppServer();

                if (m_activeAppServerEntry != null)
                {
                    while (!m_stop)
                    {
                        Thread.Sleep(Convert.ToInt32(m_interval.TotalMilliseconds % Int32.MaxValue));

                        logger.Debug("AppServerDispatcher executing.");

                        m_startCheckTime.Reset();
                        m_startCheckTime.Start();

                        SIPClientUserAgent uac            = new SIPClientUserAgent(m_sipTransport, null, null, null, LogMonitorEvent);
                        SIPCallDescriptor  callDescriptor = new SIPCallDescriptor(null, null, m_activeAppServerEntry.AppServerURI.ToString(), null, null, null, null, null, SIPCallDirection.Out, null, null, null);
                        callDescriptor.MangleResponseSDP = false;
                        uac.CallFailed   += CallFailed;
                        uac.CallAnswered += CallAnswered;
                        uac.Call(callDescriptor);
                        uac.ServerTransaction.CDR = null;
                    }
                }
                else
                {
                    logger.Warn("No active app server could be set in AppServerDispatcher.Start, job stopping.");
                }
            }
            catch (Exception excp)
            {
                logger.Error("Exception AppServerDispatcher StartJob. " + excp.Message);
            }
        }
Example #17
0
        public SIPCallDescriptor CopyOf()
        {
            List <string> copiedCustomHeaders = null;

            if (CustomHeaders != null)
            {
                copiedCustomHeaders = new List <string>();
                copiedCustomHeaders.InsertRange(0, CustomHeaders);
            }

            SIPCallDescriptor copy = new SIPCallDescriptor(
                Username,
                Password,
                Uri,
                From,
                To,
                RouteSet,
                copiedCustomHeaders,
                AuthUsername,
                CallDirection,
                ContentType,
                Content,
                (MangleIPAddress != null) ? new IPAddress(MangleIPAddress.GetAddressBytes()) : null);

            // Options.
            copy.DelaySeconds      = DelaySeconds;
            copy.RedirectMode      = RedirectMode;
            copy.CallDurationLimit = CallDurationLimit;
            copy.MangleResponseSDP = MangleResponseSDP;
            copy.FromDisplayName   = FromDisplayName;
            copy.FromURIUsername   = FromURIUsername;
            copy.FromURIHost       = FromURIHost;
            copy.TransferMode      = TransferMode;

            copy.ToSIPAccount = ToSIPAccount;

            return(copy);
        }
        public void Call(SIPCallDescriptor descriptor)
        {
            try
            {
                CallDescriptor = descriptor;
                SIPURI destinationURI = SIPURI.ParseSIPURIRelaxed(descriptor.Uri);
                SIPDialogue = m_googleVoiceCall.InitiateCall(descriptor.Username, descriptor.Password, descriptor.CallbackNumber, destinationURI.User, descriptor.CallbackPattern, descriptor.CallbackPhoneType, MAX_CALLBACK_WAIT_TIME, descriptor.ContentType, descriptor.Content);

                if (SIPDialogue != null)
                {
                    CallAnswered(this, null);
                }
                else
                {
                    CallFailed(this, "Google Voice call failed.");
                }
            }
            catch (Exception excp)
            {
                logger.Error("Exception GoogleVoiceCallAgent Call. " + excp.Message);
                CallFailed(this, excp.Message);
            }
        }
Example #19
0
        //private SIPDNSLookupResult ResolveSIPEndPoint(SIPURI uri, bool async)
        //{
        //    logger.Debug("Resolving SIP URI " + uri.ToParameterlessString() + ".");
        //    return null;
        //}
        /// <summary>
        /// Places an outgoing SIP call.
        /// </summary>
        /// <param name="destination">The SIP URI to place a call to. The destination can be a full SIP URI in which case the all will
        /// be placed anonymously directly to that URI. Alternatively it can be just the user portion of a URI in which case it will
        /// be sent to the configured SIP server.</param>
        public void Call(string destination, IPEndPoint rtpEndPoint, string sipUsername, string sipPassword, string realm)
        {
            // Determine if this is a direct anonymous call or whether it should be placed using the pre-configured SIP server account.
            SIPURI callURI = null;
            //string sipUsername = null;
            //string sipPassword = null;
            string fromHeader = null;

            //if (destination.Contains("@") || m_sipServer == null)
            //{
                // Anonymous call direct to SIP server specified in the URI.
                callURI = SIPURI.ParseSIPURIRelaxed(destination);
            //}
            //else
            //{
            //    // This call will use the pre-configured SIP account.
            //    callURI = SIPURI.ParseSIPURIRelaxed(destination + "@" + m_sipServer);
            //    sipUsername = m_sipUsername;
            //    sipPassword = m_sipPassword;
                fromHeader = (new SIPFromHeader(sipUsername, new SIPURI(sipUsername, realm, null), null)).ToString();
            //}

            StatusMessage("Starting call to " + callURI.ToString() + ".");

            m_uac = new SIPClientUserAgent(m_sipTransport, null, null, null, null);
            m_uac.CallTrying += CallTrying;
            m_uac.CallRinging += CallRinging;
            m_uac.CallAnswered += CallAnswered;
            m_uac.CallFailed += CallFailed;

            _audioChannel = new AudioChannel(rtpEndPoint);

            // Get the SDP requesting that the public IP address be used if the host on the call destination is not a private IP address.
            SDP sdp = _audioChannel.GetSDP();
            SIPCallDescriptor callDescriptor = new SIPCallDescriptor(sipUsername, sipPassword, callURI.ToString(), fromHeader, null, null, null, null, SIPCallDirection.Out, SDP.SDP_MIME_CONTENTTYPE, sdp.ToString(), null);
            m_uac.Call(callDescriptor);
        }
Example #20
0
        private void StartNewCallAsync(SIPCallDescriptor callDescriptor)
        {
            try
            {
                callDescriptor.DialPlanContextID = (m_dialPlanContext != null) ? m_dialPlanContext.DialPlanContextID : Guid.Empty;

                if (Thread.CurrentThread.Name == null)
                {
                    Thread.CurrentThread.Name = THEAD_NAME + DateTime.Now.ToString("HHmmss") + "-" + Crypto.GetRandomString(3);
                }

                StartNewCallSync(callDescriptor);
            }
            catch (Exception excp)
            {
                logger.Error("Exception StartNewCallAsync. " + excp.Message);
            }
        }
        public void ReferOutOfDialog(SIPURI fromUri, SIPURI toUri, SIPURI referToUri, ReplacesCallDescriptor sipReplacesCallDescriptor)
        {
            try
            {
                m_sipCallDescriptor = new SIPCallDescriptor(null,toUri.ToString(),fromUri.ToString(),null,null);
                m_sipCallDescriptor.Gruu = toUri.Parameters.Get(SIPCallDescriptor.GRUU_KEY);
                m_sipCallDescriptor.ReplacesCall = sipReplacesCallDescriptor;

                SIPURI callURI = SIPURI.ParseSIPURI(m_sipCallDescriptor.Uri);

                    // 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))
                    {
                        m_serverEndPoint = m_outboundProxy;
                    }
                    else if (!m_sipCallDescriptor.ProxySendFrom.IsNullOrBlank())
                    {
                        // 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.
                        SIPEndPoint outboundProxyEndPoint = SIPEndPoint.ParseSIPEndPoint(m_sipCallDescriptor.ProxySendFrom);
                        m_outboundProxy = new SIPEndPoint(SIPProtocolsEnum.udp, new IPEndPoint(outboundProxyEndPoint.Address, m_defaultSIPPort));
                        m_serverEndPoint = m_outboundProxy;
                        Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.ReferUserAgentClient, SIPMonitorEventTypesEnum.Refer, "SIPReferClientUserAgent refer request using alternate outbound proxy of " + m_outboundProxy + ".", Owner));
                    }
                    else if (m_outboundProxy != null)
                    {
                        // Using the system outbound proxy only, no additional user routing requirements.
                        m_serverEndPoint = m_outboundProxy;
                    }

                    // 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
                        {
                            Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.ReferUserAgentClient, SIPMonitorEventTypesEnum.Refer, "Error an outbound proxy value was not recognised in SIPReferClientUserAgent refer request. " + m_sipCallDescriptor.RouteSet + ".", Owner));
                        }
                    }

                    // No outbound proxy, determine the forward destination based on the SIP request.
                    if (m_serverEndPoint == null)
                    {
                        SIPDNSLookupResult lookupResult = null;

                        if (RouteSet == null || RouteSet.Length == 0)
                        {
                            Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.ReferUserAgentClient, SIPMonitorEventTypesEnum.Refer, "Attempting to resolve " + callURI.Host + ".", Owner));
                            lookupResult = m_sipTransport.GetURIEndPoint(callURI, false);
                        }
                        else
                        {
                            Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.ReferUserAgentClient, SIPMonitorEventTypesEnum.Refer, "Route set for refer request " + RouteSet.ToString() + ".", Owner));
                            lookupResult = m_sipTransport.GetURIEndPoint(RouteSet.TopRoute.URI, false);
                        }

                        if (lookupResult.LookupError != null)
                        {
                            Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.ReferUserAgentClient, SIPMonitorEventTypesEnum.Refer, "DNS error resolving " + callURI.Host + ", " + lookupResult.LookupError + ". Refer request cannot proceed.", Owner));
                        }
                        else
                        {
                            m_serverEndPoint = lookupResult.GetSIPEndPoint();
                        }
                    }

                    if (m_serverEndPoint != null)
                    {
                        Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.ReferUserAgentClient, SIPMonitorEventTypesEnum.Refer, "Switching to " + SIPURI.ParseSIPURI(m_sipCallDescriptor.Uri).CanonicalAddress + " via " + m_serverEndPoint + ".", Owner));

                        m_localSIPEndPoint = m_sipTransport.GetDefaultSIPEndPoint(m_serverEndPoint);
                        if (m_localSIPEndPoint == null)
                        {
                            throw new ApplicationException("The refer request could not locate an appropriate SIP transport channel for protocol " + callURI.Protocol + ".");
                        }

                        SIPRequest referRequest = GetReferRequest(m_localSIPEndPoint,referToUri, sipReplacesCallDescriptor);

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

                        m_serverTransaction.NonInviteTransactionFinalResponseReceived += m_serverTransaction_NonInviteTransactionFinalResponseReceived;
                        m_serverTransaction.NonInviteTransactionTimedOut += m_serverTransaction_NonInviteTransactionTimedOut;
                        m_serverTransaction.TransactionTraceMessage += TransactionTraceMessage;

                        m_serverTransaction.SendReliableRequest();

                    }
                    else
                    {
                        if (RouteSet == null || RouteSet.Length == 0)
                        {
                            Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.ReferUserAgentClient, SIPMonitorEventTypesEnum.Refer, "Forward leg failed, could not resolve URI host " + callURI.Host, Owner));
                            FireReferFailed(this, "unresolvable destination " + callURI.Host);
                        }
                        else
                        {
                            Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.ReferUserAgentClient, SIPMonitorEventTypesEnum.Refer, "Forward leg failed, could not resolve top Route host " + RouteSet.TopRoute.Host, Owner));
                            FireReferFailed(this, "unresolvable destination " + RouteSet.TopRoute.Host);
                        }
                    }
            }
            catch (ApplicationException appExcp)
            {
                FireReferFailed(this, appExcp.Message);
            }
            catch (Exception excp)
            {
                Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.ReferUserAgentClient, SIPMonitorEventTypesEnum.Refer, "Exception UserAgentClient Call. " + excp.Message, Owner));
                FireReferFailed(this, excp.Message);
            }
        }
        public void Call(SIPCallDescriptor sipCallDescriptor)
        {
            try
            {
                m_sipCallDescriptor = sipCallDescriptor;
                SIPURI callURI = SIPURI.ParseSIPURI(sipCallDescriptor.Uri);
                SIPRouteSet routeSet = null;

                if (!m_callCancelled)
                {
                    // 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))
                    {
                        m_serverEndPoint = m_outboundProxy;
                    }
                    else if (!sipCallDescriptor.ProxySendFrom.IsNullOrBlank())
                    {
                        // 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.
                        SIPEndPoint outboundProxyEndPoint = SIPEndPoint.ParseSIPEndPoint(sipCallDescriptor.ProxySendFrom);
                        m_outboundProxy = new SIPEndPoint(SIPProtocolsEnum.udp, new IPEndPoint(outboundProxyEndPoint.Address, m_defaultSIPPort));
                        m_serverEndPoint = m_outboundProxy;
                        Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentClient, SIPMonitorEventTypesEnum.DialPlan, "SIPClientUserAgent Call using alternate outbound proxy of " + m_outboundProxy + ".", Owner));
                    }
                    else if (m_outboundProxy != null)
                    {
                        // Using the system outbound proxy only, no additional user routing requirements.
                        m_serverEndPoint = m_outboundProxy;
                    }

                    // 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
                        {
                            Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentClient, SIPMonitorEventTypesEnum.DialPlan, "Error an outbound proxy value was not recognised in SIPClientUserAgent Call. " + m_sipCallDescriptor.RouteSet + ".", Owner));
                        }
                    }

                    // No outbound proxy, determine the forward destination based on the SIP request.
                    if (m_serverEndPoint == null)
                    {
                        SIPDNSLookupResult lookupResult = null;

                        if (routeSet == null || routeSet.Length == 0)
                        {
                            Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentClient, SIPMonitorEventTypesEnum.DialPlan, "Attempting to resolve " + callURI.Host + ".", Owner));
                            lookupResult = m_sipTransport.GetURIEndPoint(callURI, false);
                        }
                        else
                        {
                            Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentClient, SIPMonitorEventTypesEnum.DialPlan, "Route set for call " + routeSet.ToString() + ".", Owner));
                            lookupResult = m_sipTransport.GetURIEndPoint(routeSet.TopRoute.URI, false);
                        }

                        if (lookupResult.LookupError != null)
                        {
                            Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentClient, SIPMonitorEventTypesEnum.DialPlan, "DNS error resolving " + callURI.Host + ", " + lookupResult.LookupError + ". Call cannot proceed.", Owner));
                        }
                        else
                        {
                            m_serverEndPoint = lookupResult.GetSIPEndPoint();
                        }
                    }

                    if (m_serverEndPoint != null)
                    {
                        Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentClient, SIPMonitorEventTypesEnum.DialPlan, "Switching to " + SIPURI.ParseSIPURI(m_sipCallDescriptor.Uri).CanonicalAddress + " via " + m_serverEndPoint + ".", Owner));

                        m_localSIPEndPoint = m_sipTransport.GetDefaultSIPEndPoint(m_serverEndPoint);
                        if (m_localSIPEndPoint == null)
                        {
                            throw new ApplicationException("The call could not locate an appropriate SIP transport channel for protocol " + callURI.Protocol + ".");
                        }

                        string content = sipCallDescriptor.Content;

                        if (content.IsNullOrBlank())
                        {
                            Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Body on UAC call was empty.", Owner));
                        }
                        else if (m_sipCallDescriptor.ContentType == m_sdpContentType)
                        {
                            if (!m_sipCallDescriptor.MangleResponseSDP)
                            {
                                IPEndPoint sdpEndPoint = SDP.GetSDPRTPEndPoint(content);
                                Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "SDP on UAC call was set to NOT mangle, RTP socket " + sdpEndPoint.ToString() + ".", Owner));
                            }
                            else
                            {
                                IPEndPoint sdpEndPoint = SDP.GetSDPRTPEndPoint(content);
                                if (sdpEndPoint != null)
                                {
                                    if (!IPSocket.IsPrivateAddress(sdpEndPoint.Address.ToString()))
                                    {
                                        Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "SDP on UAC call had public IP not mangled, RTP socket " + sdpEndPoint.ToString() + ".", Owner));
                                    }
                                    else
                                    {
                                        bool wasSDPMangled = false;
                                        if (sipCallDescriptor.MangleIPAddress != null)
                                        {
                                            if (sdpEndPoint != null)
                                            {
                                                content = SIPPacketMangler.MangleSDP(content, sipCallDescriptor.MangleIPAddress.ToString(), out wasSDPMangled);
                                            }
                                        }

                                        if (wasSDPMangled)
                                        {
                                            Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "SDP on UAC call had RTP socket mangled from " + sdpEndPoint.ToString() + " to " + sipCallDescriptor.MangleIPAddress.ToString() + ":" + sdpEndPoint.Port + ".", Owner));
                                        }
                                        else if (sdpEndPoint != null)
                                        {
                                            Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "SDP on UAC could not be mangled, using original RTP socket of " + sdpEndPoint.ToString() + ".", Owner));
                                        }
                                    }
                                }
                                else
                                {
                                    Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "SDP RTP socket on UAC call could not be determined.", Owner));
                                }
                            }
                        }

                        SIPRequest switchServerInvite = GetInviteRequest(m_sipCallDescriptor, CallProperties.CreateBranchId(), CallProperties.CreateNewCallId(), m_localSIPEndPoint, routeSet, content, sipCallDescriptor.ContentType);

                        // Now that we have a destination socket create a new UAC transaction for forwarded leg of the call.
                        m_serverTransaction = m_sipTransport.CreateUACTransaction(switchServerInvite, m_serverEndPoint, m_localSIPEndPoint, m_outboundProxy);
                        if (m_serverTransaction.CDR != null)
                        {
                            m_serverTransaction.CDR.Owner = Owner;
                            m_serverTransaction.CDR.AdminMemberId = AdminMemberId;
                        }

                        m_serverTransaction.UACInviteTransactionInformationResponseReceived += ServerInformationResponseReceived;
                        m_serverTransaction.UACInviteTransactionFinalResponseReceived += ServerFinalResponseReceived;
                        m_serverTransaction.UACInviteTransactionTimedOut += ServerTimedOut;
                        m_serverTransaction.TransactionTraceMessage += TransactionTraceMessage;

                        m_serverTransaction.SendInviteRequest(m_serverEndPoint, m_serverTransaction.TransactionRequest);
                    }
                    else
                    {
                        if (routeSet == null || routeSet.Length == 0)
                        {
                            Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentClient, SIPMonitorEventTypesEnum.DialPlan, "Forward leg failed, could not resolve URI host " + callURI.Host, Owner));
                            FireCallFailed(this, "unresolvable destination " + callURI.Host);
                        }
                        else
                        {
                            Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentClient, SIPMonitorEventTypesEnum.DialPlan, "Forward leg failed, could not resolve top Route host " + routeSet.TopRoute.Host, Owner));
                            FireCallFailed(this, "unresolvable destination " + routeSet.TopRoute.Host);
                        }
                    }
                }       
            }
            catch (ApplicationException appExcp)
            {
                FireCallFailed(this, appExcp.Message);
            }
            catch (Exception excp)
            {
                Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentClient, SIPMonitorEventTypesEnum.DialPlan, "Exception UserAgentClient Call. " + excp.Message, Owner));
                FireCallFailed(this, excp.Message);
            }
        }
Example #23
0
        private SIPRequest GetInviteRequest(string callURI, SIPCallDescriptor sipCallDescriptor)
        {
            SIPFromHeader fromHeader = sipCallDescriptor.GetFromHeader();

            SIPRequest inviteRequest = new SIPRequest(SIPMethodsEnum.INVITE, SIPURI.ParseSIPURI(callURI));
            inviteRequest.LocalSIPEndPoint = m_blackhole;

            SIPHeader inviteHeader = new SIPHeader(fromHeader, new SIPToHeader(null, inviteRequest.URI, null), 1, CallProperties.CreateNewCallId());

            inviteHeader.From.FromTag = CallProperties.CreateNewTag();

            // For incoming calls forwarded via the dial plan the username needs to go into the Contact header.
            inviteHeader.Contact = new List<SIPContactHeader>() { new SIPContactHeader(null, new SIPURI(inviteRequest.URI.Scheme, m_blackhole)) };
            inviteHeader.CSeqMethod = SIPMethodsEnum.INVITE;
            inviteRequest.Header = inviteHeader;

            SIPViaHeader viaHeader = new SIPViaHeader(m_blackhole, CallProperties.CreateBranchId());
            inviteRequest.Header.Vias.PushViaHeader(viaHeader);

            try
            {
                if (sipCallDescriptor.CustomHeaders != null && sipCallDescriptor.CustomHeaders.Count > 0)
                {
                    foreach (string customHeader in sipCallDescriptor.CustomHeaders)
                    {
                        if (customHeader.IsNullOrBlank())
                        {
                            continue;
                        }
                        else if (customHeader.Trim().StartsWith(SIPHeaders.SIP_HEADER_USERAGENT))
                        {
                            inviteRequest.Header.UserAgent = customHeader.Substring(customHeader.IndexOf(":") + 1).Trim();
                        }
                        else
                        {
                            inviteRequest.Header.UnknownHeaders.Add(customHeader);
                        }
                    }
                }
            }
            catch (Exception excp)
            {
                logger.Error("Exception Parsing CustomHeader for GetInviteRequest. " + excp.Message + sipCallDescriptor.CustomHeaders);
            }

            return inviteRequest;
        }
        /// <summary>
        /// Gets the destination of the remote SIP end point for this call.
        /// </summary>
        /// <param name="sipCallDescriptor">The call descriptor containing the settings to use to place the call.</param>
        /// <returns>The server end point for the call.</returns>
        public async Task <SIPEndPoint> GetCallDestination(SIPCallDescriptor sipCallDescriptor)
        {
            SIPURI      callURI        = SIPURI.ParseSIPURI(sipCallDescriptor.Uri);
            SIPEndPoint serverEndPoint = 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))
            {
                serverEndPoint = m_outboundProxy;
            }
            else if (!sipCallDescriptor.ProxySendFrom.IsNullOrBlank())
            {
                // 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.
                //SIPEndPoint outboundProxyEndPoint = SIPEndPoint.ParseSIPEndPoint(sipCallDescriptor.ProxySendFrom);
                //m_outboundProxy = new SIPEndPoint(SIPProtocolsEnum.udp, outboundProxyEndPoint.Address, SIPConstants.DEFAULT_SIP_PORT);
                //m_serverEndPoint = m_outboundProxy;
                m_outboundProxy = SIPEndPoint.ParseSIPEndPoint(sipCallDescriptor.ProxySendFrom);
                serverEndPoint  = m_outboundProxy;
                logger.LogDebug($"SIPClientUserAgent Call using alternate outbound proxy of {serverEndPoint}.");
            }
            else if (m_outboundProxy != null)
            {
                // Using the system outbound proxy only, no additional user routing requirements.
                serverEndPoint = m_outboundProxy;
            }

            // No outbound proxy, determine the forward destination based on the SIP request.
            if (serverEndPoint == null)
            {
                //SIPDNSLookupResult lookupResult = null;
                SIPEndPoint lookupResult = null;
                double      lookupDurationMilliseconds = 0;

                if (sipCallDescriptor.RouteSet != null && sipCallDescriptor.RouteSet.IndexOf(OUTBOUNDPROXY_AS_ROUTESET_CHAR) != -1)
                {
                    var routeSet = new SIPRouteSet();
                    routeSet.PushRoute(new SIPRoute(sipCallDescriptor.RouteSet, true));
                    logger.LogDebug("Route set for call " + routeSet.ToString() + ".");
                    //lookupResult = m_sipTransport.GetURIEndPoint(routeSet.TopRoute.URI, false);
                    lookupResult = await m_sipTransport.ResolveSIPUriAsync(routeSet.TopRoute.URI).ConfigureAwait(false);
                }
                else
                {
                    logger.LogDebug("SIPClientUserAgent attempting to resolve " + callURI.Host + ".");
                    //lookupResult = m_sipTransport.GetURIEndPoint(callURI, false);
                    DateTime lookupStartedAt = DateTime.Now;
                    lookupResult = await m_sipTransport.ResolveSIPUriAsync(callURI).ConfigureAwait(false);

                    lookupDurationMilliseconds = DateTime.Now.Subtract(lookupStartedAt).TotalMilliseconds;
                }

                if (lookupResult == null)
                {
                    logger.LogDebug($"SIPClientUserAgent DNS failure resolving {callURI.Host} in {lookupDurationMilliseconds:0.##}ms. Call cannot proceed.");
                }
                else
                {
                    logger.LogDebug($"SIPClientUserAgent resolved {callURI.Host} to {lookupResult} in {lookupDurationMilliseconds:0.##}ms.");
                    serverEndPoint = lookupResult;
                }
            }

            return(serverEndPoint);
        }
        /// <summary>
        /// Sends the SIP INVITE probe request.
        /// </summary>
        public void SendProbe()
        {
            try
            {
                if (WorkerProcess == null)
                {
                    logger.Debug("When attempting to send probe the worker process was null. Marking for immediate restart.");
                    NeedsImmediateRestart = true;
                }
                else if (WorkerProcess.HasExited)
                {
                    logger.Debug("When attempting to send probe the worker had exited. Marking for immediate restart.");
                    NeedsImmediateRestart = true;
                }
                else if (m_probeUAC != null && !m_probeUAC.IsUACAnswered)
                {
                    // A probe call has timed out.
                    m_probeUAC.Cancel();
                    m_missedProbes++;
                    if (m_missedProbes >= m_missedProbesLimit)
                    {
                        logger.Warn(m_missedProbes + " probes missed for " + AppServerEndpoint.ToString() + ". Marking for immediate restart.");
                        NeedsImmediateRestart = true;
                    }
                }

                if(!NeedsImmediateRestart && !NeedsToRestart)
                {
                    m_probeCount++;
                    //logger.Debug("Sending probe " + m_probeCount + " to " + AppServerEndpoint.GetIPEndPoint().ToString() + ".");
                    DateTime probeSentAt = DateTime.Now;

                    SIPCallDescriptor callDescriptor = new SIPCallDescriptor(m_dispatcherUsername, null, "sip:" + m_dispatcherUsername + "@" + AppServerEndpoint.GetIPEndPoint().ToString(),
                                       "sip:" + m_dispatcherUsername + "@sipcalldispatcher", "sip:" + AppServerEndpoint.GetIPEndPoint().ToString(), null, null, null, SIPCallDirection.Out, null, null, null);
                    m_probeUAC = new SIPClientUserAgent(m_sipTransport, null, null, null, null);

                    m_probeUAC.CallAnswered += (call, sipResponse) =>
                    {
                        //logger.Debug("Probe response received for " + AppServerEndpoint.ToString() + ".");
                        if (sipResponse.Status != SIPResponseStatusCodesEnum.BadExtension)
                        //if (sipResponse.Status != SIPResponseStatusCodesEnum.InternalServerError)
                        {
                            logger.Warn("Probe to " + AppServerEndpoint.ToString() + " answered incorrectly on probe number " + m_probeCount + " after "
                                    + DateTime.Now.Subtract(probeSentAt).TotalSeconds.ToString("0.##") + "s, unexpected response of " + ((int)sipResponse.StatusCode) + ".");
                            NeedsImmediateRestart = true;
                        }
                        else
                        {
                            m_gotInitialProbeResponse = true;
                        }

                        if (m_initialResponseMRE != null)
                        {
                            m_initialResponseMRE.Set();
                        }
                    };

                    m_probeUAC.Call(callDescriptor);
                }
            }
            catch (Exception excp)
            {
                logger.Error("Exception SendProbe. " + excp.Message);
            }
        }
        /// <summary>
        /// Sends the SIP INVITE probe request.
        /// </summary>
        private void ProbeWorker(SIPAppServerWorker worker, bool isInitialProbe)
        {
            try
            {
                if (isInitialProbe)
                {
                    worker.InitialProbeCount++;
                }

                int workerProcessID = worker.WorkerProcess.Id;
                SIPEndPoint workerEndPoint = worker.AppServerEndpoint;
                DateTime probeSentAt = DateTime.Now;
                SIPCallDescriptor callDescriptor = new SIPCallDescriptor(m_dispatcherUsername, null, "sip:" + m_dispatcherUsername + "@" + workerEndPoint.GetIPEndPoint().ToString(),
                                   "sip:" + m_dispatcherUsername + "@sipcalldispatcher", "sip:" + workerEndPoint.GetIPEndPoint().ToString(), null, null, null, SIPCallDirection.Out, null, null, null);
                SIPClientUserAgent uac = new SIPClientUserAgent(m_sipTransport, null, null, null, null);

                uac.CallFailed += (failedUAC, errorMessage) =>
                {
                    AppServerCallFailed(failedUAC, errorMessage, workerProcessID, probeSentAt, isInitialProbe);
                };

                uac.CallAnswered += (call, sipResponse) =>
                {
                    if (sipResponse.Status != SIPResponseStatusCodesEnum.BadExtension)
                    {
                        //logger.Warn("Probe call answered with unexpected response code of " + sipResponse.StatusCode + ".");
                        AppServerCallFailed(call, "Unexpected response of " + ((int)sipResponse.StatusCode) + " on probe call.", workerProcessID, probeSentAt, isInitialProbe);
                    }
                    else
                    {
                        AppServerCallSucceeded(call);
                    }
                };

                uac.Call(callDescriptor);
            }
            catch (Exception excp)
            {
                logger.Error("Exception SIPAppServerManager ProberWorker. " + excp.Message);
            }
        }
        //private void ByeFinalResponseReceived(IPEndPoint localEndPoint, IPEndPoint remoteEndPoint, SIPTransaction sipTransaction, SIPResponse sipResponse)
        //{
        //    Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentClient, SIPMonitorEventTypesEnum.DialPlan, "BYE response " + sipResponse.StatusCode + " " + sipResponse.ReasonPhrase + ".", Owner));
        //}
        private SIPRequest GetInviteRequest(SIPCallDescriptor sipCallDescriptor, string branchId, string callId, SIPEndPoint localSIPEndPoint, SIPRouteSet routeSet, string content, string contentType)
        {
            SIPRequest inviteRequest = new SIPRequest(SIPMethodsEnum.INVITE, sipCallDescriptor.Uri);
            inviteRequest.LocalSIPEndPoint = localSIPEndPoint;

            SIPHeader inviteHeader = new SIPHeader(sipCallDescriptor.GetFromHeader(), SIPToHeader.ParseToHeader(sipCallDescriptor.To), 1, callId);

            inviteHeader.From.FromTag = CallProperties.CreateNewTag();

            // For incoming calls forwarded via the dial plan the username needs to go into the Contact header.
            inviteHeader.Contact = new List<SIPContactHeader>() { new SIPContactHeader(null, new SIPURI(inviteRequest.URI.Scheme, localSIPEndPoint)) };
            inviteHeader.Contact[0].ContactURI.User = sipCallDescriptor.Username;
            inviteHeader.CSeqMethod = SIPMethodsEnum.INVITE;
            inviteHeader.UserAgent = m_userAgent;
            inviteHeader.Routes = routeSet;
            inviteRequest.Header = inviteHeader;

            if (!sipCallDescriptor.ProxySendFrom.IsNullOrBlank())
            {
                inviteHeader.ProxySendFrom = sipCallDescriptor.ProxySendFrom;
            }

            SIPViaHeader viaHeader = new SIPViaHeader(localSIPEndPoint, branchId);
            inviteRequest.Header.Vias.PushViaHeader(viaHeader);

            inviteRequest.Body = content;
            inviteRequest.Header.ContentLength = (inviteRequest.Body != null) ? inviteRequest.Body.Length : 0;
            inviteRequest.Header.ContentType = contentType;

            // Add custom switchboard headers.
            if (CallDescriptor.SwitchboardHeaders != null)
            {
                inviteHeader.SwitchboardOriginalCallID = CallDescriptor.SwitchboardHeaders.SwitchboardOriginalCallID;
                //inviteHeader.SwitchboardCallerDescription = CallDescriptor.SwitchboardHeaders.SwitchboardCallerDescription;
                inviteHeader.SwitchboardLineName = CallDescriptor.SwitchboardHeaders.SwitchboardLineName;
                //inviteHeader.SwitchboardOwner = CallDescriptor.SwitchboardHeaders.SwitchboardOwner;
                //inviteHeader.SwitchboardOriginalFrom = CallDescriptor.SwitchboardHeaders.SwitchboardOriginalFrom;
            }

            // Add custom CRM headers.
            if (CallDescriptor.CRMHeaders != null)
            {
                inviteHeader.CRMPersonName = CallDescriptor.CRMHeaders.PersonName;
                inviteHeader.CRMCompanyName = CallDescriptor.CRMHeaders.CompanyName;
                inviteHeader.CRMPictureURL = CallDescriptor.CRMHeaders.AvatarURL;
            }

            try
            {
                if (sipCallDescriptor.CustomHeaders != null && sipCallDescriptor.CustomHeaders.Count > 0)
                {
                    foreach (string customHeader in sipCallDescriptor.CustomHeaders)
                    {
                        if (customHeader.IsNullOrBlank())
                        {
                            continue;
                        }
                        else if (customHeader.Trim().StartsWith(SIPHeaders.SIP_HEADER_USERAGENT))
                        {
                            inviteRequest.Header.UserAgent = customHeader.Substring(customHeader.IndexOf(":") + 1).Trim();
                        }
                        else
                        {
                            inviteRequest.Header.UnknownHeaders.Add(customHeader);
                        }
                    }
                }
            }
            catch (Exception excp)
            {
                logger.Error("Exception Parsing CustomHeader for GetInviteRequest. " + excp.Message + sipCallDescriptor.CustomHeaders);
            }

            return inviteRequest;
        }
        public void Call(SIPCallDescriptor sipCallDescriptor)
        {
            try
            {
                m_sipCallDescriptor = sipCallDescriptor;
                SIPURI callURI = SIPURI.ParseSIPURI(sipCallDescriptor.Uri);
                SIPRouteSet routeSet = null;

                if (!m_callCancelled)
                {
                    // 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))
                    {
                        m_serverEndPoint = m_outboundProxy;
                    }
                    else if (!sipCallDescriptor.ProxySendFrom.IsNullOrBlank())
                    {
                        // 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.
                        SIPEndPoint outboundProxyEndPoint = SIPEndPoint.ParseSIPEndPoint(sipCallDescriptor.ProxySendFrom);
                        m_outboundProxy = new SIPEndPoint(SIPProtocolsEnum.udp, new IPEndPoint(outboundProxyEndPoint.Address, m_defaultSIPPort));
                        m_serverEndPoint = m_outboundProxy;
                        Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentClient, SIPMonitorEventTypesEnum.DialPlan, "SIPClientUserAgent Call using alternate outbound proxy of " + m_outboundProxy + ".", Owner));
                    }
                    else if (m_outboundProxy != null)
                    {
                        // Using the system outbound proxy only, no additional user routing requirements.
                        m_serverEndPoint = m_outboundProxy;
                    }

                    // 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
                        {
                            Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentClient, SIPMonitorEventTypesEnum.DialPlan, "Error an outbound proxy value was not recognised in SIPClientUserAgent Call. " + m_sipCallDescriptor.RouteSet + ".", Owner));
                        }
                    }

                    // No outbound proxy, determine the forward destination based on the SIP request.
                    if (m_serverEndPoint == null)
                    {
                        SIPDNSLookupResult lookupResult = null;

                        if (routeSet == null || routeSet.Length == 0)
                        {
                            Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentClient, SIPMonitorEventTypesEnum.DialPlan, "Attempting to resolve " + callURI.Host + ".", Owner));
                            lookupResult = m_sipTransport.GetURIEndPoint(callURI, false);
                        }
                        else
                        {
                            Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentClient, SIPMonitorEventTypesEnum.DialPlan, "Route set for call " + routeSet.ToString() + ".", Owner));
                            lookupResult = m_sipTransport.GetURIEndPoint(routeSet.TopRoute.URI, false);
                        }

                        if (lookupResult.LookupError != null)
                        {
                            Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentClient, SIPMonitorEventTypesEnum.DialPlan, "DNS error resolving " + callURI.Host + ", " + lookupResult.LookupError + ". Call cannot proceed.", Owner));
                        }
                        else
                        {
                            m_serverEndPoint = lookupResult.GetSIPEndPoint();
                        }
                    }

                    if (m_callCancelled)
                    {
                        Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentClient, SIPMonitorEventTypesEnum.DialPlan, "Call was cancelled during DNS resolution of " + callURI.Host, Owner));
                        FireCallFailed(this, "Cancelled by caller");
                    }
                    else if (m_serverEndPoint != null)
                    {
                        Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentClient, SIPMonitorEventTypesEnum.DialPlan, "Switching to " + SIPURI.ParseSIPURI(m_sipCallDescriptor.Uri).CanonicalAddress + " via " + m_serverEndPoint + ".", Owner));

                        m_localSIPEndPoint = m_sipTransport.GetDefaultSIPEndPoint(m_serverEndPoint);
                        if (m_localSIPEndPoint == null)
                        {
                            throw new ApplicationException("The call could not locate an appropriate SIP transport channel for protocol " + callURI.Protocol + ".");
                        }

                        string content = sipCallDescriptor.Content;

                        if (content.IsNullOrBlank())
                        {
                            Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Body on UAC call was empty.", Owner));
                        }
                        else if (m_sipCallDescriptor.ContentType == m_sdpContentType)
                        {
                            if (!m_sipCallDescriptor.MangleResponseSDP)
                            {
                                IPEndPoint sdpEndPoint = SDP.GetSDPRTPEndPoint(content);
                                if (sdpEndPoint != null)
                                {
                                    Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "SDP on UAC call was set to NOT mangle, RTP socket " + sdpEndPoint.ToString() + ".", Owner));
                                }
                                else
                                {
                                    Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "SDP on UAC call was set to NOT mangle, RTP socket could not be determined.", Owner));
                                }
                            }
                            else
                            {
                                IPEndPoint sdpEndPoint = SDP.GetSDPRTPEndPoint(content);
                                if (sdpEndPoint != null)
                                {
                                    if (!IPSocket.IsPrivateAddress(sdpEndPoint.Address.ToString()))
                                    {
                                        Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "SDP on UAC call had public IP not mangled, RTP socket " + sdpEndPoint.ToString() + ".", Owner));
                                    }
                                    else
                                    {
                                        bool wasSDPMangled = false;
                                        if (sipCallDescriptor.MangleIPAddress != null)
                                        {
                                            if (sdpEndPoint != null)
                                            {
                                                content = SIPPacketMangler.MangleSDP(content, sipCallDescriptor.MangleIPAddress.ToString(), out wasSDPMangled);
                                            }
                                        }

                                        if (wasSDPMangled)
                                        {
                                            Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "SDP on UAC call had RTP socket mangled from " + sdpEndPoint.ToString() + " to " + sipCallDescriptor.MangleIPAddress.ToString() + ":" + sdpEndPoint.Port + ".", Owner));
                                        }
                                        else if (sdpEndPoint != null)
                                        {
                                            Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "SDP on UAC could not be mangled, using original RTP socket of " + sdpEndPoint.ToString() + ".", Owner));
                                        }
                                    }
                                }
                                else
                                {
                                    Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "SDP RTP socket on UAC call could not be determined.", Owner));
                                }
                            }
                        }

                        SIPRequest switchServerInvite = GetInviteRequest(m_sipCallDescriptor, CallProperties.CreateBranchId(), CallProperties.CreateNewCallId(), m_localSIPEndPoint, routeSet, content, sipCallDescriptor.ContentType);

                        // Now that we have a destination socket create a new UAC transaction for forwarded leg of the call.
                        m_serverTransaction = m_sipTransport.CreateUACTransaction(switchServerInvite, m_serverEndPoint, m_localSIPEndPoint, m_outboundProxy);
                        m_serverTransaction.CDR.DialPlanContextID = m_sipCallDescriptor.DialPlanContextID;

                        #region Real-time call control processing.

                        string rtccError = null;

                        if (m_serverTransaction.CDR != null)
                        {
                            m_serverTransaction.CDR.Owner = Owner;
                            m_serverTransaction.CDR.AdminMemberId = AdminMemberId;

                            m_serverTransaction.CDR.Updated();

            #if !SILVERLIGHT && !MIN_BUILD

                            if (m_sipCallDescriptor.AccountCode != null)
                            {
                                var customerAccount = m_customerAccountDataLayer.CheckAccountCode(Owner, m_sipCallDescriptor.AccountCode);

                                if (customerAccount == null)
                                {
                                    Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "A billable call could not proceed as no account exists for account code or number " + m_sipCallDescriptor.AccountCode + ".", Owner));
                                    rtccLogger.Debug("A billable call could not proceed as no account exists for account code or number " + m_sipCallDescriptor.AccountCode + " and owner " + Owner + ".");
                                    rtccError = "Real-time call control invalid account code";
                                }
                                else
                                {
                                    AccountCode = customerAccount.AccountCode;

                                    string rateDestination = m_sipCallDescriptor.Uri;
                                    if (SIPURI.TryParse(m_sipCallDescriptor.Uri))
                                    {
                                        rateDestination = SIPURI.ParseSIPURIRelaxed(m_sipCallDescriptor.Uri).User;
                                    }

                                    var rate = m_customerAccountDataLayer.GetRate(Owner, m_sipCallDescriptor.RateCode, rateDestination, customerAccount.RatePlan);

                                    if (rate == null)
                                    {
                                        Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "A billable call could not proceed as no rate could be determined for destination " + rateDestination + ".", Owner));
                                        rtccLogger.Debug("A billable call could not proceed as no rate could be determined for destination " + rateDestination + " and owner " + Owner + ".");
                                        rtccError = "Real-time call control no rate";
                                    }
                                    else
                                    {
                                        Rate = rate.Rate1;

                                        if (rate.Rate1 == 0 && rate.SetupCost == 0)
                                        {
                                            Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "The rate and setup cost for the " + rateDestination + "were both zero. The call will be allowed to proceed with no RTCC reservation.", Owner));
                                        }
                                        else
                                        {
                                            decimal balance = m_customerAccountDataLayer.GetBalance(AccountCode);

                                            if (balance < Rate)
                                            {
                                                Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "A billable call could not proceed as the available credit for " + AccountCode + " was not sufficient for 60 seconds to destination " + rateDestination + ".", Owner));
                                                rtccLogger.Debug("A billable call could not proceed as the available credit for " + AccountCode + " was not sufficient for 60 seconds to destination " + rateDestination + " and owner " + Owner + ".");
                                                rtccError = "Real-time call control insufficient credit";
                                            }
                                            else
                                            {
                                                int intialSeconds = 0;
                                                var reservationCost = m_customerAccountDataLayer.ReserveInitialCredit(AccountCode, rate, m_serverTransaction.CDR, out intialSeconds);

                                                if (reservationCost == Decimal.MinusOne)
                                                {
                                                    Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Call will not proceed as the intial real-time call control credit reservation failed.", Owner));
                                                    rtccLogger.Debug("Call will not proceed as the intial real-time call control credit reservation failed for owner " + Owner + ".");
                                                    rtccError = "Real-time call control initial reservation failed";
                                                }
                                                else
                                                {
                                                    ReservedCredit = reservationCost;
                                                    ReservedSeconds = intialSeconds;
                                                }
                                            }
                                        }
                                    }
                                }
                            }
            #endif

                        }

                        // If this is a billable call attempt to reserve the first chunk of credit.
                        //if (m_serverTransaction.CDR != null && AccountCode.NotNullOrBlank())
                        //{
                        //    m_serverTransaction.CDR.AccountCode = AccountCode;
                        //    m_serverTransaction.CDR.Rate = Rate;
                        //    //m_serverTransaction.CDR.Cost = ReservedCredit;
                        //    //m_serverTransaction.CDR.SecondsReserved = ReservedSeconds;

                        //    var reservationCost = m_customerAccountDataLayer.ReserveInitialCredit(AccountCode, Rate, m_rtccInitialReservationSeconds);

                        //    if (reservationCost == Decimal.MinusOne)
                        //    {
                        //        Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Call will not proceed as the intial real-time call control credit reservation failed.", Owner));
                        //    }
                        //    else
                        //    {
                        //        m_serverTransaction.CDR.SecondsReserved = m_rtccInitialReservationSeconds;
                        //        m_serverTransaction.CDR.Cost = reservationCost;
                        //    }
                        //}

                        #endregion

                        if (rtccError == null)
                        {
                            m_serverTransaction.UACInviteTransactionInformationResponseReceived += ServerInformationResponseReceived;
                            m_serverTransaction.UACInviteTransactionFinalResponseReceived += ServerFinalResponseReceived;
                            m_serverTransaction.UACInviteTransactionTimedOut += ServerTimedOut;
                            m_serverTransaction.TransactionTraceMessage += TransactionTraceMessage;

                            m_serverTransaction.SendInviteRequest(m_serverEndPoint, m_serverTransaction.TransactionRequest);
                        }
                        else
                        {
                            m_serverTransaction.CancelCall(rtccError);
                            FireCallFailed(this, rtccError);
                        }
                    }
                    else
                    {
                        if (routeSet == null || routeSet.Length == 0)
                        {
                            Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentClient, SIPMonitorEventTypesEnum.DialPlan, "Forward leg failed, could not resolve URI host " + callURI.Host, Owner));
                            m_serverTransaction.CancelCall("Unresolvable destination " + callURI.Host);
                            FireCallFailed(this, "unresolvable destination " + callURI.Host);
                        }
                        else
                        {
                            Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentClient, SIPMonitorEventTypesEnum.DialPlan, "Forward leg failed, could not resolve top Route host " + routeSet.TopRoute.Host, Owner));
                            m_serverTransaction.CancelCall("Unresolvable destination " + routeSet.TopRoute.Host);
                            FireCallFailed(this, "unresolvable destination " + routeSet.TopRoute.Host);
                        }
                    }
                }
            }
            catch (ApplicationException appExcp)
            {
                if (m_serverTransaction != null)
                {
                    m_serverTransaction.CancelCall(appExcp.Message);
                }

                FireCallFailed(this, appExcp.Message);
            }
            catch (Exception excp)
            {
                Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.UserAgentClient, SIPMonitorEventTypesEnum.DialPlan, "Exception UserAgentClient Call. " + excp.Message, Owner));

                if (m_serverTransaction != null)
                {
                    m_serverTransaction.CancelCall("Unknown exception");
                }

                FireCallFailed(this, excp.Message);
            }
        }
Example #29
0
        private void StartNewCallSync(SIPCallDescriptor callDescriptor)
        {
            try
            {
                // A call will not be delayed if there are no other calls being attempted.
                if (callDescriptor.DelaySeconds != 0 && m_switchCalls.Count > 0)
                {
                    callDescriptor.DelayMRE = new ManualResetEvent(false);
                    lock (m_delayedCalls)
                    {
                        m_delayedCalls.Add(callDescriptor);
                    }

                    int delaySeconds = (callDescriptor.DelaySeconds > MAX_DELAY_SECONDS) ? MAX_DELAY_SECONDS : callDescriptor.DelaySeconds;
                    FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Delaying call leg to " + callDescriptor.Uri + " by " + delaySeconds + "s.", m_username));
                    callDescriptor.DelayMRE.WaitOne(delaySeconds * 1000);
                }

                lock (m_delayedCalls)
                {
                    m_delayedCalls.Remove(callDescriptor);
                }

                if (!m_callAnswered && !m_commandCancelled)
                {
                    ISIPClientUserAgent uacCall = null;

                    if (callDescriptor.ToSIPAccount == null)
                    {
                        if (callDescriptor.IsGoogleVoiceCall)
                        {
                            FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Creating Google Voice user agent for " + callDescriptor.Uri + ".", m_username));
                            uacCall = new GoogleVoiceUserAgent(m_sipTransport, m_callManager, m_statefulProxyLogEvent, m_username, m_adminMemberId, m_outboundProxySocket);
                        }
                        else
                        {
                            uacCall = new SIPClientUserAgent(m_sipTransport, m_outboundProxySocket, m_username, m_adminMemberId, m_statefulProxyLogEvent);
                        }
                    }
                    else
                    {
                        FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Creating B2B call for " + callDescriptor.Uri + ".", m_username));
                        uacCall = new SIPB2BUserAgent(m_statefulProxyLogEvent, QueueNewCall_External, m_sipTransport, m_username, m_adminMemberId);
                    }

                    //ISIPClientUserAgent uacCall = new JingleUserAgent(m_username, m_adminMemberId, m_statefulProxyLogEvent);

                    lock (m_switchCalls)
                    {
                        m_switchCalls.Add(uacCall);
                    }

                    uacCall.CallAnswered += UACCallAnswered;
                    uacCall.CallFailed += UACCallFailed;
                    uacCall.CallRinging += UACCallProgress;
                    //uacCall.CallTrying += UACCallTrying;

                    uacCall.Call(callDescriptor);
                }
            }
            catch (Exception excp)
            {
                logger.Error("Exception ForkCall StartNewCall. " + excp.Message);
            }
        }
        public void Call(SIPCallDescriptor sipCallDescriptor)
        {
            try
            {
                m_uacCallDescriptor = sipCallDescriptor;
                SIPRequest uacInviteRequest = GetInviteRequest(m_uacCallDescriptor.Uri, sipCallDescriptor.GetFromHeader());
                if (sipCallDescriptor.MangleResponseSDP && sipCallDescriptor.MangleIPAddress != null)
                {
                    uacInviteRequest.Header.ProxyReceivedFrom = sipCallDescriptor.MangleIPAddress.ToString();
                }
                uacInviteRequest.Body = sipCallDescriptor.Content;
                uacInviteRequest.Header.ContentType = sipCallDescriptor.ContentType;
                uacInviteRequest.LocalSIPEndPoint = m_blackhole;
                uacInviteRequest.RemoteSIPEndPoint = m_blackhole;

                // Now that we have a destination socket create a new UAC transaction for forwarded leg of the call.
                m_uacTransaction = m_sipTransport.CreateUACTransaction(uacInviteRequest, m_blackhole, m_blackhole, null);
                if (m_uacTransaction.CDR != null)
                {
                    m_uacTransaction.CDR.Owner = m_uacOwner;
                    m_uacTransaction.CDR.AdminMemberId = m_uacAdminMemberId;
                }

                //uacTransaction.UACInviteTransactionInformationResponseReceived += ServerInformationResponseReceived;
                //uacTransaction.UACInviteTransactionFinalResponseReceived += ServerFinalResponseReceived;
                //uacTransaction.UACInviteTransactionTimedOut += ServerTimedOut;
                //uacTransaction.TransactionTraceMessage += TransactionTraceMessage;

                m_uacTransaction.SendInviteRequest(m_blackhole, m_uacTransaction.TransactionRequest);

                SIPRequest uasInviteRequest = uacInviteRequest.Copy();
                uasInviteRequest.LocalSIPEndPoint = m_blackhole;
                uasInviteRequest.RemoteSIPEndPoint = m_blackhole;
                uasInviteRequest.Header.Vias.TopViaHeader.Branch = CallProperties.CreateBranchId();
                m_uasTransaction = m_sipTransport.CreateUASTransaction(uasInviteRequest, m_blackhole, m_blackhole, null);

                SetOwner(sipCallDescriptor.ToSIPAccount.Owner, sipCallDescriptor.ToSIPAccount.AdminMemberId);
                //m_uasTransaction.TransactionTraceMessage += TransactionTraceMessage;
                //m_uasTransaction.UASInviteTransactionTimedOut += ClientTimedOut;
                //m_uasTransaction.UASInviteTransactionCancelled += (t) => { };

                QueueNewCall_External(this);
            }
            catch (Exception excp)
            {
                logger.Error("Exception SIPB2BUserAgent Call. " + excp.Message);
            }
        }
        public SIPCallDescriptor CopyOf()
        {
            List<string> copiedCustomHeaders = null;
            if (CustomHeaders != null)
            {
                copiedCustomHeaders = new List<string>();
                copiedCustomHeaders.InsertRange(0, CustomHeaders);
            }

            SIPCallDescriptor copy = new SIPCallDescriptor(
                Username,
                Password,
                Uri,
                From,
                To,
                RouteSet,
                copiedCustomHeaders,
                AuthUsername,
                CallDirection,
                ContentType,
                Content,
                (MangleIPAddress != null) ? new IPAddress(MangleIPAddress.GetAddressBytes()) : null);

            // Options.
            copy.DelaySeconds = DelaySeconds;
            copy.RedirectMode = RedirectMode;
            copy.CallDurationLimit = CallDurationLimit;
            copy.MangleResponseSDP = MangleResponseSDP;
            copy.FromDisplayName = FromDisplayName;
            copy.FromURIUsername = FromURIUsername;
            copy.FromURIHost = FromURIHost;
            copy.TransferMode = TransferMode;

            copy.ToSIPAccount = ToSIPAccount;

            return copy;
        }
        private void ProbeWorkers() {
            try {

                while (!m_exit) {

                    try {
                        SIPEndPoint activeWorkerEndPoint = GetFirstHealthyEndPoint();
                        SIPCallDescriptor callDescriptor = new SIPCallDescriptor(m_dispatcherUsername, null, "sip:" + m_dispatcherUsername + "@" + activeWorkerEndPoint.SocketEndPoint.ToString(),
                                "sip:" + m_dispatcherUsername + "@sipcalldispatcher", "sip:" + activeWorkerEndPoint.SocketEndPoint.ToString(), null, null, null, SIPCallDirection.Out, null, null, null);
                        SIPClientUserAgent uac = new SIPClientUserAgent(m_sipTransport, null, null, null, null);
                        uac.CallAnswered += DispatcherCallAnswered;
                        uac.CallFailed += new SIPCallFailedDelegate(DispatcherCallFailed);
                        uac.Call(callDescriptor);
                    }
                    catch (Exception probeExcp) {
                        dispatcherLogger.Error("Exception SIPCallDispatcher Sending Probe. " + probeExcp.Message);
                    }

                    Thread.Sleep(PROBE_WORKER_CALL_PERIOD);
                }
            }
            catch (Exception excp) {
                logger.Error("Exception SIPCallDispatcher ProberWorkers. " + excp.Message);
            }
        }
        /// <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 #34
0
        /// <summary>
        /// Places an outgoing SIP call.
        /// </summary>
        /// <param name="destination">The SIP URI to place a call to. The destination can be a full SIP URI in which case the all will
        /// be placed anonymously directly to that URI. Alternatively it can be just the user portion of a URI in which case it will
        /// be sent to the configured SIP server.</param>
        public void Call(MediaManager mediaManager, string destination)
        {
            _mediaManager = mediaManager;
            _mediaManager.NewCall();

            // Determine if this is a direct anonymous call or whether it should be placed using the pre-configured SIP server account.
            SIPURI callURI = null;
            string sipUsername = null;
            string sipPassword = null;
            string fromHeader = null;

            if (destination.Contains("@") || m_sipServer == null)
            {
                // Anonymous call direct to SIP server specified in the URI.
                callURI = SIPURI.ParseSIPURIRelaxed(destination);
            }
            else
            {
                // This call will use the pre-configured SIP account.
                callURI = SIPURI.ParseSIPURIRelaxed(destination + "@" + m_sipServer);
                sipUsername = m_sipUsername;
                sipPassword = m_sipPassword;
                fromHeader = (new SIPFromHeader(m_sipFromName, new SIPURI(m_sipUsername, m_sipServer, null), null)).ToString();
            }

            StatusMessage("Starting call to " + callURI.ToString() + ".");

            m_uac = new SIPClientUserAgent(m_sipTransport, null, null, null, null);
            m_uac.CallTrying += CallTrying;
            m_uac.CallRinging += CallRinging;
            m_uac.CallAnswered += CallAnswered;
            m_uac.CallFailed += CallFailed;

            // Get the SDP requesting that the public IP address be used if the host on the call destination is not a private IP address.
            SDP sdp = _mediaManager.GetSDP(!(IPSocket.IsIPAddress(callURI.Host) && IPSocket.IsPrivateAddress(callURI.Host)));
            System.Diagnostics.Debug.WriteLine(sdp.ToString());
            SIPCallDescriptor callDescriptor = new SIPCallDescriptor(sipUsername, sipPassword, callURI.ToString(), fromHeader, null, null, null, null, SIPCallDirection.Out, _sdpMimeContentType, sdp.ToString(), null);
            m_uac.Call(callDescriptor);
        }
        public void Call(SIPCallDescriptor descriptor)
        {
            try
            {
                CallDescriptor = descriptor;
                SIPURI destinationURI = SIPURI.ParseSIPURIRelaxed(descriptor.Uri);

                bool wasSDPMangled = false;
                IPEndPoint sdpEndPoint = null;
                if (descriptor.MangleIPAddress != null)
                {
                    sdpEndPoint = SDP.GetSDPRTPEndPoint(descriptor.Content);
                    if (sdpEndPoint != null)
                    {
                        descriptor.Content = SIPPacketMangler.MangleSDP(descriptor.Content, descriptor.MangleIPAddress.ToString(), out wasSDPMangled);
                    }
                }

                if (wasSDPMangled)
                {
                    Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "SDP on Google Voice call had RTP socket mangled from " + sdpEndPoint.ToString() + " to " + descriptor.MangleIPAddress.ToString() + ":" + sdpEndPoint.Port + ".", Owner));
                }
                else if (sdpEndPoint != null)
                {
                    Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "SDP on Google Voice call could not be mangled, using original RTP socket of " + sdpEndPoint.ToString() + ".", Owner));
                }

                SIPDialogue = m_googleVoiceCall.InitiateCall(descriptor.Username, descriptor.Password, descriptor.CallbackNumber, destinationURI.User, descriptor.CallbackPattern, descriptor.CallbackPhoneType, MAX_CALLBACK_WAIT_TIME, descriptor.ContentType, descriptor.Content);

                if (SIPDialogue != null)
                {
                    CallAnswered(this, null);
                }
                else
                {
                    CallFailed(this, "Google Voice call failed.");
                }
            }
            catch (Exception excp)
            {
                logger.Error("Exception GoogleVoiceCallAgent Call. " + excp.Message);
                CallFailed(this, excp.Message);
            }
        }
        /// <summary>
        /// Builds the call list based on the original dial plan SwitchCall format. This will result in only a single call leg with a single forward
        /// destination. Examples of the dial string in a dial plan command are:
        ///
        /// exten = number,priority,Switch(username,password,new number[,From[,SendTo[,Trace]]]) 
        ///  or
        /// sys.Dial("username,password,${dst}@provider")
        /// </summary>
        private SIPCallDescriptor ParseAsteriskDialString(string data, SIPRequest sipRequest)
        {
            try
            {
                string username = null;
                string password = null;
                string sendToSocket = null;
                bool traceReqd = false;
                string forwardURIStr = null;
                string fromHeaderStr = null;
                SIPURI forwardURI = null;

                string[] dataFields = data.Split(new char[] { ',' });

                username = dataFields[0].Trim().Trim(new char[] { '"', '\'' });
                password = dataFields[1].Trim().Trim(new char[] { '"', '\'' });
                forwardURIStr = dataFields[2].Trim().Trim(new char[] { '"', '\'' });

                if (dataFields.Length > 3 && dataFields[3] != null)
                {
                    fromHeaderStr = dataFields[3].Trim();
                }

                if (dataFields.Length > 4 && dataFields[4] != null)
                {
                    sendToSocket = dataFields[4].Trim().Trim(new char[] { '"', '\'' });
                }

                if (dataFields.Length > 5 && dataFields[5] != null)
                {
                    Boolean.TryParse(dataFields[5].Trim(), out traceReqd);
                }

                forwardURI = SIPURI.ParseSIPURIRelaxed(SubstituteRequestVars(sipRequest, forwardURIStr));
                if (forwardURI != null)
                {
                    if (forwardURI.User == null)
                    {
                        forwardURI.User = sipRequest.URI.User;
                    }

                    SIPFromHeader callFromHeader = ParseFromHeaderOption(fromHeaderStr, sipRequest, username, forwardURI.Host);
                    string socket = (sendToSocket != null && sendToSocket.Trim().Length > 0) ? sendToSocket : null;
                    string content = sipRequest.Body;
                    string remoteUAStr = sipRequest.Header.ProxyReceivedFrom;
                    SIPEndPoint remoteUAAddress = (!remoteUAStr.IsNullOrBlank()) ? SIPEndPoint.ParseSIPEndPoint(remoteUAStr) : sipRequest.RemoteSIPEndPoint;
                    SIPCallDescriptor switchCallStruct = new SIPCallDescriptor(username, password, forwardURI.ToString(), callFromHeader.ToString(), forwardURI.ToString(), socket, null, null, SIPCallDirection.Out, sipRequest.Header.ContentType, content, remoteUAAddress.Address);

                    return switchCallStruct;
                }
                else
                {
                    logger.Warn("Could not parse SIP URI from " + forwardURIStr + " in ParseAsteriskDialString.");
                    return null;
                }
            }
            catch (Exception excp)
            {
                logger.Error("Exception ParseAsteriskDialString. " + excp.Message);
                return null;
            }
        }
        public List<SIPCallDescriptor> GetForwardsForRedirect(SIPURI redirectURI, SIPCallDescriptor callDescriptor)
        {
            Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Getting forwards for redirect to " + redirectURI.ToString() + ".", m_username));

            List<SIPCallDescriptor> redirectCalls = new List<SIPCallDescriptor>();

            string localDomain = GetCanonicalDomain_External(redirectURI.Host, false);
            if (localDomain != null)
            {
                Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Redirect is for local SIP account " + redirectURI.User + " and canonical domain " + localDomain + ", looking up bindings.", m_username));

                SIPAccount sipAccount = GetSIPAccount_External(s => s.SIPUsername == redirectURI.User && s.SIPDomain == localDomain);

                List<SIPRegistrarBinding> bindings = GetRegistrarBindings_External(b => b.SIPAccountId == sipAccount.Id, null, 0, Int32.MaxValue);

                if (bindings != null)
                {
                    Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, bindings.Count + " bindings found for local SIP account " + sipAccount.SIPUsername + "@" + sipAccount.SIPDomain + " when processing redirect.", m_username));

                    // Build list of registered contacts.
                    for (int index = 0; index < bindings.Count; index++)
                    {
                        SIPRegistrarBinding binding = bindings[index];
                        SIPURI contactURI = binding.MangledContactSIPURI;
                        SIPCallDescriptor redirectCallDescriptor = callDescriptor.CopyOf();
                        redirectCallDescriptor.Uri = contactURI.ToString();
                        redirectCalls.Add(redirectCallDescriptor);
                    }
                }
                else
                {
                    Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "No bindings were found for local SIP account " + sipAccount.SIPUsername + "@" + sipAccount.SIPDomain + " when processing redirect.", m_username));
                }
            }
            else
            {
                Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Redirect destination " + redirectURI.ToString() + " was determined as an external URI.", m_username));

                SIPCallDescriptor redirectCallDescriptor = callDescriptor.CopyOf();
                redirectCallDescriptor.Uri = redirectURI.ToString();
                redirectCalls.Add(redirectCallDescriptor);
            }

            return redirectCalls;
        }
        /// <summary>
        /// Processes dial strings using the multi-legged format. Each leg is separated from the proceeding one by the | character and each subsequent leg
        /// will only be used if all the forwards in the preceeding one fail. Within each leg the forwards are separated by the & character.
        /// 
        /// Example: 
        /// Dial(123@provider1&provider2|[email protected]|provider4&456@provider5[,trace])
        /// </summary>
        private Queue<List<SIPCallDescriptor>> ParseScriptDialString(
            SIPRequest sipRequest,
            string command,
            List<string> customHeaders,
            string customContentType,
            string customContent,
            string callersNetworkId,
            string fromDisplayName,
            string fromUsername,
            string fromHost,
            CRMHeaders contact)
        {
            try
            {
                Queue<List<SIPCallDescriptor>> callsQueue = new Queue<List<SIPCallDescriptor>>();
                string[] followonLegs = command.Split(CALLLEG_FOLLOWON_SEPARATOR);

                foreach (string followOnLeg in followonLegs)
                {
                    List<SIPCallDescriptor> switchCalls = new List<SIPCallDescriptor>();
                    string[] callLegs = followOnLeg.Split(CALLLEG_SIMULTANEOUS_SEPARATOR);

                    foreach (string callLeg in callLegs)
                    {
                        if (!callLeg.IsNullOrBlank())
                        {
                            // Strip off the options string if present.
                            string options = null;
                            string callLegDestination = callLeg;

                            int optionsStartIndex = callLeg.IndexOf(CALLLEG_OPTIONS_START_CHAR);
                            int optionsEndIndex = callLeg.IndexOf(CALLLEG_OPTIONS_END_CHAR);
                            if (optionsStartIndex != -1)
                            {
                                callLegDestination = callLeg.Substring(0, optionsStartIndex);
                                options = callLeg.Substring(optionsStartIndex, optionsEndIndex - optionsStartIndex);
                            }

                            // Determine whether the call forward is for a local domain or not.
                            SIPURI callLegSIPURI = SIPURI.ParseSIPURIRelaxed(SubstituteRequestVars(sipRequest, callLegDestination));
                            if (callLegSIPURI != null && callLegSIPURI.User == null)
                            {
                                callLegSIPURI.User = sipRequest.URI.User;
                            }

                            if (callLegSIPURI != null)
                            {
                                string localDomain = GetCanonicalDomain_External(callLegSIPURI.Host, false);
                                if (localDomain != null)
                                {
                                    SIPAccount calledSIPAccount = GetSIPAccount_External(s => s.SIPUsername == callLegSIPURI.User && s.SIPDomain == localDomain);
                                    if (calledSIPAccount == null && callLegSIPURI.User.Contains("."))
                                    {
                                        // A full lookup failed. Now try a partial lookup if the incoming username is in a dotted domain name format.
                                        string sipUsernameSuffix = callLegSIPURI.User.Substring(callLegSIPURI.User.LastIndexOf(".") + 1);
                                        calledSIPAccount = GetSIPAccount_External(s => s.SIPUsername == sipUsernameSuffix && s.SIPDomain == localDomain);
                                    }
                                    if (calledSIPAccount != null)
                                    {
                                        // An incoming dialplan won't be used if it's invoked from itself.
                                        if (calledSIPAccount.InDialPlanName.IsNullOrBlank() || (m_username == calledSIPAccount.Owner && m_dialPlanName == calledSIPAccount.InDialPlanName))
                                        {
                                            Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Call leg is for local domain looking up bindings for " + callLegSIPURI.User + "@" + localDomain + " for call leg " + callLegDestination + ".", m_username));
                                            switchCalls.AddRange(GetForwardsForLocalLeg(sipRequest, calledSIPAccount, customHeaders, customContentType, customContent, options, callersNetworkId, fromDisplayName, fromUsername, fromHost, contact));
                                        }
                                        else
                                        {
                                            // An incoming call for a SIP account that has an incoming dialplan specified.
                                            Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Call leg is for local domain forwarding to incoming dialplan for " + callLegSIPURI.User + "@" + localDomain + ".", m_username));
                                            string sipUsername = (m_sipAccount != null) ? m_sipAccount.SIPUsername : m_username;
                                            string sipDomain = (m_sipAccount != null) ? m_sipAccount.SIPDomain : GetCanonicalDomain_External(SIPDomainManager.DEFAULT_LOCAL_DOMAIN, false);
                                            SIPFromHeader fromHeader = ParseFromHeaderOption(null, sipRequest, sipUsername, sipDomain);

                                            string content = customContent;
                                            string contentType = customContentType;
                                            if (contentType.IsNullOrBlank())
                                            {
                                                contentType = sipRequest.Header.ContentType;
                                            }

                                            if (content.IsNullOrBlank())
                                            {
                                                content = sipRequest.Body;
                                            }

                                            SIPCallDescriptor loopbackCall = new SIPCallDescriptor(calledSIPAccount, callLegSIPURI.ToString(), fromHeader.ToString(), contentType, content);
                                            loopbackCall.SetGeneralFromHeaderFields(fromDisplayName, fromUsername, fromHost);
                                            loopbackCall.MangleIPAddress = (PublicIPAddress != null) ? PublicIPAddress : SIPPacketMangler.GetRequestIPAddress(sipRequest);
                                            loopbackCall.ParseCallOptions(options);
                                            switchCalls.Add(loopbackCall);
                                        }
                                    }
                                    else
                                    {
                                        Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "No sip account could be found for local call leg " + callLeg + ".", m_username));
                                    }
                                }
                                else
                                {
                                    // Construct a call forward for a remote destination.
                                    SIPCallDescriptor sipCallDescriptor = GetForwardsForExternalLeg(sipRequest, callLegSIPURI, customContentType, customContent, fromDisplayName, fromUsername, fromHost, contact);

                                    if (sipCallDescriptor != null)
                                    {
                                        // Add and provided custom headers to those already present in the call descriptor and overwrite if an existing
                                        // header is already present.
                                        if (customHeaders != null && customHeaders.Count > 0)
                                        {
                                            foreach (string customHeader in customHeaders)
                                            {
                                                string customHeaderValue = SubstituteRequestVars(sipRequest, customHeader);
                                                sipCallDescriptor.CustomHeaders.Add(customHeaderValue);
                                            }
                                        }

                                        sipCallDescriptor.ParseCallOptions(options);
                                        switchCalls.Add(sipCallDescriptor);
                                    }
                                }
                            }
                            else
                            {
                                Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Could not parse a SIP URI from " + callLeg + " in ParseMultiDialString.", m_username));
                            }
                        }
                    }

                    // Calls will not be added if the URI is already in the queue!
                    List<SIPCallDescriptor> callList = new List<SIPCallDescriptor>();
                    callsQueue.Enqueue(callList);
                    foreach (SIPCallDescriptor callToAdd in switchCalls)
                    {
                        if (!IsURIInQueue(callsQueue, callToAdd.Uri))
                        {
                            callList.Add(callToAdd);
                        }
                        else
                        {
                            Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Call leg " + callToAdd.Uri.ToString() + " already added duplicate ignored.", m_username));
                        }
                    }
                }

                return callsQueue;
            }
            catch (Exception excp)
            {
                logger.Error("Exception ParseScriptDialString. " + excp.Message);
                throw excp;
            }
        }
Example #39
0
 public SIPRequest Call(SIPCallDescriptor sipCallDescriptor)
 {
     return(Call(sipCallDescriptor, null));
 }
        /// <summary>
        /// Creates a list of calls based on the registered contacts for a user registration.
        /// </summary>
        /// <param name="user"></param>
        /// <param name="domain"></param>
        /// <param name="from">The From header that will be set on the forwarded call leg.</param>
        /// <returns></returns>
        public List<SIPCallDescriptor> GetForwardsForLocalLeg(
            SIPRequest sipRequest,
            SIPAccount sipAccount,
            List<string> customHeaders,
            string customContentType,
            string customContent,
            string options,
            string callersNetworkId,
            string fromDisplayName,
            string fromUsername,
            string fromHost,
            CRMHeaders contact)
        {
            List<SIPCallDescriptor> localUserSwitchCalls = new List<SIPCallDescriptor>();

            try
            {
                if (sipAccount == null)
                {
                    throw new ApplicationException("Cannot lookup forwards for a null SIP account.");
                }

                List<SIPRegistrarBinding> bindings = GetRegistrarBindings_External(b => b.SIPAccountId == sipAccount.Id, null, 0, Int32.MaxValue);

                if (bindings != null)
                {
                    Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, bindings.Count + " found for " + sipAccount.SIPUsername + "@" + sipAccount.SIPDomain + ".", m_username));

                    // Build list of registered contacts.
                    for (int index = 0; index < bindings.Count; index++)
                    {
                        SIPRegistrarBinding binding = bindings[index];
                        SIPURI contactURI = binding.MangledContactSIPURI;

                        // Determine the content based on a custom request, caller's network id and whether mangling is required.
                        string contentType = (sipRequest != null) ? sipRequest.Header.ContentType : null;
                        string content = (sipRequest != null) ? sipRequest.Body : null;

                        if (!customContentType.IsNullOrBlank())
                        {
                            contentType = customContentType;
                        }

                        if (!customContent.IsNullOrBlank())
                        {
                            content = customContent;
                        }

                        IPAddress publicSDPAddress = PublicIPAddress;
                        if (publicSDPAddress == null && sipRequest != null)
                        {
                            publicSDPAddress = SIPPacketMangler.GetRequestIPAddress(sipRequest);
                        }

                        string fromHeader = (sipRequest != null) ? sipRequest.Header.From.ToString() : m_anonymousFromURI;

                        SIPCallDescriptor switchCall = new SIPCallDescriptor(
                            null,
                            null,
                            contactURI.ToString(),
                            fromHeader,
                            new SIPToHeader(null, SIPURI.ParseSIPURIRelaxed(sipAccount.SIPUsername + "@" + sipAccount.SIPDomain), null).ToString(),
                            null,
                            customHeaders,
                            null,
                            SIPCallDirection.In,
                            contentType,
                            content,
                            publicSDPAddress);
                        switchCall.CRMHeaders = contact;

                        // If the binding for the call is a switchboard add the custom switchboard headers.
                        if (!sipRequest.Header.SwitchboardFrom.IsNullOrBlank())
                        {
                            switchCall.SwitchboardHeaders.SwitchboardFrom = sipRequest.Header.SwitchboardFrom;
                        }

                        // If the binding has a proxy socket defined set the header to ask the upstream proxy to use it.
                        if (binding.ProxySIPEndPoint != null)
                        {
                            switchCall.ProxySendFrom = binding.ProxySIPEndPoint.ToString();
                        }
                        switchCall.ParseCallOptions(options);
                        if (sipAccount != null && !sipAccount.NetworkId.IsNullOrBlank() && sipAccount.NetworkId == callersNetworkId)
                        {
                            switchCall.MangleResponseSDP = false;
                        }
                        switchCall.SetGeneralFromHeaderFields(fromDisplayName, fromUsername, fromHost);
                        localUserSwitchCalls.Add(switchCall);
                    }
                }
                else
                {
                    Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "No current bindings found for local SIP account " + sipAccount.SIPUsername + "@" + sipAccount.SIPDomain + ".", m_username));
                }

                return localUserSwitchCalls;
            }
            catch (Exception excp)
            {
                logger.Error("Exception GetForwardsForLocalLeg. " + excp);
                return localUserSwitchCalls;
            }
        }
        private void PlaceCall(object state)
        {
            string callURI = (string)state;

            /*m_dnsLookupComplete.Reset();
            ThreadPool.QueueUserWorkItem(new WaitCallback(DNSLookup), callURI);
            if (!m_dnsLookupComplete.WaitOne(DNS_LOOKUP_TIMEOUT)) {
                AppendTraceMessage("DNS lookup for " + callURI + " timed out.\n");
                ResetToCallStartState();
            }
            else {*/
                AppendTraceMessage("Starting call to " + callURI + ".\n");
                m_uac = new SIPClientUserAgent(m_sipTransport, null, null, null, LogTraceMessage);
                m_uac.CallTrying += CallTrying;
                m_uac.CallRinging += CallRinging;
                m_uac.CallAnswered += CallAnswered;
                m_uac.CallFailed += CallFailed;
                SIPCallDescriptor callDescriptor = new SIPCallDescriptor("anonymous", null, callURI, null, null, null, null, null, SIPCallDirection.Out, null, null, null);
                m_uac.Call(callDescriptor);
            //}
        }
        /// <summary>
        /// Can't be used for local destinations!
        /// </summary>
        /// <param name="sipRequest"></param>
        /// <param name="command"></param>
        /// <returns></returns>
        private SIPCallDescriptor GetForwardsForExternalLeg(
            SIPRequest sipRequest,
            SIPURI callLegURI,
            string customContentType,
            string customContent,
            string fromDisplayName,
            string fromUsername,
            string fromHost,
            CRMHeaders contact)
        {
            try
            {
                SIPCallDescriptor sipCallDescriptor = null;

                Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Attempting to locate a provider for call leg: " + callLegURI.ToString() + ".", m_username));
                bool providerFound = false;

                string contentType = (sipRequest != null) ? sipRequest.Header.ContentType : null;
                string content = (sipRequest != null) ? sipRequest.Body : null;

                if (!customContentType.IsNullOrBlank())
                {
                    contentType = customContentType;
                }

                if (!customContent.IsNullOrBlank())
                {
                    content = customContent;
                }

                IPAddress publicSDPAddress = PublicIPAddress;
                if (publicSDPAddress == null && sipRequest != null)
                {
                    publicSDPAddress = SIPPacketMangler.GetRequestIPAddress(sipRequest);
                }

                if (m_sipProviders != null)
                {
                    foreach (SIPProvider provider in m_sipProviders)
                    {
                        if (callLegURI.Host.ToUpper() == provider.ProviderName.ToUpper())
                        {
                            if (provider.ProviderType == ProviderTypes.GoogleVoice)
                            {
                                sipCallDescriptor = new SIPCallDescriptor(
                                        provider.ProviderUsername,
                                        provider.ProviderPassword,
                                        callLegURI.User + "@" + provider.ProviderName,
                                        provider.GVCallbackNumber,
                                        provider.GVCallbackPattern,
                                        (provider.GVCallbackType != null) ? (int)provider.GVCallbackType.Value : DEFAULT_GVCALLBACK_TYPE,
                                        content,
                                        contentType);

                                sipCallDescriptor.CRMHeaders = contact;
                                providerFound = true;
                                break;
                            }
                            else
                            {
                                SIPURI providerURI = SIPURI.ParseSIPURI(provider.ProviderServer);
                                if (providerURI != null)
                                {
                                    providerURI.User = callLegURI.User;

                                    if (callLegURI.Parameters.Count > 0)
                                    {
                                        foreach (string parameterName in callLegURI.Parameters.GetKeys())
                                        {
                                            if (!providerURI.Parameters.Has(parameterName))
                                            {
                                                providerURI.Parameters.Set(parameterName, callLegURI.Parameters.Get(parameterName));
                                            }
                                        }
                                    }

                                    if (callLegURI.Headers.Count > 0)
                                    {
                                        foreach (string headerName in callLegURI.Headers.GetKeys())
                                        {
                                            if (!providerURI.Headers.Has(headerName))
                                            {
                                                providerURI.Headers.Set(headerName, callLegURI.Headers.Get(headerName));
                                            }
                                        }
                                    }

                                    SIPFromHeader fromHeader = ParseFromHeaderOption(provider.ProviderFrom, sipRequest, provider.ProviderUsername, providerURI.Host);

                                    sipCallDescriptor = new SIPCallDescriptor(
                                        provider.ProviderUsername,
                                        provider.ProviderPassword,
                                        providerURI.ToString(),
                                        fromHeader.ToString(),
                                        providerURI.ToString(),
                                        null,
                                        SIPCallDescriptor.ParseCustomHeaders(SubstituteRequestVars(sipRequest, provider.CustomHeaders)),
                                        provider.ProviderAuthUsername,
                                        SIPCallDirection.Out,
                                        contentType,
                                        content,
                                        publicSDPAddress);
                                    sipCallDescriptor.CRMHeaders = contact;

                                    if (!provider.ProviderOutboundProxy.IsNullOrBlank())
                                    {
                                        sipCallDescriptor.ProxySendFrom = provider.ProviderOutboundProxy.Trim();
                                    }

                                    providerFound = true;

                                    if (provider.ProviderFrom.IsNullOrBlank())
                                    {
                                        // If there is already a custom From header set on the provider that overrides the general settings.
                                        sipCallDescriptor.SetGeneralFromHeaderFields(fromDisplayName, fromUsername, fromHost);
                                    }

                                    break;
                                }
                                else
                                {
                                    Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Could not parse SIP URI from Provider Server " + provider.ProviderServer + " in GetForwardsForExternalLeg.", m_username));
                                }
                            }
                        }
                    }
                }

                if (!providerFound)
                {
                    // Treat as an anonymous SIP URI.

                    // Copy the From header so the tag can be removed before adding to the forwarded request.
                    string fromHeaderStr = (sipRequest != null) ? sipRequest.Header.From.ToString() : m_anonymousFromURI;
                    SIPFromHeader forwardedFromHeader = SIPFromHeader.ParseFromHeader(fromHeaderStr);
                    forwardedFromHeader.FromTag = null;

                    sipCallDescriptor = new SIPCallDescriptor(
                        m_anonymousUsername,
                        null,
                        callLegURI.ToString(),
                        forwardedFromHeader.ToString(),
                        callLegURI.ToString(),
                        null,
                        null,
                        null,
                        SIPCallDirection.Out,
                        contentType,
                        content,
                        publicSDPAddress);
                    sipCallDescriptor.CRMHeaders = contact;

                    sipCallDescriptor.SetGeneralFromHeaderFields(fromDisplayName, fromUsername, fromHost);
                }

                return sipCallDescriptor;
            }
            catch (Exception excp)
            {
                logger.Error("Exception GetForwardsForExternalLeg. " + excp.Message);
                return null;
            }
        }
        private void ProbeWorkers()
        {
            try
            {
                while (!m_exit)
                {
                    Thread.Sleep(PROBE_WORKER_CALL_PERIOD);

                    try
                    {
                        SIPEndPoint activeWorkerEndPoint = GetFirstHealthyEndPoint();
                        if (activeWorkerEndPoint != null)
                        {
                            SIPCallDescriptor callDescriptor = new SIPCallDescriptor(m_dispatcherUsername, null, "sip:" + m_dispatcherUsername + "@" + activeWorkerEndPoint.GetIPEndPoint().ToString(),
                                    "sip:" + m_dispatcherUsername + "@sipcalldispatcher", "sip:" + activeWorkerEndPoint.GetIPEndPoint().ToString(), null, null, null, SIPCallDirection.Out, null, null, null);
                            SIPClientUserAgent uac = new SIPClientUserAgent(m_sipTransport, null, null, null, null);
                            uac.CallFailed += new SIPCallFailedDelegate(AppServerCallFailed);
                            uac.CallAnswered += (call, sipResponse) => 
                            {
                                if (sipResponse.Status != SIPResponseStatusCodesEnum.BadExtension)
                                {
                                    logger.Warn("Probe call answered with unexpected response code of " + sipResponse.StatusCode + ".");
                                    AppServerCallFailed(call, "Unexpected response of " + ((int)sipResponse.StatusCode) + " on probe call.");
                                }
                            };
                            uac.Call(callDescriptor);
                        }
                        else
                        {
                            logger.Warn("SIPAppServerManager was not able to find a healthy app server endpoint.");
                        }
                    }
                    catch (Exception probeExcp)
                    {
                        logger.Error("Exception SIPAppServerManager Sending Probe. " + probeExcp.Message);
                    }
                }
            }
            catch (Exception excp)
            {
                logger.Error("Exception SIPAppServerManager ProberWorkers. " + excp.Message);
            }
        }
        private SIPRequest GetInviteRequest(SIPCallDescriptor sipCallDescriptor, string branchId, string callId, SIPRouteSet routeSet, string content, string contentType)
        {
            SIPRequest inviteRequest = new SIPRequest(SIPMethodsEnum.INVITE, sipCallDescriptor.Uri);

            SIPHeader inviteHeader = new SIPHeader(sipCallDescriptor.GetFromHeader(), SIPToHeader.ParseToHeader(sipCallDescriptor.To), 1, callId);

            inviteHeader.From.FromTag = CallProperties.CreateNewTag();

            inviteHeader.Contact = new List <SIPContactHeader>()
            {
                SIPContactHeader.GetDefaultSIPContactHeader(inviteRequest.URI.Scheme)
            };
            inviteHeader.Contact[0].ContactURI.User = sipCallDescriptor.Username;
            inviteHeader.CSeqMethod = SIPMethodsEnum.INVITE;
            inviteHeader.UserAgent  = SIPConstants.SipUserAgentVersionString;
            inviteHeader.Routes     = routeSet;
            inviteHeader.Supported  = SIPExtensionHeaders.REPLACES + ", " + SIPExtensionHeaders.NO_REFER_SUB
                                      + ((PrackSupported == true) ? ", " + SIPExtensionHeaders.PRACK : "");

            inviteRequest.Header = inviteHeader;

            if (!sipCallDescriptor.ProxySendFrom.IsNullOrBlank())
            {
                inviteHeader.ProxySendFrom = sipCallDescriptor.ProxySendFrom;
            }

            SIPViaHeader viaHeader = new SIPViaHeader(new IPEndPoint(IPAddress.Any, 0), branchId);

            inviteRequest.Header.Vias.PushViaHeader(viaHeader);

            inviteRequest.Body = content;
            inviteRequest.Header.ContentLength = (inviteRequest.Body != null) ? inviteRequest.Body.Length : 0;
            inviteRequest.Header.ContentType   = contentType;

            try
            {
                if (sipCallDescriptor.CustomHeaders != null && sipCallDescriptor.CustomHeaders.Count > 0)
                {
                    foreach (string customHeader in sipCallDescriptor.CustomHeaders)
                    {
                        if (customHeader.IsNullOrBlank())
                        {
                            continue;
                        }
                        else if (customHeader.Trim().StartsWith(SIPHeaders.SIP_HEADER_USERAGENT))
                        {
                            inviteRequest.Header.UserAgent = customHeader.Substring(customHeader.IndexOf(":") + 1).Trim();
                        }
                        else if (customHeader.Trim().StartsWith(SIPHeaders.SIP_HEADER_TO + ":"))
                        {
                            var customToHeader = SIPUserField.ParseSIPUserField(customHeader.Substring(customHeader.IndexOf(":") + 1).Trim());
                            if (customToHeader != null)
                            {
                                inviteRequest.Header.To.ToUserField = customToHeader;
                            }
                        }
                        else
                        {
                            inviteRequest.Header.UnknownHeaders.Add(customHeader);
                        }
                    }
                }
            }
            catch (Exception excp)
            {
                logger.LogError("Exception Parsing CustomHeader for GetInviteRequest. " + excp.Message + sipCallDescriptor.CustomHeaders);
            }

            if (AdjustInvite != null)
            {
                inviteRequest = AdjustInvite(inviteRequest);
            }

            return(inviteRequest);
        }
Example #45
0
        private void StartNewCallSync(SIPCallDescriptor callDescriptor)
        {
            try
            {
                callDescriptor.DialPlanContextID = (m_dialPlanContext != null) ? m_dialPlanContext.DialPlanContextID : Guid.Empty;

                if (callDescriptor.DelaySeconds != 0)
                {
                    callDescriptor.DelayMRE = new ManualResetEvent(false);
                    lock (m_delayedCalls)
                    {
                        m_delayedCalls.Add(callDescriptor);
                    }

                    int delaySeconds = (callDescriptor.DelaySeconds > MAX_DELAY_SECONDS) ? MAX_DELAY_SECONDS : callDescriptor.DelaySeconds;
                    FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Delaying call leg to " + callDescriptor.Uri + " by " + delaySeconds + "s.", m_username));
                    callDescriptor.DelayMRE.WaitOne(delaySeconds * 1000);
                }

                lock (m_delayedCalls)
                {
                    m_delayedCalls.Remove(callDescriptor);
                }

                if (!m_callAnswered && !m_commandCancelled)
                {
                    ISIPClientUserAgent uacCall = null;

                    if (callDescriptor.ToSIPAccount == null)
                    {
                        if (callDescriptor.IsGoogleVoiceCall)
                        {
                            FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Creating Google Voice user agent for " + callDescriptor.Uri + ".", m_username));
                            uacCall = new GoogleVoiceUserAgent(m_sipTransport, m_callManager, m_statefulProxyLogEvent, m_username, m_adminMemberId, m_outboundProxySocket);
                        }
                        else
                        {
                            uacCall = new SIPClientUserAgent(m_sipTransport, m_outboundProxySocket, m_username, m_adminMemberId, m_statefulProxyLogEvent,
                                m_customerAccountDataLayer.GetRtccCustomer, m_customerAccountDataLayer.GetRtccRate, m_customerAccountDataLayer.GetBalance,
                                m_customerAccountDataLayer.ReserveInitialCredit, m_customerAccountDataLayer.UpdateRealTimeCallControlCDRID);
                        }
                    }
                    else
                    {
                        if (QueueNewCall_External == null)
                        {
                            FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "B2B calls are not supported in this dialplan manifestation.", m_username));
                        }
                        else
                        {
                            FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Creating B2B call for " + callDescriptor.Uri + ".", m_username));
                            uacCall = new SIPB2BUserAgent(m_statefulProxyLogEvent, QueueNewCall_External, m_sipTransport, m_username, m_adminMemberId);
                        }
                    }

                    //ISIPClientUserAgent uacCall = new JingleUserAgent(m_username, m_adminMemberId, m_statefulProxyLogEvent);

                    if (uacCall != null)
                    {
                        lock (m_switchCalls)
                        {
                            m_switchCalls.Add(uacCall);
                        }

                        uacCall.CallAnswered += UACCallAnswered;
                        uacCall.CallFailed += UACCallFailed;
                        uacCall.CallRinging += UACCallProgress;
                        //uacCall.CallTrying += UACCallTrying;

                        uacCall.Call(callDescriptor);
                    }
                }
            }
            catch (Exception excp)
            {
                logger.Error("Exception ForkCall StartNewCall. " + excp.Message);
            }
        }
        public override void Start()
        {
            try
            {
                base.Start();

                m_activeAppServerEntry = GetActiveAppServer();

                if (m_activeAppServerEntry != null)
                {
                    while (!m_stop)
                    {
                        Thread.Sleep(Convert.ToInt32(m_interval.TotalMilliseconds % Int32.MaxValue));

                        logger.Debug("AppServerDispatcher executing.");

                        m_startCheckTime.Reset();
                        m_startCheckTime.Start();

                        SIPClientUserAgent uac = new SIPClientUserAgent(m_sipTransport, null, null, null, LogMonitorEvent);
                        SIPCallDescriptor callDescriptor = new SIPCallDescriptor(null, null, m_activeAppServerEntry.AppServerURI.ToString(), null, null, null, null, null, SIPCallDirection.Out, null, null, null);
                        callDescriptor.MangleResponseSDP = false;
                        uac.CallFailed += CallFailed;
                        uac.CallAnswered += CallAnswered;
                        uac.Call(callDescriptor);
                        uac.ServerTransaction.CDR = null;
                    }
                }
                else
                {
                    logger.Warn("No active app server could be set in AppServerDispatcher.Start, job stopping.");
                }
            }
            catch (Exception excp)
            {
                logger.Error("Exception AppServerDispatcher StartJob. " + excp.Message);
            }
        }