/// <summary>
        /// Request handler.
        /// </summary>
        /// <param name="sender">The serveragent object.</param>
        /// <param name="eventArgs">Request parameters.</param>
        public virtual void OnRequest(object sender, RequestReceivedEventArgs eventArgs)
        {
            Request request          = eventArgs.Request;
            bool    requestIsAllowed = false;
            bool    addedToAllowList = false;
            string  fromUserAtHost;
            string  toUserAtHost;

            Header header = request.AllHeaders.FindFirst(Header.StandardHeaderType.From);

            fromUserAtHost = Utils.UriParser.GetUserAtHost(header.Value);
            header         = request.AllHeaders.FindFirst(Header.StandardHeaderType.To);
            toUserAtHost   = Utils.UriParser.GetUserAtHost(header.Value);

            //
            // Check the request origin and carry out the appropriate action.
            //

            AuthenticationInfo authenticationInfo = (AuthenticationInfo)request.AuthenticationInfo;

            if (authenticationInfo.Origin == AuthenticationInfo.MessageOrigin.NetworkExternal)
            {
                //
                // Get the From domain.
                //

                string fromDomain = Utils.UriParser.GetHost(fromUserAtHost).ToLower();

                //
                // See if this domain has been validated already.
                //


                lock (this.SyncRoot) {
                    if (allowList.Contains(fromDomain))
                    {
                        //
                        // This is a validated domain. It can show up here if we
                        // added this in another thread and this has not been picked up
                        // in SPL.
                        //

                        requestIsAllowed = true;
                    }
                }

                if (!requestIsAllowed)
                {
                    LogEntry logEntry = new LogEntry(fromUserAtHost, toUserAtHost, fromDomain);
                    lock (externalEdgeLog.SyncRoot) {
                        externalEdgeLog.Log(logEntry);
                    }
                }
            }
            else
            {
                // We should have only internal here - the SPL script should not be
                // dispatching the other cases here.
                Debug.Assert(authenticationInfo.Origin == AuthenticationInfo.MessageOrigin.NetworkInternal);

                //
                // Get the To domain.
                //

                string toDomain = Utils.UriParser.GetHost(toUserAtHost).ToLower();

                //
                // See if this domain has been validated already.
                //

                lock (this.SyncRoot) {
                    if (allowList.Contains(toDomain))
                    {
                        //
                        // This is a validated domain. It can show up here if we
                        // added this in another thread and this has not been picked up
                        // in SPL.
                        //

                        requestIsAllowed = true;
                    }
                    else
                    {
                        //
                        // Policy implementation. Put action to be carried out for unknown
                        // internal domains here.
                        //

                        //
                        // Check whether we are allowed to add this entry automatically.
                        //

                        if (config.ActionForUnknownDomainFromInternalEdge == Config.ActionAutoAdd)
                        {
                            if (currentDomains + 1 < config.MaxDomainsInEnhancedAllowList)
                            {
                                allowList.Add(toDomain, null);
                                currentDomains  += 1;
                                addedToAllowList = true;
                                requestIsAllowed = true;
                            }
                            else
                            {
                                RaiseConfigFileFullEvent();
                            }
                        }
                    }
                }

                if (addedToAllowList)
                {
                    //
                    // This entry was added to the global allow list and hence we need to add
                    // this to the SPL script flat file.
                    //

                    try {
                        InternalAppendDomainToEnhancedAllowListFile(toDomain);
                    } catch (Exception e) {
                        // Failed to open or write to allow list.
                        lock (this.SyncRoot) {
                            allowList.Remove(toDomain);
                            currentDomains  -= 1;
                            addedToAllowList = false;
                            requestIsAllowed = false;
                        }

                        RaiseConfigFileWriteFailureEvent(e.Message);
                    }

                    if (addedToAllowList)
                    {
                        //
                        // Log that we added this entry as well.
                        //

                        LogEntry logEntry = new AllowListLogEntry(fromUserAtHost, toUserAtHost, toDomain);
                        lock (internalEdgeLog.SyncRoot) {
                            internalEdgeLog.Log(logEntry);
                        }
                    }
                }

                if (!requestIsAllowed)
                {
                    LogEntry logEntry = new LogEntry(fromUserAtHost, toUserAtHost, toDomain);
                    lock (internalEdgeLog.SyncRoot) {
                        internalEdgeLog.Log(logEntry);
                    }
                }
            }

            if (requestIsAllowed)
            {
                //
                // Mark the request as simple proxy. This will turn on
                // performance optimizations that would otherwise be not
                // possible.
                //

                request.SimpleProxy = true;
                eventArgs.ServerTransaction.EnableForking = false;


                ClientTransaction ct = eventArgs.ServerTransaction.CreateBranch();
                ct.SendRequest(request);
            }
            else
            {
                Response localResponse = request.CreateResponse(403);
                eventArgs.ServerTransaction.SendResponse(localResponse);
            }
        }
        /// <summary>
        /// This function receives SIP requests, updates
        /// session state variables, and proxies the request
        /// to the default request uri
        /// </summary>
        /// <remarks>
        /// The request handler's name must be the name of the
        /// function that is given in the SPL Dispatch function
        /// for SIP requests.
        /// </remarks>
        /// <param name="sender">not used</param>
        /// <param name="e">the request state</param>
        public void RequestHandler(object sender, RequestReceivedEventArgs e)
        {
            /* If this is a SIP INVITE, then create an entry
             *  in the session state table for this call-id.
             *  A session is established, when an ACK for this
             *  call-id is received.
             */
            Request request = e.Request;

            if (request.StandardMethod == Request.StandardMethodType.Invite)
            {
                ///extract the call-id and create session state
                Header callIdHeader = request.AllHeaders.FindFirst("Call-ID");

                if (callIdHeader != null)
                {
                    Session newSession = new Session();
                    newSession.State  = Session.States.Initializing;
                    newSession.CallId = callIdHeader.Value;
                    lock (sessionStateTable.SyncRoot) {
                        sessionStateTable[callIdHeader.Value] = newSession;
                    }
                }
            }
            else if (request.StandardMethod == Request.StandardMethodType.Ack)
            {
                ///extract the call-id and update session state, ignore errors
                Header callIdHeader = request.AllHeaders.FindFirst("Call-ID");

                if (callIdHeader != null)
                {
                    Session session = sessionStateTable[callIdHeader.Value] as Session;
                    if (session != null)
                    {
                        session.State = Session.States.Established;
                        statistics.Update(true /* new session */);
                    }
                }
            }

            ///update other counters
            statistics.Update(request.StandardMethod);

            Header fromHeader = request.AllHeaders.FindFirst("From");
            Header toHeader   = request.AllHeaders.FindFirst("To");


            statistics.Update(SipUriParser.GetUserAtHost(fromHeader.Value));
            statistics.Update(SipUriParser.GetUserAtHost(toHeader.Value));

            ///notify the state change
            this.StateChangeListeners(e);

            ///We will not be forking, and marking this explicitly
            ///allows ServerAgent to optimize message proxying.
            e.ServerTransaction.EnableForking = false;

            ///we are done with state management, proxy
            ClientTransaction ct = e.ServerTransaction.CreateBranch();

            if (SimpleProxy)
            {
                // Setting SimpleProxy to true will turn on performance
                // optimizations during message proxying.
                request.SimpleProxy = true;
            }

            ///Add a header if requested by user.
            if (AddHeader)
            {
                Header h = new Header(SipSnoopHeaderName, SipSnoopHeaderValue);
                request.AllHeaders.Add(h);
            }

            ///Modify To header if requested by user by adding a parameter.
            if (ModifyToHeader)
            {
                NameValueCollection toParamColl = toHeader.Parameters;
                toParamColl.Set(SipSnoopParamName, SipSnoopParamValue);
                toHeader.Parameters = toParamColl;
            }

            ct.SendRequest(e.Request);

            return;
        }