357 lines
13 KiB
C#
357 lines
13 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Data;
|
|
using System.Diagnostics;
|
|
using System.Linq;
|
|
using System.ServiceProcess;
|
|
using System.Text;
|
|
using Pluto.Registration;
|
|
using System.Reflection;
|
|
using Yaulw.Thread;
|
|
|
|
namespace RegistrationServer
|
|
{
|
|
public partial class RegistrationService : ServiceBase
|
|
{
|
|
|
|
#region Internal Consts
|
|
|
|
// Threshold used to determine if system just rebooted, and service just
|
|
// started. We need to wait a little because we need to make sure the Database Server is up
|
|
internal const int NUMBER_OF_MINUTES_SERVICE_UP_THRESHOLD = 5;
|
|
internal const int NUMBER_OF_MINUTES_SYSTEM_UP_THRESHOLD = 10;
|
|
|
|
#endregion
|
|
|
|
#region Internal Statics
|
|
|
|
/// <summary>
|
|
/// Service Start Time
|
|
/// </summary>
|
|
internal static DateTime ServiceStartDT = DateTime.MinValue;
|
|
|
|
#endregion
|
|
|
|
#region Private Members
|
|
|
|
/// <summary>
|
|
/// Check if this is the first time the network got enabled
|
|
/// </summary>
|
|
private bool FirstTimeNetworkConnected = true;
|
|
|
|
/// <summary>
|
|
/// Was the Channel Activated?
|
|
/// </summary>
|
|
private bool ROHasBeenActivated = false;
|
|
|
|
/// <summary>
|
|
/// Did a System Reboot just occur?
|
|
/// </summary>
|
|
private bool SystemJustStarted_SoUseServiceThreshold = false;
|
|
private bool ServiceUpTimeReached = false;
|
|
private bool SystemThresholdNotReached = true;
|
|
|
|
/// <summary>
|
|
/// Is the Logger Setup?
|
|
/// </summary>
|
|
private bool LoggerIsSetup = false;
|
|
|
|
/// <summary>
|
|
/// Our Connectivity Timer Thread
|
|
/// </summary>
|
|
private SingleThreadTimer connectivityTimer = null;
|
|
|
|
/// <summary>
|
|
/// If for some reason the network goes down, we should re-initialize
|
|
/// everything as if nothing happened
|
|
/// </summary>
|
|
private bool NetworkOutageDetected = false;
|
|
|
|
#endregion
|
|
|
|
#region Construction
|
|
|
|
/// <summary>
|
|
/// Singleton Instance of the Service
|
|
/// </summary>
|
|
internal static RegistrationService s_RegistrationService = null;
|
|
|
|
/// <summary>
|
|
/// Constructor
|
|
/// </summary>
|
|
public RegistrationService()
|
|
{
|
|
InitializeComponent();
|
|
|
|
// Log to the Application System Log
|
|
this.EventLog.Log = "Application";
|
|
s_RegistrationService = this;
|
|
|
|
// Handle all unexpected errors
|
|
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Unhandled Domain Exception
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
|
|
{
|
|
Exception ex = (Exception)e.ExceptionObject;
|
|
String msg = "UnhandledException Occured: " + ex.Message + "\n\n" + ex.InnerException.Message;
|
|
AppLogError(msg);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Windows Event Logging
|
|
|
|
internal static void AppLogError(string errMsg)
|
|
{
|
|
s_RegistrationService.EventLog.WriteEntry(errMsg, EventLogEntryType.Error);
|
|
if (Registration.Logger != null)
|
|
Registration.Logger.Error(errMsg);
|
|
}
|
|
|
|
internal static void AppLogInfo(string infoMsg)
|
|
{
|
|
s_RegistrationService.EventLog.WriteEntry(infoMsg, EventLogEntryType.Information);
|
|
if (Registration.Logger != null)
|
|
Registration.Logger.Info(infoMsg);
|
|
}
|
|
|
|
internal static void AppLogWarning(string warnMsg)
|
|
{
|
|
s_RegistrationService.EventLog.WriteEntry(warnMsg, EventLogEntryType.Warning);
|
|
if (Registration.Logger != null)
|
|
Registration.Logger.Info(warnMsg);
|
|
}
|
|
|
|
#endregion
|
|
|
|
// usefull for debugging Service in visual studio
|
|
#if DEBUG
|
|
internal void DebugStart(string[] args)
|
|
{
|
|
DEBUGGING_ONLY.DEBUGSTEP_INTO();
|
|
OnStart(args);
|
|
}
|
|
#endif
|
|
|
|
#region System / Service Up Time
|
|
|
|
/// <summary>
|
|
/// Get Service UpTime
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
private TimeSpan GetServiceUpTime()
|
|
{
|
|
return (DateTime.Now - ServiceStartDT);
|
|
}
|
|
|
|
/// <summary>
|
|
/// For Service Handling, see if the system has been up long enough
|
|
/// Once it becomes true, it will always return true
|
|
/// </summary>
|
|
private bool HasServiceBeenUpLongEnough()
|
|
{
|
|
if (!ServiceUpTimeReached)
|
|
ServiceUpTimeReached = GetServiceUpTime().TotalMinutes >= NUMBER_OF_MINUTES_SERVICE_UP_THRESHOLD;
|
|
return ServiceUpTimeReached;
|
|
}
|
|
|
|
/// <summary>
|
|
/// For Error Handling, see if the system has been up till this threshold
|
|
/// Once it becomes false, will always return false
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
private bool IsSystemBeenUpWithinMaxThreshold()
|
|
{
|
|
if (SystemThresholdNotReached)
|
|
SystemThresholdNotReached = (Yaulw.Installer.Common.GetSystemUpTime().TotalMinutes <= NUMBER_OF_MINUTES_SYSTEM_UP_THRESHOLD);
|
|
return SystemThresholdNotReached;
|
|
}
|
|
|
|
#endregion
|
|
|
|
/// <summary>
|
|
/// Service Start-Up
|
|
/// </summary>
|
|
/// <param name="args"></param>
|
|
protected override void OnStart(string[] args)
|
|
{
|
|
try
|
|
{
|
|
// Service Started
|
|
// System just started, so make sure that service is timing out a little to make
|
|
// sure everything is up and running
|
|
SystemJustStarted_SoUseServiceThreshold = IsSystemBeenUpWithinMaxThreshold();
|
|
AppLogInfo(String.Format("MSLMobile Gateway Service started up at: {0}. System Reboot detected: {1}", DateTime.Now.ToLongTimeString(), SystemJustStarted_SoUseServiceThreshold));
|
|
ServiceStartDT = DateTime.Now;
|
|
|
|
// Internet / Network Connectivity Timer
|
|
// * Ran into issues when computer is rebooted, we need certain things working before the service can start,
|
|
// * therefore decided to put DataStore Read(), AutoUpdate, RO Connection into a Connection Timer,
|
|
// that keeps checking every 10 seconds if we have network connectivity * Enables / Disables RO Channels as needed, just in case *
|
|
AppLogInfo("MSLMobile Gateway Service starting connectivity timer.");
|
|
connectivityTimer = new SingleThreadTimer(ConnectivityHandler, (uint)TimeSpan.FromSeconds(10).TotalMilliseconds, true);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
AppLogError(String.Format("Service OnStart() Error thrown. Fatal. Can't continue: {0}", e.Message));
|
|
this.Stop();
|
|
}
|
|
}
|
|
|
|
#region Private Connectivity Timed Thread (runs every 10 Seconds)
|
|
|
|
/// <summary>
|
|
/// Single Threaded Connectivity Handler (Handles Auto-Update, ReadInDataStore(), and RO Channels)
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
private void ConnectivityHandler(object sender, Yaulw.Thread.SingleThreadTimer.STElapsedEventArgs e)
|
|
{
|
|
// System just started, we won't do anyting in here until our
|
|
// Service Startup 'NUMBER_OF_MINUTES_SERVICE_UP_THRESHOLD' timeout of is reached
|
|
if (SystemJustStarted_SoUseServiceThreshold && !HasServiceBeenUpLongEnough())
|
|
return;
|
|
|
|
// Check Connectivity,
|
|
// ~withouth basic networking being up there is nothing really to do here
|
|
bool bHasConnection = Yaulw.Net.IPHostHelper.HasConnection();
|
|
if (!bHasConnection)
|
|
{
|
|
DeactivateChannelIfActivated(true);
|
|
return;
|
|
}
|
|
|
|
// Always set up the Logger First (Needed for all subsequent DB Calls)
|
|
if (!LoggerIsSetup)
|
|
{
|
|
AppLogInfo("Setting up Logger");
|
|
Registration.Setup_Logger();
|
|
LoggerIsSetup = true;
|
|
}
|
|
|
|
// * Check to Make sure the System has been up long enough *
|
|
// Calling VerifyConnectivity() requires SQL Server to be up
|
|
// and running and hence, we can't do it right at service start when the
|
|
// server just rebooted, we wait 5 of service uptime to make sure after a server reboot,
|
|
// that the services needed are up
|
|
if (FirstTimeNetworkConnected)
|
|
{
|
|
AppLogInfo("System has been up long enough. Starting Initialization.");
|
|
|
|
// Make sure we can connect to the Database
|
|
try
|
|
{
|
|
if (!DataAccessLayer.VerifyConnectivity())
|
|
{
|
|
AppLogError("Cannot verify SQL Server Credentials upon initialization. Service must be stopped.");
|
|
this.Stop();
|
|
}
|
|
else
|
|
{
|
|
AppLogInfo("Success. SQL Server Credentials could connect upon initialization.");
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
AppLogError(String.Format("Cannot verify SQL Server Credentials upon initialization '{0}'. Service must be stopped.", ex.Message));
|
|
this.Stop();
|
|
}
|
|
FirstTimeNetworkConnected = false;
|
|
return;
|
|
}
|
|
|
|
// We have a valid SQL Server Connection, hence we can continue
|
|
if (!FirstTimeNetworkConnected)
|
|
{
|
|
// If Network disconnection occured, we should try to re-read in everything,
|
|
// to make sure we are doing the best we can
|
|
if (NetworkOutageDetected)
|
|
{
|
|
AppLogInfo("Network Outage Detected - Trying to retry connecting to SQL Server");
|
|
// Make sure we can connect to the Database
|
|
try
|
|
{
|
|
if (!DataAccessLayer.VerifyConnectivity())
|
|
AppLogError("Cannot verify SQL Server Credentials after Network Outage.");
|
|
else
|
|
AppLogInfo("Success. SQL Server Credentials could connect after Networ Outage.");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
AppLogError(String.Format("Cannot verify SQL Server Credentials after Network Outage '{0}'.", ex.Message));
|
|
}
|
|
}
|
|
|
|
// Activate the RO Channel
|
|
ActivateChannelIfNotActivated();
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Private RO Channel Helpers
|
|
|
|
/// <summary>
|
|
/// Activate all Channel
|
|
/// </summary>
|
|
private void ActivateChannelIfNotActivated()
|
|
{
|
|
if (!ROHasBeenActivated)
|
|
{
|
|
SetPort(Configuration.Port);
|
|
ServerChannel.Activate();
|
|
ROHasBeenActivated = true;
|
|
AppLogInfo(String.Format("MSLMobile Gateway Service Channel Activated on Port:{0}.", Configuration.Port));
|
|
NetworkOutageDetected = false;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Deactivate RO Channel
|
|
/// </summary>
|
|
private void DeactivateChannelIfActivated(bool bNetworkOutage)
|
|
{
|
|
if (ROHasBeenActivated)
|
|
{
|
|
ServerChannel.Deactivate();
|
|
ROHasBeenActivated = false;
|
|
AppLogInfo("MSLMobile Gateway Service Channel Deactivated.");
|
|
NetworkOutageDetected = bNetworkOutage;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
// usefull for debugging Service in visual studio
|
|
#if DEBUG
|
|
internal void DebugStop() { OnStop(); }
|
|
#endif
|
|
/// <summary>
|
|
/// SCM OnStop() call-in
|
|
/// </summary>
|
|
protected override void OnStop()
|
|
{
|
|
try
|
|
{
|
|
// First stop the internal connectivity timer
|
|
if (connectivityTimer != null)
|
|
{
|
|
AppLogInfo("MSLMobile Gateway Service connectivity timer stopped.");
|
|
connectivityTimer.Stop();
|
|
}
|
|
|
|
DeactivateChannelIfActivated(false);
|
|
AppLogInfo("End DeactivateChannelIfActivated.");
|
|
}
|
|
catch (Exception) { /* ignore */ }
|
|
}
|
|
}
|
|
}
|