From a530366938c65cf79b18fda9b526a8453aaa5f28 Mon Sep 17 00:00:00 2001 From: Gerald Elder-Vass Date: Thu, 22 Feb 2024 11:46:33 +0000 Subject: [PATCH] Use monotonic time in Python3 to avoid timeouts during NTP changes Avoids authentication timeouts and session timeouts when the time jumps forward, either by chrony (NTP) or manual time changes --- XSConsoleAuth.py | 13 ++++++++++--- XSConsoleTerm.py | 21 ++++++++++++++------- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/XSConsoleAuth.py b/XSConsoleAuth.py index e3f4c91..e0c4daa 100644 --- a/XSConsoleAuth.py +++ b/XSConsoleAuth.py @@ -25,6 +25,13 @@ import XenAPI + +if sys.version_info >= (3, 0): + getTimeStamp = time.monotonic +else: + getTimeStamp = time.time + + class Auth: instance = None @@ -68,7 +75,7 @@ def IsTestMode(self): def AuthAge(self): if self.isAuthenticated: - retVal = time.time() - self.authTimestampSeconds + retVal = getTimeStamp() - self.authTimestampSeconds else: raise Exception("Cannot get age - not authenticated") return retVal @@ -77,7 +84,7 @@ def KeepAlive(self): if self.isAuthenticated: if self.AuthAge() <= State.Inst().AuthTimeoutSeconds(): # Auth still valid, so update timestamp to now - self.authTimestampSeconds = time.time() + self.authTimestampSeconds = getTimeStamp() def LoggedInUsername(self): if (self.isAuthenticated): @@ -126,7 +133,7 @@ def ProcessLogin(self, inUsername, inPassword): if self.testingHost is not None: # Store password when testing only self.loggedInPassword = inPassword - self.authTimestampSeconds = time.time() + self.authTimestampSeconds = getTimeStamp() self.isAuthenticated = True XSLog('User authenticated successfully') diff --git a/XSConsoleTerm.py b/XSConsoleTerm.py index dfcd7c5..73c1bb6 100644 --- a/XSConsoleTerm.py +++ b/XSConsoleTerm.py @@ -30,6 +30,13 @@ from XSConsoleRootDialogue import * from XSConsoleState import * + +if sys.version_info >= (3, 0): + getTimeStamp = time.monotonic +else: + getTimeStamp = time.time + + class App: __instance = None @@ -53,9 +60,9 @@ def Build(self, inDirs = None): Importer.ImportRelativeDir(dir) def Enter(self): - startTime = time.time() + startTime = getTimeStamp() Data.Inst().Update() - elapsedTime = time.time() - startTime + elapsedTime = getTimeStamp() - startTime XSLog('Loaded initial xapi and system data in %.3f seconds' % elapsedTime) doQuit = False @@ -158,7 +165,7 @@ def NeedsRefresh(self): def HandleKeypress(self, inKeypress): handled = True Auth.Inst().KeepAlive() - self.lastWakeSeconds = time.time() + self.lastWakeSeconds = getTimeStamp() if self.layout.TopDialogue().HandleKey(inKeypress): State.Inst().SaveIfRequired() self.needsRefresh = True @@ -180,7 +187,7 @@ def HandleKeypress(self, inKeypress): def MainLoop(self): doQuit= False - startSeconds = time.time() + startSeconds = getTimeStamp() lastDataUpdateSeconds = startSeconds lastScreenUpdateSeconds = startSeconds lastGarbageCollectSeconds = startSeconds @@ -193,7 +200,7 @@ def MainLoop(self): while not doQuit: self.needsRefresh = False gotTestCommand = RemoteTest.Inst().Poll() - secondsNow = time.time() + secondsNow = getTimeStamp() try: if gotTestCommand: gotKey = None # Prevent delay whilst waiting for a keypress @@ -205,7 +212,7 @@ def MainLoop(self): XSLog('Entering sleep due to inactivity - xsconsole is now blocked waiting for a keypress') self.layout.Window(Layout.WIN_MAIN).GetKeyBlocking() XSLog('Exiting sleep') - self.lastWakeSeconds = time.time() + self.lastWakeSeconds = getTimeStamp() self.needsRefresh = True Layout.Inst().PopDialogue() else: @@ -234,7 +241,7 @@ def MainLoop(self): gotKey = None break - secondsNow = time.time() + secondsNow = getTimeStamp() secondsRunning = secondsNow - startSeconds if data.host.address('') == '' or len(data.derived.managementpifs([])) == 0: