3 # Martin von Loewis - python 3 port
5 # See the LICENSE file for legal information regarding use of this file.
7 """Class for caching TLS sessions."""
12 class SessionCache(object):
13 """This class is used by the server to cache TLS sessions.
15 Caching sessions allows the client to use TLS session resumption
16 and avoid the expense of a full handshake. To use this class,
17 simply pass a SessionCache instance into the server handshake
20 This class is thread-safe.
23 #References to these instances
24 #are also held by the caller, who may change the 'resumable'
25 #flag, so the SessionCache must return the same instances
28 def __init__(self, maxEntries=10000, maxAge=14400):
29 """Create a new SessionCache.
32 @param maxEntries: The maximum size of the cache. When this
33 limit is reached, the oldest sessions will be deleted as
34 necessary to make room for new ones. The default is 10000.
37 @param maxAge: The number of seconds before a session expires
38 from the cache. The default is 14400 (i.e. 4 hours)."""
40 self.lock = threading.Lock()
42 # Maps sessionIDs to sessions
45 #Circular list of (sessionID, timestamp) pairs
46 self.entriesList = [(None,None)] * maxEntries
52 def __getitem__(self, sessionID):
55 self._purge() #Delete old items, so we're assured of a new one
56 session = self.entriesDict[bytes(sessionID)]
58 #When we add sessions they're resumable, but it's possible
59 #for the session to be invalidated later on (if a fatal alert
60 #is returned), so we have to check for resumability before
61 #returning the session.
71 def __setitem__(self, sessionID, session):
75 self.entriesDict[bytes(sessionID)] = session
76 self.entriesList[self.lastIndex] = (sessionID, time.time())
77 self.lastIndex = (self.lastIndex+1) % len(self.entriesList)
79 #If the cache is full, we delete the oldest element to make an
81 if self.lastIndex == self.firstIndex:
82 del(self.entriesDict[self.entriesList[self.firstIndex][0]])
83 self.firstIndex = (self.firstIndex+1) % len(self.entriesList)
89 currentTime = time.time()
91 #Search through the circular list, deleting expired elements until
92 #we reach a non-expired element. Since elements in list are
93 #ordered in time, we can break once we reach the first non-expired
95 index = self.firstIndex
96 while index != self.lastIndex:
97 if currentTime - self.entriesList[index][1] > self.maxAge:
98 del(self.entriesDict[self.entriesList[index][0]])
99 index = (index+1) % len(self.entriesList)
102 self.firstIndex = index
105 import doctest, SessionCache
106 return doctest.testmod(SessionCache)
108 if __name__ == "__main__":