private void DispatcherCallFailed(ISIPClientUserAgent uac, string errorMessage)
        {
            try {
                string workerSocket = SIPURI.ParseSIPURI(uac.CallDescriptor.Uri).Host;
                dispatcherLogger.Debug("Dispatcher call to " + workerSocket + " failed " + errorMessage + ".");

                // Find the worker for the failed end point.
                SIPCallDispatcherWorker failedWorker = null;
                lock (m_callDispatcherWorkers) {
                    foreach (SIPCallDispatcherWorker worker in m_callDispatcherWorkers)
                    {
                        if (worker.AppServerEndpoint.SocketEndPoint.ToString() == workerSocket)
                        {
                            failedWorker = worker;
                            break;
                        }
                    }
                }

                if (failedWorker != null)
                {
                    dispatcherLogger.Debug("Scheduling immediate restart on worker process pid=" + failedWorker.WorkerProcess.Id + " due to failed probe.");
                    failedWorker.RestartTime = DateTime.Now;
                }
            }
            catch (Exception excp) {
                dispatcherLogger.Error("Exception DispatcherCallFailed. " + excp.Message);
            }
        }
        private List <string> m_workerSIPEndPoints = new List <string>();                                     // Allow quick lookups to determine whether a remote end point is that of a worker process.

        public SIPCallDispatcher(
            SIPMonitorLogDelegate logDelegate,
            SIPTransport sipTransport,
            XmlNode callDispatcherNode,
            SIPEndPoint outboundProxy,
            string dispatcherScriptPath)
        {
            if (callDispatcherNode == null || callDispatcherNode.ChildNodes.Count == 0)
            {
                throw new ArgumentNullException("A SIPCallDispatcher cannot be created with an empty configuration node.");
            }

            SIPMonitorLogEvent_External = logDelegate;
            m_sipTransport         = sipTransport;
            m_callDispatcherNode   = callDispatcherNode;
            m_outboundProxy        = outboundProxy;
            m_dispatcherScriptPath = dispatcherScriptPath;

            m_scriptLoader = new ScriptLoader(SIPMonitorLogEvent_External, m_dispatcherScriptPath);
            m_scriptLoader.ScriptFileChanged += (s, e) => { m_compiledScript = m_scriptLoader.GetCompiledScript(); };
            m_compiledScript = m_scriptLoader.GetCompiledScript();

            try {
                CallManagerPassThruServiceInstanceProvider callManagerPassThruSvcInstanceProvider = new CallManagerPassThruServiceInstanceProvider(this);
                m_callManagerPassThruSvcHost = new ServiceHost(typeof(CallManagerPassThruService));
                m_callManagerPassThruSvcHost.Description.Behaviors.Add(callManagerPassThruSvcInstanceProvider);
                m_callManagerPassThruSvcHost.Open();

                logger.Debug("SIPCallDispatcher CallManagerPassThru hosted service successfully started on " + m_callManagerPassThruSvcHost.BaseAddresses[0].AbsoluteUri + ".");
            }
            catch (Exception excp) {
                logger.Warn("Exception starting SIPCallDispatcher CallManagerPassThru hosted service. " + excp.Message);
            }

            foreach (XmlNode callDispatcherWorkerNode in callDispatcherNode.ChildNodes)
            {
                SIPCallDispatcherWorker callDispatcherWorker = new SIPCallDispatcherWorker(callDispatcherWorkerNode);
                m_callDispatcherWorkers.Add(callDispatcherWorker);
                m_workerSIPEndPoints.Add(callDispatcherWorker.AppServerEndpoint.ToString());
                dispatcherLogger.Debug(" SIPCallDispatcher worker added for " + callDispatcherWorker.AppServerEndpoint.ToString() + " and " + callDispatcherWorker.CallManagerAddress.ToString() + ".");
            }

            ThreadPool.QueueUserWorkItem(delegate { SpawnWorkers(); });
            ThreadPool.QueueUserWorkItem(delegate { ProbeWorkers(); });
        }
        private List<string> m_workerSIPEndPoints = new List<string>();                             // Allow quick lookups to determine whether a remote end point is that of a worker process.

        public SIPCallDispatcher(
            SIPMonitorLogDelegate logDelegate, 
            SIPTransport sipTransport, 
            XmlNode callDispatcherNode,
            SIPEndPoint outboundProxy,
            string dispatcherScriptPath) {

            if (callDispatcherNode == null || callDispatcherNode.ChildNodes.Count == 0) {
                throw new ArgumentNullException("A SIPCallDispatcher cannot be created with an empty configuration node.");
            }

            SIPMonitorLogEvent_External = logDelegate;
            m_sipTransport = sipTransport;
            m_callDispatcherNode = callDispatcherNode;
            m_outboundProxy = outboundProxy;
            m_dispatcherScriptPath = dispatcherScriptPath;

            m_scriptLoader = new ScriptLoader(SIPMonitorLogEvent_External, m_dispatcherScriptPath);
            m_scriptLoader.ScriptFileChanged += (s, e) => { m_compiledScript = m_scriptLoader.GetCompiledScript(); };
            m_compiledScript = m_scriptLoader.GetCompiledScript();

            try {
                CallManagerPassThruServiceInstanceProvider callManagerPassThruSvcInstanceProvider = new CallManagerPassThruServiceInstanceProvider(this);
                m_callManagerPassThruSvcHost = new ServiceHost(typeof(CallManagerPassThruService));
                m_callManagerPassThruSvcHost.Description.Behaviors.Add(callManagerPassThruSvcInstanceProvider);
                m_callManagerPassThruSvcHost.Open();

                logger.Debug("SIPCallDispatcher CallManagerPassThru hosted service successfully started on " + m_callManagerPassThruSvcHost.BaseAddresses[0].AbsoluteUri + ".");
            }
            catch (Exception excp) {
                logger.Warn("Exception starting SIPCallDispatcher CallManagerPassThru hosted service. " + excp.Message);
            }

            foreach (XmlNode callDispatcherWorkerNode in callDispatcherNode.ChildNodes) {
                SIPCallDispatcherWorker callDispatcherWorker = new SIPCallDispatcherWorker(callDispatcherWorkerNode);
                m_callDispatcherWorkers.Add(callDispatcherWorker);
                m_workerSIPEndPoints.Add(callDispatcherWorker.AppServerEndpoint.ToString());
                dispatcherLogger.Debug(" SIPCallDispatcher worker added for " + callDispatcherWorker.AppServerEndpoint.ToString() + " and " + callDispatcherWorker.CallManagerAddress.ToString() + ".");
            }

            ThreadPool.QueueUserWorkItem(delegate { SpawnWorkers(); });
            ThreadPool.QueueUserWorkItem(delegate { ProbeWorkers(); });
        }