Exemple #1
0
        private void CleanupDisconnectedSession(RemoteSessionExitCode exitCode)
        {
            try
            {
                _application.Lock();

                #region session

                // unregister the remote session at the application level
                var remoteSessions = (IDictionary <Guid, RemoteSession>)_application[HttpApplicationStateVariables.RemoteSessions.ToString()];
                if (remoteSessions.ContainsKey(_remoteSessionManager.RemoteSession.Id))
                {
                    remoteSessions.Remove(_remoteSessionManager.RemoteSession.Id);
                }

                #endregion

                #region session sharing

                // remove the remote session guest(s)
                var guests         = new List <SharingInfo>();
                var sharedSessions = (IDictionary <Guid, SharingInfo>)_application[HttpApplicationStateVariables.SharedRemoteSessions.ToString()];
                foreach (var sharingInfo in sharedSessions.Values)
                {
                    if (sharingInfo.RemoteSession.Id.Equals(_remoteSessionManager.RemoteSession.Id))
                    {
                        guests.Add(sharingInfo);
                    }
                }

                foreach (var guest in guests)
                {
                    sharedSessions.Remove(guest.GuestInfo.Id);
                }

                #endregion

                #region application pool recycling

                /*
                 * application pool recycling may seem a bit extreme, but the garbage collector doesn't return the freed memory to the operating system
                 * instead, it makes it available to the memory workspace of the application pool process, which in turn uses it for faster memory allocation later
                 * while this is fine for most usage, this becomes critical when the OS is under memory pressure
                 * if that occurs, the process is meant to return its unused memory to the OS
                 * in reality, this is not always true; so the system becomes slow (hdd swap) and unstable
                 *
                 * memory usage of a process under Windows: https://dzone.com/articles/windows-process-memory-usage-demystified
                 * tool: https://technet.microsoft.com/en-us/sysinternals/vmmap.aspx
                 * garbage collector: https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/fundamentals
                 * reallocation of freed memory: https://stackoverflow.com/questions/28614210/why-doesnt-net-release-unused-memory-back-to-os-when-physical-95
                 */
                bool idleAppPoolRecycling;
                if (!bool.TryParse(ConfigurationManager.AppSettings["IdleAppPoolRecycling"], out idleAppPoolRecycling))
                {
                    idleAppPoolRecycling = false;
                }

                // connect from a login page or url
                bool loginEnabled;
                if (!bool.TryParse(ConfigurationManager.AppSettings["LoginEnabled"], out loginEnabled))
                {
                    loginEnabled = true;
                }

                // if enabled, url of the login page
                var loginUrl = string.Empty;
                if (loginEnabled)
                {
                    loginUrl = ConfigurationManager.AppSettings["LoginUrl"];
                }

                // recycle only if enabled and when there is no active remote session
                // don't recycle if using the enterprise mode (if there are enterprise sessions, they musn't be dropped!)
                // don't recycle in case of connection failure, so that the page can handle it (show the related error dialog)
                if (idleAppPoolRecycling &&
                    remoteSessions.Count == 0 &&
                    (_enterpriseClient.GetMode() == EnterpriseMode.None) &&
                    (exitCode == RemoteSessionExitCode.Success || exitCode == RemoteSessionExitCode.SessionDisconnectFromMenu || exitCode == RemoteSessionExitCode.SessionLogoutFromMenu))
                {
                    // if using a custom login page, the application pool must be recycled after the redirect
                    if (!string.IsNullOrEmpty(loginUrl))
                    {
                        // redirect to the custom login page
                        _remoteSessionManager.SendMessage(new RemoteSessionMessage {
                            Type = MessageType.Disconnected, Prefix = "disconnected"
                        });

                        // give some time for the redirection
                        Thread.Sleep(2000);

                        // the gateway doesn't have enough rights to recycle the application pool, this is delegated to the myrtille services
                        _applicationPoolClient.RecycleApplicationPool(Environment.UserName);
                    }
                    // otherwise, the application pool must be recycled before the redirect
                    // the browser will acquire a new http session
                    else
                    {
                        // the gateway doesn't have enough rights to recycle the application pool, this is delegated to the myrtille services
                        _applicationPoolClient.RecycleApplicationPool(Environment.UserName);

                        // give some time for the recycling
                        Thread.Sleep(2000);

                        // redirect to the default login page (empty if login is not enabled)
                        _remoteSessionManager.SendMessage(new RemoteSessionMessage {
                            Type = MessageType.Disconnected, Prefix = "disconnected"
                        });
                    }
                }
                else
                {
                    // redirect to the login page (or the hosts dashboard in enterprise mode)
                    _remoteSessionManager.SendMessage(new RemoteSessionMessage {
                        Type = MessageType.Disconnected, Prefix = "disconnected"
                    });
                }

                #endregion
            }
            catch (Exception exc)
            {
                Trace.TraceError("Failed to cleanup disconnected session, remote session {0} ({1})", _remoteSessionManager.RemoteSession.Id, exc);
                throw;
            }
            finally
            {
                _application.UnLock();
            }
        }
Exemple #2
0
        public bool SetConnectionExitCode(Guid connectionId, string IPAddress, Guid vmGuid, RemoteSessionExitCode exitCode)
        {
            if (string.IsNullOrWhiteSpace(IPAddress) && vmGuid == Guid.Empty)
            {
                throw new ArgumentException("ipAddress and VmGuid cannot both be null");
            }

            // the exit code enum list is not exhaustive (wfreerdp returns a GetLastError() integer and I wasn't able to test every possible ways for the process to exit or crash)
            // you may want to allow an (int) exit code which is not present into the enum
            // if/when you identify its meaning, you can add it into the enum
            //if (!Enum.IsDefined(typeof(RemoteSessionExitCode), exitCode))
            //{
            //    throw new ArgumentException(nameof(exitCode));
            //}

            return(_connectionService.SetConnectionExitCode(connectionId, IPAddress, vmGuid, exitCode));
        }
        public bool SetConnectionExitCode(Guid connectionId, string IPAddress, Guid vmGuid, RemoteSessionExitCode exitCode)
        {
            var restRequest  = new RestRequest($"SetConnectionExitCode?connectionId={connectionId}&IPAddress={IPAddress}&vmGuid={vmGuid}&exitCode={exitCode}", Method.GET);
            var restResponse = restClient.Execute(restRequest);

            if (restResponse.ResponseStatus != ResponseStatus.Completed)
            {
                throw new Exception(string.Format("Failed to call SetConnectionExitCode; response status: {0}, code: {1}, message: {2}", restResponse.ResponseStatus, restResponse.StatusCode, restResponse.ErrorMessage));
            }
            return(JsonConvert.DeserializeObject <bool>(restResponse.Content));
        }
Exemple #4
0
        public bool SetConnectionExitCode(Guid connectionId, string IPAddress, Guid VMGuid, RemoteSessionExitCode exitCode)
        {
            var connection = connections[connectionId] as Connection;

            if (connection != null)
            {
                Trace.TraceInformation("connection: {0}, ip={1}, vm={2}, exit code={3}", connectionId, IPAddress, VMGuid != Guid.Empty ? VMGuid.ToString() : string.Empty, exitCode);
                connection.ExitCode = exitCode;
                return(true);
            }

            Trace.TraceInformation("invalid connection: {0}", connectionId);
            return(false);
        }