/// <summary> /// Constructor for passing in parameters. /// </summary> public TClientStillAliveCheck(TConnectedClient AConnectedClient, TClientServerConnectionType AClientServerConnectionType, TDelegateTearDownAppDomain ATearDownAppDomain, string AUser = "") { FClientObject = AConnectedClient; ClientName = FClientObject.ClientName; // Note: calls to TLogging here only go to the console. The log file doesn't get initialised in TLogging until TClientDomainManager.EstablishDBConnection() TLogging.LogAtLevel(10, "TClientStillAliveCheck (for ClientName '" + ClientName + "'') created"); Int32 ClientStillAliveTimeout = TAppSettingsManager.GetInt32("Server.ClientKeepAliveTimeoutAfterXSeconds_LAN", 60); UClientStillAliveTimeout = ClientStillAliveTimeout; UClientStillAliveCheckInterval = TAppSettingsManager.GetInt32("Server.ClientKeepAliveCheckIntervalInSeconds", 60); UTearDownAppDomain = ATearDownAppDomain; // UTearDownAppDomainToken = ATearDownAppDomainToken; TLogging.LogAtLevel(2, "ClientStillAliveTimeout: " + ClientStillAliveTimeout.ToString() + "; " + "ClientKeepAliveCheckIntervalInSeconds: " + UClientStillAliveCheckInterval.ToString()); // Start ClientStillAliveCheckThread UKeepServerAliveCheck = true; UClientStillAliveCheckThread = new Thread(new ThreadStart(ClientStillAliveCheckThread)); UClientStillAliveCheckThread.Name = "ClientStillAliveCheckThread" + Guid.NewGuid().ToString(); UClientStillAliveCheckThread.IsBackground = true; UClientStillAliveCheckThread.Start(); TLogging.LogAtLevel(10, "TClientStillAliveCheck (for ClientName '" + ClientName + "'): started " + UClientStillAliveCheckThread.Name); }
/// <summary> /// Constructor for passing in parameters. /// </summary> public TClientStillAliveCheck(TConnectedClient AConnectedClient, TClientServerConnectionType AClientServerConnectionType, TDelegateTearDownAppDomain ATearDownAppDomain, string AUser = "") { FClientObject = AConnectedClient; ClientName = FClientObject.ClientName; Int32 ClientStillAliveTimeout; // Note: calls to TLogging here only go to the console. The log file doesn't get initialised in TLogging until TClientDomainManager.EstablishDBConnection() TLogging.LogAtLevel(10, "TClientStillAliveCheck (for ClientName '" + ClientName + "'') created"); // Determine timeout limit (different for Clients connected via LAN or Remote) if (AClientServerConnectionType == TClientServerConnectionType.csctRemote) { ClientStillAliveTimeout = TSrvSetting.ClientKeepAliveTimeoutAfterXSecondsRemote; } else if (AClientServerConnectionType == TClientServerConnectionType.csctLAN) { ClientStillAliveTimeout = TSrvSetting.ClientKeepAliveTimeoutAfterXSecondsLAN; } else { ClientStillAliveTimeout = TSrvSetting.ClientKeepAliveTimeoutAfterXSecondsLAN; } UClientStillAliveTimeout = ClientStillAliveTimeout; UClientStillAliveCheckInterval = TSrvSetting.ClientKeepAliveCheckIntervalInSeconds; UTearDownAppDomain = ATearDownAppDomain; // UTearDownAppDomainToken = ATearDownAppDomainToken; TLogging.LogAtLevel(2, "ClientStillAliveTimeout: " + ClientStillAliveTimeout.ToString() + "; " + "ClientKeepAliveCheckIntervalInSeconds: " + UClientStillAliveCheckInterval.ToString()); // Start ClientStillAliveCheckThread UKeepServerAliveCheck = true; UClientStillAliveCheckThread = new Thread(new ThreadStart(ClientStillAliveCheckThread)); UClientStillAliveCheckThread.Name = "ClientStillAliveCheckThread" + Guid.NewGuid().ToString(); UClientStillAliveCheckThread.IsBackground = true; UClientStillAliveCheckThread.Start(); TLogging.LogAtLevel(10, "TClientStillAliveCheck (for ClientName '" + ClientName + "'): started " + UClientStillAliveCheckThread.Name); }
/// <summary> /// Constructor for passing in parameters. /// </summary> public TClientStillAliveCheck(TConnectedClient AConnectedClient, TClientServerConnectionType AClientServerConnectionType, TDelegateTearDownAppDomain ATearDownAppDomain) { FClientObject = AConnectedClient; ClientName = FClientObject.ClientName; Int32 ClientStillAliveTimeout; TLogging.LogAtLevel(2, "TClientStillAliveCheck (for ClientName '" + ClientName + "'') created"); // Determine timeout limit (different for Clients connected via LAN or Remote) if (AClientServerConnectionType == TClientServerConnectionType.csctRemote) { ClientStillAliveTimeout = TSrvSetting.ClientKeepAliveTimeoutAfterXSecondsRemote; } else if (AClientServerConnectionType == TClientServerConnectionType.csctLAN) { ClientStillAliveTimeout = TSrvSetting.ClientKeepAliveTimeoutAfterXSecondsLAN; } else { ClientStillAliveTimeout = TSrvSetting.ClientKeepAliveTimeoutAfterXSecondsLAN; } UClientStillAliveTimeout = ClientStillAliveTimeout; UClientStillAliveCheckInterval = TSrvSetting.ClientKeepAliveCheckIntervalInSeconds; UTearDownAppDomain = ATearDownAppDomain; // UTearDownAppDomainToken = ATearDownAppDomainToken; TLogging.LogAtLevel(2, "ClientStillAliveTimeout: " + ClientStillAliveTimeout.ToString() + "; " + "ClientKeepAliveCheckIntervalInSeconds: " + UClientStillAliveCheckInterval.ToString()); // Start ClientStillAliveCheckThread UKeepServerAliveCheck = true; UClientStillAliveCheckThread = new Thread(new ThreadStart(ClientStillAliveCheckThread)); UClientStillAliveCheckThread.Name = "ClientStillAliveCheckThread" + Guid.NewGuid().ToString(); UClientStillAliveCheckThread.IsBackground = true; UClientStillAliveCheckThread.Start(); TLogging.LogAtLevel(2, "TClientStillAliveCheck (for ClientName '" + ClientName + "'): started ClientStillAliveCheckThread."); }
/// <summary> /// Called by a Client to request connection to the Petra Server. /// /// Authenticate the user and create a sesssion for the user. /// /// </summary> /// <param name="AUserName">Username with which the Client connects</param> /// <param name="APassword">Password with which the Client connects</param> /// <param name="AClientComputerName">Computer name of the Client</param> /// <param name="AClientExeVersion"></param> /// <param name="AClientIPAddress">IP Address of the Client</param> /// <param name="AClientServerConnectionType">Type of the connection (eg. LAN, Remote)</param> /// <param name="AClientID">Server-assigned ID of the Client</param> /// <param name="AWelcomeMessage"></param> /// <param name="ASystemEnabled"></param> /// <param name="ASiteKey"></param> /// <param name="ADataBase"></param> public static TConnectedClient ConnectClient(String AUserName, String APassword, String AClientComputerName, String AClientIPAddress, System.Version AClientExeVersion, TClientServerConnectionType AClientServerConnectionType, out System.Int32 AClientID, out String AWelcomeMessage, out Boolean ASystemEnabled, out System.Int64 ASiteKey, TDataBase ADataBase = null) { TDataBase DBConnectionObj = null; TDBTransaction ReadWriteTransaction = new TDBTransaction(); bool SystemEnabled = true; string WelcomeMessage = String.Empty; Int64 SiteKey = -1; TConnectedClient ConnectedClient = null; if (TLogging.DL >= 10) { TLogging.Log( "Loaded Assemblies in AppDomain " + Thread.GetDomain().FriendlyName + " (at call of ConnectClient):", TLoggingType.ToConsole | TLoggingType.ToLogfile); foreach (Assembly tmpAssembly in Thread.GetDomain().GetAssemblies()) { TLogging.Log(tmpAssembly.FullName, TLoggingType.ToConsole | TLoggingType.ToLogfile); } } /* * Every Client Connection request is coming in in a separate Thread * (.NET Remoting does that for us and this is good!). However, the next block * of code must be executed only by exactly ONE thread at the same time to * preserve the integrity of Client tracking! */ try { // TODORemoting if (Monitor.TryEnter(UConnectClientMonitor, TSrvSetting.ClientConnectionTimeoutAfterXSeconds * 1000)) { if (Thread.CurrentThread.Name == String.Empty) { Thread.CurrentThread.Name = "Client_" + AUserName + "__CLIENTCONNECTION_THREAD"; } #region Logging if (TLogging.DL >= 4) { Console.WriteLine(FormatClientList(false)); Console.WriteLine(FormatClientList(true)); } if (TLogging.DL >= 4) { TLogging.Log("Client '" + AUserName + "' is connecting...", TLoggingType.ToConsole | TLoggingType.ToLogfile); } else { TLogging.Log("Client '" + AUserName + "' is connecting...", TLoggingType.ToLogfile); } #endregion // check for username, if it is an email address if (AUserName.Contains('@')) { AUserName = GetUserIDFromEmail(AUserName); } #region Variable assignments // we are not really using the ClientID anymore, but the session ID! AClientID = (short)0; string ClientName = AUserName.ToUpper() + "_" + AClientID.ToString(); #endregion ConnectedClient = new TConnectedClient(AClientID, AUserName.ToUpper(), ClientName, AClientComputerName, AClientIPAddress, AClientServerConnectionType, ClientName); #region Client Version vs. Server Version check if (TLogging.DL >= 9) { Console.WriteLine( "Client EXE Program Version: " + AClientExeVersion.ToString() + "; Server EXE Program Version: " + TSrvSetting.ApplicationVersion.ToString()); } if (TSrvSetting.ApplicationVersion.Compare(new TFileVersionInfo(AClientExeVersion)) != 0) { ConnectedClient.SessionStatus = TSessionStatus.adsStopped; #region Logging if (TLogging.DL >= 4) { TLogging.Log( "Client '" + AUserName + "' tried to connect, but its Program Version (" + AClientExeVersion.ToString() + ") doesn't match! Aborting Client Connection!", TLoggingType.ToConsole | TLoggingType.ToLogfile); } else { TLogging.Log( "Client '" + AUserName + "' tried to connect, but its Program Version (" + AClientExeVersion.ToString() + ") doesn't match! Aborting Client Connection!", TLoggingType.ToLogfile); } #endregion throw new EClientVersionMismatchException(String.Format(StrClientServerExeProgramVersionMismatchMessage, AClientExeVersion.ToString(), TSrvSetting.ApplicationVersion.ToString())); } #endregion #region Login request verification (incl. User authentication) DBConnectionObj = DBAccess.Connect("ConnectClient (User Login)", ADataBase); bool SubmitOK = false; DBConnectionObj.WriteTransaction(ref ReadWriteTransaction, ref SubmitOK, delegate { // Perform login checks such as User authentication and Site Key check try { PerformLoginChecks(AUserName, APassword, AClientComputerName, AClientIPAddress, out SystemEnabled, ReadWriteTransaction); } #region Exception handling catch (EPetraSecurityException) { #region Logging if (TLogging.DL >= 4) { TLogging.Log( "Client '" + AUserName + "' tried to connect, but it failed the Login Checks. Aborting Client Connection!", TLoggingType.ToConsole | TLoggingType.ToLogfile); } else { TLogging.Log( "Client '" + AUserName + "' tried to connect, but it failed the Login Checks. Aborting Client Connection!", TLoggingType.ToLogfile); } #endregion ConnectedClient.SessionStatus = TSessionStatus.adsStopped; // We need to set this flag to true here to get the failed login to be stored in the DB!!! SubmitOK = true; throw; } catch (Exception) { ConnectedClient.SessionStatus = TSessionStatus.adsStopped; throw; } #endregion // Login Checks were successful! ConnectedClient.SessionStatus = TSessionStatus.adsConnectingLoginOK; // Retrieve Welcome message and SiteKey try { if (UMaintenanceLogonMessage != null) { WelcomeMessage = UMaintenanceLogonMessage.GetLogonMessage(AUserName, true, ReadWriteTransaction); } else { WelcomeMessage = "Welcome"; } // we could do this directly, or via an interface, similar to LogonMessage, see above string sql = "SELECT s_default_value_c FROM s_system_defaults WHERE s_default_code_c = 'SiteKey'"; try { SiteKey = Convert.ToInt64(DBConnectionObj.ExecuteScalar(sql, ReadWriteTransaction)); } catch (EOPDBException) { // there is no site key defined yet. SiteKey = -1; } } catch (Exception) { ConnectedClient.SessionStatus = TSessionStatus.adsStopped; throw; } SubmitOK = true; }); #endregion /* * Uncomment the following statement to be able to better test how the * Client reacts when it tries to connect and receives a * ELoginFailedServerTooBusyException. */ // Thread.Sleep(7000); /* * Notify all waiting Clients (that have not timed out yet) that they can * now try to connect... */ // TODORemoting Monitor.PulseAll(UConnectClientMonitor); } // TODORemoting else { /* * Throw Exception to tell any timed-out connecting Client that the Server * is too busy to accept connect requests at the moment. */ // TODORemoting throw new ELoginFailedServerTooBusyException(); } } finally { // TODORemoting Monitor.Exit(UConnectClientMonitor); } ConnectedClient.StartSession(); #region Logging // // Assemblies successfully loaded into Client AppDomain // if (TLogging.DL >= 4) { TLogging.Log( "Client '" + AUserName + "' successfully connected. ClientID: " + AClientID.ToString(), TLoggingType.ToConsole | TLoggingType.ToLogfile); } else { TLogging.Log("Client '" + AUserName + "' successfully connected. ClientID: " + AClientID.ToString(), TLoggingType.ToLogfile); } #endregion ASystemEnabled = SystemEnabled; AWelcomeMessage = WelcomeMessage; ASiteKey = SiteKey; return(ConnectedClient); }
/// <summary> /// Constructor for passing in parameters. /// </summary> public TClientStillAliveCheck(TConnectedClient AConnectedClient, TClientServerConnectionType AClientServerConnectionType, TDelegateTearDownAppDomain ATearDownAppDomain) { FClientObject = AConnectedClient; ClientName = FClientObject.ClientName; Int32 ClientStillAliveTimeout; TLogging.LogAtLevel(2, "TClientStillAliveCheck (for ClientName '" + ClientName + "'') created"); // Determine timeout limit (different for Clients connected via LAN or Remote) if (AClientServerConnectionType == TClientServerConnectionType.csctRemote) { ClientStillAliveTimeout = TSrvSetting.ClientKeepAliveTimeoutAfterXSecondsRemote; } else if (AClientServerConnectionType == TClientServerConnectionType.csctLAN) { ClientStillAliveTimeout = TSrvSetting.ClientKeepAliveTimeoutAfterXSecondsLAN; } else { ClientStillAliveTimeout = TSrvSetting.ClientKeepAliveTimeoutAfterXSecondsLAN; } UClientStillAliveTimeout = ClientStillAliveTimeout; UClientStillAliveCheckInterval = TSrvSetting.ClientKeepAliveCheckIntervalInSeconds; UTearDownAppDomain = ATearDownAppDomain; // UTearDownAppDomainToken = ATearDownAppDomainToken; TLogging.LogAtLevel(2, "ClientStillAliveTimeout: " + ClientStillAliveTimeout.ToString() + "; " + "ClientKeepAliveCheckIntervalInSeconds: " + UClientStillAliveCheckInterval.ToString()); // Start ClientStillAliveCheckThread UKeepServerAliveCheck = true; UClientStillAliveCheckThread = new Thread(new ThreadStart(ClientStillAliveCheckThread)); UClientStillAliveCheckThread.Name = "ClientStillAliveCheckThread" + Guid.NewGuid().ToString(); UClientStillAliveCheckThread.IsBackground = true; UClientStillAliveCheckThread.Start(); TLogging.LogAtLevel(2, "TClientStillAliveCheck (for ClientName '" + ClientName + "'): started ClientStillAliveCheckThread."); }
/// <summary> /// Called by a Client to request connection to the Petra Server. /// /// Authenticate the user and create a sesssion for the user. /// /// </summary> /// <param name="AUserName">Username with which the Client connects</param> /// <param name="APassword">Password with which the Client connects</param> /// <param name="AClientComputerName">Computer name of the Client</param> /// <param name="AClientExeVersion"></param> /// <param name="AClientIPAddress">IP Address of the Client</param> /// <param name="AClientServerConnectionType">Type of the connection (eg. LAN, Remote)</param> /// <param name="AClientID">Server-assigned ID of the Client</param> /// <param name="AWelcomeMessage"></param> /// <param name="ASystemEnabled"></param> /// <param name="AUserInfo"></param> public static TConnectedClient ConnectClient(String AUserName, String APassword, String AClientComputerName, String AClientIPAddress, System.Version AClientExeVersion, TClientServerConnectionType AClientServerConnectionType, out System.Int32 AClientID, out String AWelcomeMessage, out Boolean ASystemEnabled, out IPrincipal AUserInfo) { TConnectedClient ConnectedClient = null; if (TLogging.DL >= 10) { TLogging.Log( "Loaded Assemblies in AppDomain " + Thread.GetDomain().FriendlyName + " (at call of ConnectClient):", TLoggingType.ToConsole | TLoggingType.ToLogfile); foreach (Assembly tmpAssembly in Thread.GetDomain().GetAssemblies()) { TLogging.Log(tmpAssembly.FullName, TLoggingType.ToConsole | TLoggingType.ToLogfile); } } /* * Every Client Connection request is coming in in a separate Thread * (.NET Remoting does that for us and this is good!). However, the next block * of code must be executed only by exactly ONE thread at the same time to * preserve the integrity of Client tracking! */ try { // TODORemoting if (Monitor.TryEnter(UConnectClientMonitor, TSrvSetting.ClientConnectionTimeoutAfterXSeconds * 1000)) { if (Thread.CurrentThread.Name == String.Empty) { Thread.CurrentThread.Name = "Client_" + AUserName + "__CLIENTCONNECTION_THREAD"; } #region Logging if (TLogging.DL >= 4) { Console.WriteLine(FormatClientList(false)); Console.WriteLine(FormatClientList(true)); } if (TLogging.DL >= 4) { TLogging.Log("Client '" + AUserName + "' is connecting...", TLoggingType.ToConsole | TLoggingType.ToLogfile); } else { TLogging.Log("Client '" + AUserName + "' is connecting...", TLoggingType.ToLogfile); } #endregion #region Variable assignments AClientID = (short)FClientsConnectedTotal; FClientsConnectedTotal++; string ClientName = AUserName.ToUpper() + "_" + AClientID.ToString(); #endregion try { if (Monitor.TryEnter(UClientObjects.SyncRoot)) { ConnectedClient = new TConnectedClient(AClientID, AUserName.ToUpper(), ClientName, AClientComputerName, AClientIPAddress, AClientServerConnectionType, ClientName); // Add the new Client to UClientObjects SortedList UClientObjects.Add((object)AClientID, ConnectedClient); } } finally { Monitor.Exit(UClientObjects.SyncRoot); } #region Client Version vs. Server Version check if (TLogging.DL >= 9) { Console.WriteLine( "Client EXE Program Version: " + AClientExeVersion.ToString() + "; Server EXE Program Version: " + TSrvSetting.ApplicationVersion.ToString()); } if (TSrvSetting.ApplicationVersion.Compare(new TFileVersionInfo(AClientExeVersion)) != 0) { ConnectedClient.SessionStatus = TSessionStatus.adsStopped; #region Logging if (TLogging.DL >= 4) { TLogging.Log( "Client '" + AUserName + "' tried to connect, but its Program Version (" + AClientExeVersion.ToString() + ") doesn't match! Aborting Client Connection!", TLoggingType.ToConsole | TLoggingType.ToLogfile); } else { TLogging.Log( "Client '" + AUserName + "' tried to connect, but its Program Version (" + AClientExeVersion.ToString() + ") doesn't match! Aborting Client Connection!", TLoggingType.ToLogfile); } #endregion throw new EClientVersionMismatchException(String.Format(StrClientServerExeProgramVersionMismatchMessage, AClientExeVersion.ToString(), TSrvSetting.ApplicationVersion.ToString())); } #endregion #region Login request verification (incl. User authentication) // Perform login checks such as User authentication and Site Key check try { AUserInfo = PerformLoginChecks(AUserName, APassword, AClientComputerName, AClientIPAddress, out ASystemEnabled); } catch (EPetraSecurityException) #region Exception handling { #region Logging if (TLogging.DL >= 4) { TLogging.Log("Client '" + AUserName + "' tried to connect, but it failed the Login Checks. Aborting Client Connection!", TLoggingType.ToConsole | TLoggingType.ToLogfile); } else { TLogging.Log("Client '" + AUserName + "' tried to connect, but it failed the Login Checks. Aborting Client Connection!", TLoggingType.ToLogfile); } #endregion ConnectedClient.SessionStatus = TSessionStatus.adsStopped; throw; } catch (Exception) { ConnectedClient.SessionStatus = TSessionStatus.adsStopped; throw; } #endregion // Login Checks were successful! ConnectedClient.SessionStatus = TSessionStatus.adsConnectingLoginOK; #endregion // Retrieve Welcome message try { if (UMaintenanceLogonMessage != null) { AWelcomeMessage = UMaintenanceLogonMessage.GetLogonMessage(AUserInfo, true); } else { AWelcomeMessage = "Welcome"; } } catch (Exception) { ConnectedClient.SessionStatus = TSessionStatus.adsStopped; throw; } /* * Uncomment the following statement to be able to better test how the * Client reacts when it tries to connect and receives a * ELoginFailedServerTooBusyException. */ // Thread.Sleep(7000); /* * Notify all waiting Clients (that have not timed out yet) that they can * now try to connect... */ // TODORemoting Monitor.PulseAll(UConnectClientMonitor); } // TODORemoting else { /* * Throw Exception to tell any timed-out connecting Client that the Server * is too busy to accept connect requests at the moment. */ // TODORemoting throw new ELoginFailedServerTooBusyException(); } } finally { // TODORemoting Monitor.Exit(UConnectClientMonitor); } ConnectedClient.StartSession(new TDelegateTearDownAppDomain(DisconnectClient)); #region Logging // // Assemblies successfully loaded into Client AppDomain // if (TLogging.DL >= 4) { TLogging.Log( "Client '" + AUserName + "' successfully connected (took " + ConnectedClient.FClientConnectionFinishedTime.Subtract( ((TConnectedClient)UClientObjects[(object)AClientID]).FClientConnectionStartTime). TotalSeconds.ToString() + " sec). ClientID: " + AClientID.ToString(), TLoggingType.ToConsole | TLoggingType.ToLogfile); } else { TLogging.Log("Client '" + AUserName + "' successfully connected. ClientID: " + AClientID.ToString(), TLoggingType.ToLogfile); } #endregion return ConnectedClient; }