示例#1
0
        public void FlightRecorder_PassThru_SysLogProvider()
        {
            // Verify that the ISysLogProvider implementation works.

            Queue <FlightEvent> queue       = new Queue <FlightEvent>();
            ISysLogProvider     orgProvider = SysLog.LogProvider;

            try
            {
                FlightEvent flightEvent;

                using (var recorder = new FlightRecorder(evt => queue.Enqueue(evt)))
                {
                    SysLog.LogProvider = recorder;

                    SysLog.LogError("Test Error");
                    SysLog.LogWarning("Test Warning");
                    SysLog.LogInformation("Test Information");
                    SysLog.Flush();

                    Assert.AreEqual(3, queue.Count);

                    flightEvent = queue.Dequeue();
                    Assert.AreEqual("SysLog:Error", flightEvent.Operation);
                    Assert.IsTrue(flightEvent.Details.Contains("Test Error"));
                    Assert.IsTrue(flightEvent.IsError);

                    flightEvent = queue.Dequeue();
                    Assert.AreEqual("SysLog:Warning", flightEvent.Operation);
                    Assert.IsTrue(flightEvent.Details.Contains("Test Warning"));
                    Assert.IsFalse(flightEvent.IsError);

                    flightEvent = queue.Dequeue();
                    Assert.AreEqual("SysLog:Information", flightEvent.Operation);
                    Assert.IsTrue(flightEvent.Details.Contains("Test Information"));
                    Assert.IsFalse(flightEvent.IsError);

                    // Verify that system events actually serialize exception
                    // and stack trace related information.

                    try
                    {
                        throw new AssertException();
                    }
                    catch (Exception e)
                    {
                        SysLog.LogException(e);
                        SysLog.Flush();

                        flightEvent = queue.Dequeue();
                        Assert.AreEqual("SysLog:Exception", flightEvent.Operation);
                        Assert.IsTrue(flightEvent.Details.Contains("AssertException"));
                    }
                }
            }
            finally
            {
                SysLog.LogProvider = orgProvider;
            }
        }
示例#2
0
        /// <summary>
        /// Called to dispatch a server side session.
        /// </summary>
        /// <param name="msg">The message initiating the session.</param>
        /// <param name="target">The target object instance.</param>
        /// <param name="method">The target method information.</param>
        /// <param name="sessionInfo">The session information associated with the handler.</param>
        /// <remarks>
        /// The target and method parameter will specify the message handler
        /// for the message passed.
        /// </remarks>
        public void ServerDispatch(Msg msg, object target, MethodInfo method, SessionHandlerInfo sessionInfo)
        {
            ISession session;
            bool     start = false;

            Assertion.Test((msg._Flags & (MsgFlag.OpenSession & MsgFlag.ServerSession)) == (MsgFlag.OpenSession & MsgFlag.ServerSession));
            Assertion.Test(msg._SessionID != Guid.Empty);

            using (TimedLock.Lock(router.SyncRoot))
            {
                // Create a session with this ID if one doesn't already exist.

                serverSessions.TryGetValue(msg._SessionID, out session);

                if (session == null)
                {
                    if (sessionInfo.SessionType == null)
                    {
                        SysLog.LogError("Session creation failed for received [{0}] message: No session type specified in [MsgSession] tag for handler [{1}.{2}({3})}.",
                                        msg.GetType().FullName,
                                        target.GetType().FullName,
                                        method.Name,
                                        method.GetParameters()[0].ParameterType.Name);
                        return;
                    }

                    start   = true;
                    session = Helper.CreateInstance <ISession>(sessionInfo.SessionType);
                    session.InitServer(router, this, router.SessionTimeout, msg, target, method, sessionInfo);
                    serverSessions.Add(msg._SessionID, session);
                }
            }

            // Dispatch the message outside of the lock (to avoid deadlocks)

            if (start)
            {
                session.StartServer();
            }
            else
            {
                session.OnMsg(msg, sessionInfo);
            }
        }
示例#3
0
        /// <summary>
        /// Constructs the instance and starts the background downloading thread.
        /// </summary>
        /// <param name="node">The parent <see cref="GeoTrackerNode" /> instance.</param>
        /// <remarks>
        /// <note>
        /// The constructor will not start a background thread if IP geocoding is disabled.
        /// </note>
        /// </remarks>
        public IPGeocoder(GeoTrackerNode node)
        {
            settings = node.Settings;

            if (!settings.IPGeocodeEnabled)
            {
                return;
            }

            // Initialize the service including loading the MaxMind database if present.

            running     = true;
            stopPending = false;
            pollDataNow = false;
            maxMind     = null;

            try
            {
                if (File.Exists(dataPath))
                {
                    maxMind = new LookupService(dataPath, LookupService.GEOIP_MEMORY_CACHE);
                    maxMind.close();
                }
            }
            catch (Exception e)
            {
                // Assume that the database file is corrupted if there's an exception
                // and delete it so the download thread will download a new copy.

                SysLog.LogException(e);
                SysLog.LogError("GeoTracker: The MaxMind database file [{0}] appears to be corrupted.  This will be deleted so the downloader can get a fresh copy.", dataPath);

                Helper.DeleteFile(dataPath);
            }

            // Start the background downloader thread.

            downloadThread      = new Thread(new ThreadStart(DownloadThread));
            downloadThread.Name = "GeoTracker: GeoData Downloader";
            downloadThread.Start();
        }
示例#4
0
        /// <summary>
        /// The managing <see cref="ISipAgent" /> is responsible for calling this
        /// method whenever it receives responses correlated to this transaction.
        /// </summary>
        /// <param name="transport">The source <see cref="ISipTransport" />.</param>
        /// <param name="response">The received <see cref="SipResponse" />.</param>
        public void OnResponse(ISipTransport transport, SipResponse response)
        {
            bool         callOnComplete       = false;
            bool         callOnProceeding     = false;
            bool         callOnInviteComplete = false;
            SipResponse  callbackMsg          = null;
            SipStatus    status = SipStatus.OK;
            SipCSeqValue vCSeq;

            this.transport = transport;

            try
            {
                response.SourceTransaction = this;

                using (TimedLock.Lock(agent))
                {
                    // Ignore messages without a sequence number
                    //
                    // $todo(jeff.lill): Probably should check the method too

                    vCSeq = response.GetHeader <SipCSeqValue>(SipHeader.CSeq);
                    if (vCSeq == null)
                    {
                        return;
                    }

                    // Handle state specific processing

                    switch (base.State)
                    {
                    default:
                    case SipTransactionState.Unknown:

                        SysLog.LogError("Unexpected SIP transaction state.");
                        SetState(SipTransactionState.Terminated);

                        // Setup to call the agent's completion method

                        callOnComplete = true;
                        callbackMsg    = null;
                        status         = SipStatus.Stack_ProtocolError;
                        return;

                    case SipTransactionState.InviteCalling:

                        if (!request.MatchCSeq(response))
                        {
                            return;         // Ignore responses whose CSeq header doesn't match the request
                        }
                        if (response.IsProvisional)
                        {
                            // Provisional response.

                            SetState(SipTransactionState.InviteProceeding);

                            // Setup to call the agent's proceeding method

                            callOnProceeding = true;
                            callbackMsg      = response;
                            status           = response.Status;
                            return;
                        }

                        if (response.IsNonSuccessFinal)
                        {
                            // Final response non-2xx response.  Generate and
                            // send the ACK request to the server to squelch
                            // any further responses and then enter the
                            // InviteCompleted state to absorb any responses
                            // that do make it through.

                            ackRequest = CreateAckRequest(request, response);
                            transport.Send(remoteEP, ackRequest);

                            SetState(SipTransactionState.InviteCompleted);

                            // Setup to call the agent's invite completed method

                            callOnInviteComplete = true;
                            callbackMsg          = response;
                            status = response.Status;
                            return;
                        }

                        // Must be a 2xx response.  Setup to call the agent's
                        // completed method and enter the terminated state
                        // without sending an ACK request.
                        //
                        // Note that the agent is required to do this as
                        // described in RFC 3261 on pages 128-129.

                        SetState(SipTransactionState.Terminated);

                        callOnInviteComplete = true;
                        callbackMsg          = response;
                        status = response.Status;
                        break;

                    case SipTransactionState.InviteProceeding:

                        if (!request.MatchCSeq(response))
                        {
                            return;         // Ignore responses whose CSeq header doesn't match the request
                        }
                        if (response.IsProvisional)
                        {
                            // Setup to call the agent's proceeding method

                            callOnProceeding = true;
                            callbackMsg      = response;
                            status           = response.Status;
                            return;
                        }

                        if (response.IsNonSuccessFinal)
                        {
                            // Final response non-2xx response.  Generate and
                            // send the ACK request to the server to squelch
                            // any further responses and then enter the
                            // InviteCompleted state to absorb any responses
                            // that do make it through.

                            // $todo(jeff.lill):
                            //
                            // I need to figure out a way to
                            // map to the dialog so that it
                            // can generate the ACK rather than
                            // doing this locally.

                            ackRequest = CreateAckRequest(request, response);
                            transport.Send(remoteEP, ackRequest);

                            SetState(SipTransactionState.InviteCompleted);

                            // Setup to call the agent's invite completed method

                            callOnInviteComplete = true;
                            callbackMsg          = response;
                            status = response.Status;
                            return;
                        }

                        // Must be a 2xx response.  Setup to call the agent's
                        // completed method and enter the terminated state
                        // without sending an ACK request.
                        //
                        // Note that the agent is required to do this as
                        // described in RFC 3261 on pages 128-129.

                        SetState(SipTransactionState.Terminated);

                        callOnInviteComplete = true;
                        callbackMsg          = response;
                        status = response.Status;
                        break;

                    case SipTransactionState.InviteCompleted:

                        // Retransmit the ACK if we get another final response

                        if (response.IsFinal)
                        {
                            transport.Send(remoteEP, ackRequest);
                        }

                        break;

                    case SipTransactionState.Trying:

                        if (!request.MatchCSeq(response))
                        {
                            return;         // Ignore responses whose CSeq header doesn't match the request
                        }
                        if (response.IsProvisional)
                        {
                            // Provisional response.

                            SetState(SipTransactionState.Proceeding);

                            // Setup to call the agent's proceeding method

                            callOnProceeding = true;
                            callbackMsg      = response;
                            status           = response.Status;
                            return;
                        }
                        else
                        {
                            // Final response

                            SetState(SipTransactionState.Completed);

                            // Setup to call the agent's completion method

                            callOnComplete = true;
                            callbackMsg    = response;
                            status         = response.Status;
                            return;
                        }

                    case SipTransactionState.Proceeding:

                        if (!request.MatchCSeq(response))
                        {
                            return;         // Ignore responses whose CSeq header doesn't match the request
                        }
                        if (response.IsProvisional)
                        {
                            // Setup to call the agent's proceeding method

                            callOnProceeding = true;
                            callbackMsg      = response;
                            status           = response.Status;
                            return;
                        }

                        // Final response.

                        SetState(SipTransactionState.Completed);

                        // Setup to call the agent's completion method

                        callOnComplete = true;
                        callbackMsg    = response;
                        status         = response.Status;
                        return;

                    case SipTransactionState.Completed:

                        break;

                    case SipTransactionState.Terminated:

                        break;
                    }
                }
            }
            finally
            {
                // Handle the agent callbacks outside of the lock to avoid
                // deadlock issues.

                if (callOnProceeding)
                {
                    agent.OnProceeding(this, callbackMsg);
                }

                if (callOnComplete)
                {
                    agent.OnComplete(this, status, callbackMsg);
                }

                if (callOnInviteComplete)
                {
                    agent.OnInviteComplete(this, status, response);
                }
            }
        }
示例#5
0
        /// <summary>
        /// Handles received packets.
        /// </summary>
        /// <param name="ar">The <see cref="IAsyncResult" /> instance.</param>
        private void OnReceive(IAsyncResult ar)
        {
            DnsRequest request = null;
            int        cbRecv;
            IPEndPoint ep;

            try
            {
                cbRecv = ((EnhancedSocket)ar.AsyncState).EndReceiveFrom(ar, ref remoteEP);
            }
            catch
            {
                cbRecv = 0;
            }

            if (sock == null)
            {
                return; // The server has stopped
            }
            if (cbRecv != 0)
            {
                // Parse the request packet

                try
                {
                    request = new DnsRequest();
                    request.ParsePacket(recvBuf, cbRecv);
                }
                catch (Exception e)
                {
                    SysLog.LogException(e);
                }
            }

            // Save the remote EP and then initiate another async
            // packet receive.

            ep       = (IPEndPoint)remoteEP;
            remoteEP = new IPEndPoint(IPAddress.Any, 0);

            sock.BeginReceiveFrom(recvBuf, 0, recvBuf.Length, SocketFlags.None, ref remoteEP, onReceive, sock);

            // Process the request and transmit the response (if there is one).

            if (request != null && RequestEvent != null)
            {
                var args = new DnsServerEventArgs(ep, request);

                RequestEvent(this, args);
                if (args.Response != null)
                {
                    byte[] sendBuf;
                    int    cbSend;

                    // $todo(jeff.lill):
                    //
                    // Remove this exception code after figuring out why the
                    // response's QName field is sometimes NULL.

                    try
                    {
                        sendBuf = args.Response.FormatPacket(out cbSend);
                    }
                    catch
                    {
                        SysLog.LogError("DNS Formatting Error:\r\n\r\n" +
                                        args.Request.GetTraceDetails(ep.Address) +
                                        "\r\n" +
                                        args.Response.GetTraceDetails(ep.Address));
                        throw;
                    }

                    lock (syncLock)
                    {
                        if (sock != null)
                        {
                            sock.SendTo(sendBuf, cbSend, SocketFlags.None, args.RemoteEP);
                        }
                    }
                }
            }
        }
示例#6
0
        private static Dictionary <string, string> voiceNameMap;        // Maps friendly voice names to the internal name

        /// <summary>
        /// Starts the engine if it is not already running.
        /// </summary>
        /// <param name="settings">The engine settings.</param>
        /// <exception cref="ArgumentNullException">Thrown if <paramref name="settings"/> is <c>null</c>.</exception>
        public static void Start(SpeechEngineSettings settings)
        {
            if (settings == null)
            {
                throw new ArgumentNullException("settings");
            }

            lock (syncLock)
            {
                if (SpeechEngine.isRunning)
                {
                    return;
                }

                SpeechEngine.settings  = settings;
                SpeechEngine.cache     = new PhraseCache(settings);
                SpeechEngine.isRunning = true;

                // Create the default audio formats.

                format_8000KHz  = new SpeechAudioFormatInfo(8000, AudioBitsPerSample.Eight, AudioChannel.Mono);
                format_11025KHz = new SpeechAudioFormatInfo(11025, AudioBitsPerSample.Eight, AudioChannel.Mono);
                format_16000KHz = new SpeechAudioFormatInfo(16000, AudioBitsPerSample.Eight, AudioChannel.Mono);

                // Get the fully qualified paths to the error files.

                noVoicesPath   = Path.Combine(CoreApp.InstallPath, "Audio", "NoVoicesError.wav");
                synthErrorPath = Path.Combine(CoreApp.InstallPath, "Audio", "SpeechSynthError.wav");

                // Enumerate the installed voices and select the default voice.
                //
                // Note: The Microsoft Speech Platform voices have really clunky names like:
                //
                //    "Microsoft Server Speech Text to Speech Voice (en-AU, Hayley)"
                //
                // I'm going to simplify these to be just "Microsoft <name>" and maintain
                // a table that maps back to the original name.

                voiceNameMap = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase);

                using (var synth = new SpeechSynthesizer())
                {
                    var voices = new Dictionary <string, VoiceInfo>(StringComparer.OrdinalIgnoreCase);

                    foreach (var voice in synth.GetInstalledVoices())
                    {
                        var voiceName = voice.VoiceInfo.Name;

                        if (!voice.Enabled)
                        {
                            continue;
                        }

                        // $hack(jeff.lill):
                        //
                        // Make sure that the voice can actually be used.  I've run into
                        // situations where [Microsoft Anna] was present and enabled but
                        // could not be selected.  I believe this may be a 64-bit issue
                        // or perhaps installing Cepstral voices messes with Anna.

                        try
                        {
                            synth.SelectVoice(voice.VoiceInfo.Name);
                        }
                        catch
                        {
                            continue;
                        }

                        if (voiceName.StartsWith("Microsoft Server Speech Text to Speech Voice ("))
                        {
                            int p = voiceName.IndexOf(',');

                            if (p != -1)
                            {
                                voiceName = voiceName.Substring(p + 1);
                                voiceName = "Microsoft " + voiceName.Replace(")", string.Empty).Trim();

                                voiceNameMap[voiceName] = voice.VoiceInfo.Name;
                            }
                        }

                        voices.Add(voiceName, voice.VoiceInfo);
                    }

                    SpeechEngine.InstalledVoices  = voices.ToReadOnly();
                    SpeechEngine.DefaultVoice     = null;
                    SpeechEngine.DefaultVoiceInfo = null;

                    // First see if the desired default voice exists.

                    if (!string.IsNullOrWhiteSpace(settings.DefaultVoice) && String.Compare(settings.DefaultVoice, "auto") != 0)
                    {
                        VoiceInfo voiceInfo;

                        if (voices.TryGetValue(settings.DefaultVoice, out voiceInfo))
                        {
                            SpeechEngine.DefaultVoice = voiceInfo.Name;
                        }
                        else
                        {
                            SysLog.LogWarning("[SpeechEngine] was not able to locate the requested default voice [{0}].  Another voice will be selected automatically.", settings.DefaultVoice);
                        }
                    }

                    // If not look for an alternative

                    if (SpeechEngine.DefaultVoice == null)
                    {
                        if (voices.ContainsKey("Microsoft Helen"))
                        {
                            SpeechEngine.DefaultVoice = "Microsoft Helen";
                        }
                        else if (voices.ContainsKey("Microsoft Anna"))
                        {
                            SpeechEngine.DefaultVoice = "Microsoft Anna";
                        }
                        else
                        {
                            SysLog.LogWarning("[SpeechEngine] was not able to locate the [Microsoft Anna] voice.");

                            var v = voices.Keys.FirstOrDefault();

                            if (v == null)
                            {
                                SpeechEngine.DefaultVoice = null;
                                SysLog.LogError("[SpeechEngine] was not able to locate any speech synthesis voices.  Speech synthesis will be disabled.");
                            }
                            else
                            {
                                SpeechEngine.DefaultVoice = v;
                            }
                        }
                    }

                    if (SpeechEngine.DefaultVoice != null)
                    {
                        SpeechEngine.DefaultVoiceInfo = SpeechEngine.InstalledVoices[GetVoice(SpeechEngine.DefaultVoice)];
                    }
                }
            }
        }
示例#7
0
        /// <summary>
        /// The managing <see cref="ISipAgent" /> is responsible for calling this
        /// method whenever it needs to send a response for the transaction.
        /// </summary>
        /// <param name="response">The <see cref="SipResponse" /> (or <c>null</c> to abort).</param>
        /// <remarks>
        /// You may pass <paramref name="response"/> as <c>null</c> to abort the transaction
        /// without sending a response.  This is equivalent to calling <see cref="Abort" />.
        /// </remarks>
        public void SendResponse(SipResponse response)
        {
            try
            {
                using (TimedLock.Lock(agent))
                {
                    if (response == null)
                    {
                        // Handle aborting by transitioning to the completed state so
                        // request retransmits will continue to be absorbed by the
                        // transaction.

                        SetState(SipTransactionState.Completed);
                        return;
                    }

                    // Handle state specific processing

                    switch (base.State)
                    {
                    default:
                    case SipTransactionState.Unknown:

                        SysLog.LogError("Unexpected SIP transaction state.");
                        SetState(SipTransactionState.Terminated);
                        return;

                    case SipTransactionState.InviteCalling:

                        break;

                    case SipTransactionState.InviteProceeding:

                        if (response.IsProvisional)
                        {
                            // Provisional

                            provisionalResponse = response;
                            transport.Send(remoteEP, provisionalResponse);
                            return;
                        }

                        if (response.IsSuccess)
                        {
                            // Final response (success)

                            finalResponse = response;
                            transport.Send(remoteEP, finalResponse);
                            SetState(SipTransactionState.Terminated);
                            return;
                        }

                        // Final response (error)

                        finalResponse = response;
                        transport.Send(remoteEP, finalResponse);
                        SetState(SipTransactionState.InviteCompleted);
                        break;

                    case SipTransactionState.InviteCompleted:

                        break;

                    case SipTransactionState.InviteConfirmed:

                        break;

                    case SipTransactionState.Trying:

                        if (response.IsProvisional)
                        {
                            // Provisional

                            provisionalResponse = response;
                            transport.Send(remoteEP, provisionalResponse);
                            SetState(SipTransactionState.Proceeding);
                            return;
                        }

                        // Final response

                        finalResponse = response;
                        transport.Send(remoteEP, finalResponse);
                        SetState(SipTransactionState.Completed);

                        break;

                    case SipTransactionState.Proceeding:

                        if (response.IsProvisional)
                        {
                            // Provisional

                            provisionalResponse = response;
                            transport.Send(remoteEP, provisionalResponse);
                            return;
                        }

                        // Final response

                        finalResponse = response;
                        transport.Send(remoteEP, finalResponse);
                        SetState(SipTransactionState.Completed);

                        return;

                    case SipTransactionState.Completed:

                        break;

                    case SipTransactionState.Terminated:

                        break;
                    }
                }
            }
            finally
            {
            }
        }
示例#8
0
        /// <summary>
        /// The managing <see cref="ISipAgent" /> is responsible for calling this
        /// method whenever it receives requests correlated to this transaction.
        /// </summary>
        /// <param name="request">The received <see cref="SipRequest" />.</param>
        public void OnRequest(SipRequest request)
        {
            SipRequest callbackMsg          = null;
            bool       callOnRequest        = false;
            bool       callOnInviteBegin    = false;
            bool       callOnInviteComplete = false;

            try
            {
                request.SourceTransaction = this;

                using (TimedLock.Lock(agent))
                {
                    if (this.request == null)
                    {
                        SipViaValue     viaValue;
                        SipContactValue toValue;
                        NetworkBinding  sentBy;
                        IPAddress       address;

                        // This is the initial transaction request.

                        this.request = request;

                        // Handle the Via "received" and "rport" header parameters (mostly) as described on page
                        // RFC 3261 (page 145) and RFC 3581 (page 4).

                        viaValue = request.GetHeader <SipViaValue>(SipHeader.Via);
                        if (viaValue == null)
                        {
                            // Illegal request

                            SetState(SipTransactionState.Terminated);
                            return;
                        }

                        sentBy = viaValue.SentByBinding;
                        if (sentBy == null || sentBy.IsHost || sentBy.Address != request.RemoteEndpoint.Address)
                        {
                            viaValue.Received = request.RemoteEndpoint.Address.ToString();
                        }

                        if (viaValue.RPort != null)
                        {
                            viaValue.RPort = request.RemoteEndpoint.Port.ToString();
                        }

                        // Determine the destination network endpoint based on the
                        // rules described on RFC 3261 (page 146).

                        if (request.SourceTransport.IsStreaming)
                        {
                            // $todo(jeff.lill):
                            //
                            // This implementation is incomplete.  To be fully
                            // compliant with the RFC, I'd have to check to
                            // see if the connection is still present in the
                            // transport and if not, use the received and
                            // rport values as described.

                            remoteEP = request.RemoteEndpoint;
                        }
                        else
                        {
                            if (viaValue.MAddr != null)
                            {
                                if (!IPAddress.TryParse(viaValue.MAddr, out address))
                                {
                                    SipException e;

                                    // Illegal request

                                    SetState(SipTransactionState.Terminated);

                                    e                = new SipException("Illegal request: Invalid [Via: maddr].");
                                    e.Transport      = transport.Name;
                                    e.SourceEndpoint = request.RemoteEndpoint;
                                    e.BadMessage     = request;

                                    throw e;
                                }

                                remoteEP = new NetworkBinding(address, viaValue.SentByBinding.Port);
                            }
                            else
                            {
                                remoteEP = request.RemoteEndpoint;
                            }
                        }

                        // INVITE and non-INVITE requests have different state machines.

                        if (request.Method == SipMethod.Invite)
                        {
                            // Start an INVITE transaction

                            SetState(SipTransactionState.InviteProceeding);

                            // If the request has a "To" header without a "tag" parameter then
                            // generate a tag.  Note that this code will cause provisional INVITE
                            // responses to include a generated tag which the RFC indicates
                            // SHOULD NOT be done.  But, it's much safer to do this once here
                            // for all transaction types, avoiding special cases, and besides,
                            // I've noticed that Asterisk includes a tag in its provisional
                            // INVITE responses.

                            toValue = request.GetHeader <SipContactValue>(SipHeader.To);
                            if (toValue != null)
                            {
                                if (toValue["tag"] == null)
                                {
                                    toValue["tag"] = SipHelper.GenerateTagID();
                                }

                                request.SetHeader(SipHeader.To, toValue);
                            }

                            // Always send an initial provisional trying response.

                            provisionalResponse = request.CreateResponse(SipStatus.Trying, null);
                            SendResponse(provisionalResponse);

                            // Setup to call the agent's OnInviteBegin() method.

                            callOnInviteBegin = true;
                            callbackMsg       = request;
                        }
                        else if (request.Method == SipMethod.Ack)
                        {
                            // Allow an ACK request to drop through to the state machine.
                        }
                        else
                        {
                            // Start a non-INVITE transaction

                            SetState(SipTransactionState.Trying);

                            // Setup to call the agent's OnRequest() method.

                            callOnRequest = true;
                            callbackMsg   = request;
                        }

                        return;
                    }

                    // Handle state specific processing

                    switch (base.State)
                    {
                    default:
                    case SipTransactionState.Unknown:

                        SysLog.LogError("Unexpected SIP transaction state.");
                        SetState(SipTransactionState.Terminated);
                        return;

                    case SipTransactionState.InviteCalling:

                        break;

                    case SipTransactionState.InviteProceeding:

                        if (provisionalResponse != null)
                        {
                            transport.Send(remoteEP, provisionalResponse);
                        }

                        break;

                    case SipTransactionState.InviteCompleted:

                        if (request.Method == SipMethod.Ack)
                        {
                            SetState(SipTransactionState.InviteConfirmed);

                            // Setup to call OnInviteComplete(ack);

                            callOnInviteComplete = true;
                            callbackMsg          = request;
                            return;
                        }

                        Assertion.Test(finalResponse != null);
                        transport.Send(remoteEP, finalResponse);
                        break;

                    case SipTransactionState.InviteConfirmed:

                        break;

                    case SipTransactionState.Trying:

                        break;

                    case SipTransactionState.Proceeding:

                        Assertion.Test(provisionalResponse != null);
                        transport.Send(remoteEP, provisionalResponse);
                        break;

                    case SipTransactionState.Completed:

                        Assertion.Test(finalResponse != null);
                        transport.Send(remoteEP, finalResponse);
                        break;

                    case SipTransactionState.Terminated:

                        break;
                    }
                }
            }
            finally
            {
                // Handle the agent callbacks outside of the lock to avoid
                // deadlock issues.

                if (callOnRequest)
                {
                    agent.OnRequest(this, callbackMsg);
                }

                if (callOnInviteBegin)
                {
                    agent.OnInviteBegin(this, request);
                }

                if (callOnInviteComplete)
                {
                    agent.OnInviteComplete(this, this.request, finalResponse, callbackMsg);
                }
            }
        }
示例#9
0
        /// <summary>
        /// Implements the background thread.
        /// </summary>
        private void DownloadThread()
        {
            DateTime    lastWarningTime = DateTime.MinValue;
            PolledTimer pollTimer;
            bool        resetTimer;

            try
            {
                // Initialize the GeoTracker file folder

                try
                {
                    Helper.CreateFileTree(dataPath);

                    if (File.Exists(downloadPath))
                    {
                        SysLog.LogWarning("GeoTracker: Deleting existing temporary [{0}] file on startup.", downloadPath);
                        Helper.DeleteFile(downloadPath);
                    }

                    if (File.Exists(decryptedPath))
                    {
                        SysLog.LogWarning("GeoTracker: Deleting existing temporary [{0}] file on startup.", decryptedPath);
                        Helper.DeleteFile(decryptedPath);
                    }
                }
                catch (Exception e)
                {
                    SysLog.LogException(e);
                }

                // Initalize the poll timer.  We'll schedule an immediate download if the data file does
                // not exist, otherwise we'll delay the polling for a random period of time between
                // 0 and 15 minutes in the hope that we'll end up staggering the polling times across
                // the server cluster (so we won't hammer the source website).

                pollTimer  = new PolledTimer(settings.IPGeocodeSourcePollInterval, false);
                resetTimer = false;

                if (!File.Exists(dataPath))
                {
                    pollTimer.FireNow();
                }
                else
                {
                    pollTimer.ResetRandomTemporary(TimeSpan.Zero, TimeSpan.FromMinutes(15));
                }

                // The polling loop.

                while (true)
                {
                    if (stopPending)
                    {
                        return;
                    }

                    try
                    {
                        if (pollDataNow)
                        {
                            pollTimer.FireNow();
                            pollDataNow = false;
                        }

                        if (pollTimer.HasFired)
                        {
                            DateTime        fileDateUtc = DateTime.UtcNow;
                            bool            isUpdate    = false;
                            double          fileSize    = 0;
                            ElapsedTimer    downloadTimer;
                            HttpWebRequest  request;
                            HttpWebResponse response;
                            HttpStatusCode  statusCode;

                            resetTimer = true;

                            // If a database file already exists then extract its last modify
                            // date and use this in an If-Modified-Since request to the source
                            // website to see if there's an updated file.

                            if (File.Exists(dataPath))
                            {
                                request         = (HttpWebRequest)WebRequest.Create(settings.IPGeocodeSourceUri);
                                request.Timeout = (int)TimeSpan.FromSeconds(30).TotalMilliseconds;

                                isUpdate    = true;
                                fileDateUtc = File.GetLastWriteTimeUtc(dataPath);

                                request.Method          = "HEAD";
                                request.IfModifiedSince = fileDateUtc;

                                try
                                {
                                    using (response = (HttpWebResponse)request.GetResponse())
                                        statusCode = response.StatusCode;
                                }
                                catch (WebException e)
                                {
                                    statusCode = ((HttpWebResponse)e.Response).StatusCode;
                                }

                                if (statusCode == HttpStatusCode.NotModified)
                                {
                                    // The source website does not have an updated file.  I'm going to
                                    // do one extra check to see if the file we have is more than 45
                                    // days old and log a warning.  Note that we're going to issue this
                                    // warning only once a week while the service is running.

                                    if (DateTime.UtcNow - fileDateUtc < TimeSpan.FromDays(45) || DateTime.UtcNow - lastWarningTime >= TimeSpan.FromDays(7))
                                    {
                                        continue;
                                    }

                                    lastWarningTime = DateTime.UtcNow;

                                    const string warning =
                                        @"GeoTracker: The local copy of the MaxMind GeoIP City or GeoLite City database is [{0}] days old 
and should be updated.  You may need to download a new copy of the database from http://maxmind.com,
decompress it and upload it to the source website at [{1}].

Note: Make sure that the website is configured with the [.DAT=application/octet-stream] MIME mapping.";

                                    SysLog.LogWarning(warning, (int)(DateTime.UtcNow - fileDateUtc).TotalDays, settings.IPGeocodeSourceUri);
                                    continue;
                                }
                            }

                            // Download the database to the temporary download file.

                            Helper.DeleteFile(downloadPath);

                            downloadTimer = new ElapsedTimer(true);
                            fileSize      = Helper.WebDownload(settings.IPGeocodeSourceUri, downloadPath, settings.IPGeocodeSourceTimeout, out response);
                            downloadTimer.Stop();

                            // Set the file times to match the Last-Modified header received from the website (it any).

                            string lastModified = response.Headers["Last-Modified"];

                            if (lastModified != null)
                            {
                                try
                                {
                                    fileDateUtc = Helper.ParseInternetDate(lastModified);
                                    File.SetCreationTimeUtc(downloadPath, fileDateUtc);
                                    File.SetLastWriteTimeUtc(downloadPath, fileDateUtc);
                                }
                                catch (Exception e)
                                {
                                    SysLog.LogException(e, "GeoTracker: Website for [{0}] returned invalid Last-Modified header [{1}].",
                                                        settings.IPGeocodeSourceUri, lastModified);
                                }
                            }

                            // Decrypt the file and set its file dates.

                            var keyChain = new KeyChain(settings.IPGeocodeSourceRsaKey);

                            using (var secureFile = new SecureFile(downloadPath, keyChain))
                            {
                                secureFile.DecryptTo(decryptedPath);
                            }

                            File.SetCreationTimeUtc(decryptedPath, fileDateUtc);
                            File.SetLastWriteTimeUtc(decryptedPath, fileDateUtc);

                            // Verify the decrypted data file and then swap in new file.

                            const string info =
                                @"GeoTracker: {0} of IP-to-location database from [{1}] completed.
Downloaded [{2:#.#}MB] bytes in [{3}].";

                            SysLog.LogInformation(info, isUpdate ? "Update download" : "Initial download", settings.IPGeocodeSourceUri, fileSize / (1024 * 1024), downloadTimer.ElapsedTime);

                            // Create a new MaxMind lookup intance and then swap it in without interrupting
                            // any queries in progress.

                            try
                            {
                                LookupService newMaxMind;

                                newMaxMind = new LookupService(decryptedPath, LookupService.GEOIP_MEMORY_CACHE);
                                newMaxMind.close();

                                maxMind = newMaxMind;
                                UpdateCount++;
                            }
                            catch (Exception e)
                            {
                                SysLog.LogException(e);
                                SysLog.LogError("GeoTracker: The MaxMind downloaded database file [{0}] appears to be corrupted.  This will be deleted so the downloader can get a fresh copy.", downloadPath);
                            }

                            lock (syncLock)
                            {
                                Helper.DeleteFile(dataPath);
                                File.Copy(decryptedPath, dataPath);
                                File.SetCreationTimeUtc(dataPath, fileDateUtc);
                                File.SetLastWriteTimeUtc(dataPath, fileDateUtc);
                            }

                            // Delete the temporary files.

                            Helper.DeleteFile(decryptedPath);
                            Helper.DeleteFile(downloadPath);
                        }
                    }
                    catch (WebException e)
                    {
                        SysLog.LogException(e);
                        SysLog.LogWarning("GeoTracker: The download of the MaxMind database file has failed. The service will try again in 1 minute.");

                        pollTimer.ResetTemporary(TimeSpan.FromMinutes(1));
                        resetTimer = false;
                    }
                    catch (ThreadAbortException e)
                    {
                        SysLog.LogException(e);
                        throw;
                    }
                    catch (Exception e)
                    {
                        SysLog.LogException(e);
                    }
                    finally
                    {
                        if (resetTimer)
                        {
                            resetTimer = false;
                            pollTimer.Reset();
                        }
                    }

                    Thread.Sleep(settings.BkInterval);
                }
            }
            finally
            {
                running = false;
            }
        }
示例#10
0
        /// <summary>
        /// Implements the background tasks.
        /// </summary>
        /// <param name="state">Not used.</param>
        private void OnBkTask(object state)
        {
            if (!isRunning)
            {
                return;
            }

            try
            {
                // Update the service run time.

                perf.Runtime.RawValue = (int)(DateTime.UtcNow - startTime).TotalMinutes;

                if (pollTimer.HasFired)
                {
                    // Execute HTTP requests for all of the configured monitor URIs
                    // and then wait for them to return or timeout before setting the health status.
                    // Note that I'm configuring the request so the Host header will be set to
                    // the header in the URI but the request will actually be submitted to the
                    // local host.

                    try
                    {
                        if (services.Count == 0)
                        {
                            isHealthy = true;
                        }
                        else
                        {
                            bool fail = false;

                            for (int i = 0; i < this.services.Count; i++)
                            {
                                var site = services[i];

                                try
                                {
                                    using (var httpConnection = new HttpConnection(HttpOption.None))
                                    {
                                        HttpRequest  request;
                                        HttpResponse response;

                                        request = new HttpRequest("GET", site.Service.Uri, null);
                                        request["X-Health-Check"] = "true";

                                        httpConnection.Connect(new IPEndPoint(IPAddress.Loopback, site.Service.Uri.Port));
                                        response = httpConnection.Query(request, SysTime.Now + TimeSpan.FromSeconds(5));

                                        if (response.Status != HttpStatus.OK)
                                        {
                                            if (site.IsHealthy)
                                            {
                                                if (site.Service.IsCritical)
                                                {
                                                    SysLog.LogError("Critical local service [{0}] transitioned to unhealthy status with code [{1}={2}].", site.Service.Uri, response.Status, (int)response.Status);
                                                }
                                                else
                                                {
                                                    SysLog.LogWarning("Noncritical local service [{0}] transitioned to unhealthy status with code [{1}={2}].", site.Service.Uri, response.Status, (int)response.Status);
                                                }
                                            }

                                            if (site.Service.IsCritical)
                                            {
                                                fail = true;
                                            }

                                            site.IsHealthy  = false;
                                            site.StatusCode = (int)response.Status;
                                        }
                                        else
                                        {
                                            if (!site.IsHealthy)
                                            {
                                                if (site.Service.IsCritical)
                                                {
                                                    SysLog.LogInformation("Critical local service [{0}] transitioned to healthy status.", site.Service.Uri);
                                                }
                                                else
                                                {
                                                    SysLog.LogInformation("Noncritical local service [{0}] transitioned to healthy status.", site.Service.Uri);
                                                }
                                            }

                                            site.IsHealthy  = true;
                                            site.StatusCode = (int)response.Status;
                                        }
                                    }
                                }
                                catch (Exception e)
                                {
                                    if (site.IsHealthy)
                                    {
                                        if (site.Service.IsCritical)
                                        {
                                            SysLog.LogError("Critical local service [{0}] transitioned to unhealthy status with exception [{1}]: {2}.", site.Service.Uri, e.GetType().Name, e.Message);
                                        }
                                        else
                                        {
                                            SysLog.LogWarning("Noncritical local service [{0}] transitioned to unhealthy status with exception [{1}]: {2}.", site.Service.Uri, e.GetType().Name, e.Message);
                                        }
                                    }

                                    if (site.Service.IsCritical)
                                    {
                                        fail = true;
                                    }

                                    site.IsHealthy  = false;
                                    site.StatusCode = 0;
                                }
                            }

                            isHealthy = !fail;
                        }
                    }
                    finally
                    {
                        pollTimer.Reset();
                    }
                }
            }
            catch (Exception e)
            {
                SysLog.LogException(e);
                isHealthy = false;
            }
            finally
            {
                // Update the status performance counter.

                this.perf.Status.RawValue = isHealthy ? 1 : 0;
            }
        }
示例#11
0
        /// <summary>
        /// Implements the background thread responsible for persisting buffered <see cref="GeoFix "/>es .
        /// </summary>
        private void FlushThread()
        {
            bool             stopCompleted = false;
            List <FixRecord> writeFixes;

            while (true)
            {
                writeFixes = null;

                try
                {
                    lock (syncLock)
                    {
                        if (!isRunning)
                        {
                            return;
                        }

                        if (stopPending || bufferedFixes.Count >= bufferSize || flushTimer.HasFired)
                        {
                            writeFixes    = bufferedFixes;
                            bufferedFixes = new List <FixRecord>(writeFixes.Count);
                        }
                    }

                    if (writeFixes != null && writeFixes.Count > 0)
                    {
                        // Build SQL batch command that to add all of the buffered fixes using
                        // the SQL script template to generate the T-SQL statements for each fix.

                        var processor = new MacroProcessor();
                        var sqlBatch  = new StringBuilder(8192);

                        foreach (var record in writeFixes)
                        {
                            if (record.EntityID == null)
                            {
                                SysLog.LogWarning("SqlGeoFixArchiver: GeoFix has a [EntityID=NULL] field and will be ignored.");
                            }

                            if (!record.Fix.TimeUtc.HasValue)
                            {
                                SysLog.LogWarning("SqlGeoFixArchiver: GeoFix has a [TimeUtc=NULL] field and will be ignored.");
                            }

                            if (double.IsNaN(record.Fix.Latitude))
                            {
                                SysLog.LogWarning("SqlGeoFixArchiver: GeoFix has a [Latitude=NaN] field and will be ignored.");
                            }

                            if (double.IsNaN(record.Fix.Longitude))
                            {
                                SysLog.LogWarning("SqlGeoFixArchiver: GeoFix has a [Longitude=NaN] field and will be ignored.");
                            }

                            processor["EntityID"]           = ToSqlLiteral(record.EntityID);
                            processor["GroupID"]            = ToSqlLiteral(record.GroupID);
                            processor["TimeUtc"]            = ToSqlLiteral(record.Fix.TimeUtc);
                            processor["Technology"]         = ToSqlLiteral(record.Fix.Technology);
                            processor["Latitude"]           = ToSqlLiteral(record.Fix.Latitude);
                            processor["Longitude"]          = ToSqlLiteral(record.Fix.Longitude);
                            processor["Altitude"]           = ToSqlLiteral(record.Fix.Altitude);
                            processor["Course"]             = ToSqlLiteral(record.Fix.Course);
                            processor["Speed"]              = ToSqlLiteral(record.Fix.Speed);
                            processor["HorizontalAccuracy"] = ToSqlLiteral(record.Fix.HorizontalAccuracy);
                            processor["VerticalAccurancy"]  = ToSqlLiteral(record.Fix.VerticalAccurancy);
                            processor["NetworkStatus"]      = ToSqlLiteral(record.Fix.NetworkStatus);

                            sqlBatch.AppendLine(processor.Expand(addScript));
                        }

                        // Submit the T-SQL batch to the server.

                        var sqlCtx = new SqlContext(conString);

                        sqlCtx.Open();
                        try
                        {
                            sqlCtx.Execute(sqlBatch.ToString());
                            node.IncrementFixesReceivedBy(writeFixes.Count);
                        }
                        catch (SqlException e)
                        {
                            const string msgTemplate =
                                @"SQL Error [Line {1}]: {0}

{2}
";
                            SysLog.LogException(e);
                            SysLog.LogError(msgTemplate, e.Message, e.LineNumber, sqlBatch);
                        }
                        finally
                        {
                            sqlCtx.Close();
                        }
                    }
                }
                catch (Exception e)
                {
                    SysLog.LogException(e);
                }
                finally
                {
                    if (writeFixes != null)
                    {
                        writeFixes = null;
                        flushTimer.Reset();
                    }
                }

                if (stopCompleted)
                {
                    return;
                }

                if (stopPending)
                {
                    // Loop one more time to archive any fixes cached while we were
                    // persisting to the database.

                    stopCompleted = true;
                    continue;
                }

                Thread.Sleep(settings.BkInterval);
            }
        }