/// <summary>
        /// This function receives asynchronous one-way
        /// notification for requests.
        /// </summary>
        /// <remarks>
        /// The request handler's name must be the name of the
        /// function that is given in the SPL Dispatch function
        /// for SIP request async calls.
        /// </remarks>
        /// <param name="sender">not used</param>
        /// <param name="e">the arguments for async call</param>
        public void RequestNotificationHandler(object sender, NotificationReceivedEventArgs e)
        {
            object[] parameters = e.Parameters;

            // First argument from manifest is SIP Method,
            // use it for statistics

            statistics.Update(Request.GetStandardMethod((string)parameters[0]));

            // Next two arguments are From and To user, use it
            // for statistics
            statistics.Update(SipUriParser.GetUserAtHost((string)parameters[1]));

            statistics.Update(SipUriParser.GetUserAtHost((string)parameters[2]));

            // Raise the event finally
            this.StateChangeListeners(e);
        }
        /// <summary>
        /// This function receives asynchronous one-way
        /// notification for responses.
        /// </summary>
        /// <remarks>
        /// The response handler's name must be the name of the
        /// function that is given in the SPL Dispatch function
        /// for SIP request async calls.
        /// </remarks>
        /// <param name="sender">not used</param>
        /// <param name="e">the arguments for async call</param>
        public void ResponseNotificationHandler(object sender, NotificationReceivedEventArgs e)
        {
            object[] parameters = e.Parameters;

            // First argument from manifest is SIP response code,
            // use it for statistics

            statistics.Update(Response.GetStatusClass((int)parameters[0]));

            // Last two arguments are From and
            // To user, use it for statistics
            statistics.Update(SipUriParser.GetUserAtHost((string)parameters[1]));

            statistics.Update(SipUriParser.GetUserAtHost((string)parameters[2]));

            // Raise the event finally
            this.StateChangeListeners(e);
        }
        /// <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;
        }