PageRenderTime 60ms CodeModel.GetById 53ms app.highlight 4ms RepoModel.GetById 1ms app.codeStats 0ms

/gdata/tlslite/SessionCache.py

http://radioappz.googlecode.com/
Python | 103 lines | 47 code | 18 blank | 38 comment | 5 complexity | 14790609ab341dd37903ffd11bd2bbd9 MD5 | raw file
  1"""Class for caching TLS sessions."""
  2
  3import thread
  4import time
  5
  6class SessionCache:
  7    """This class is used by the server to cache TLS sessions.
  8
  9    Caching sessions allows the client to use TLS session resumption
 10    and avoid the expense of a full handshake.  To use this class,
 11    simply pass a SessionCache instance into the server handshake
 12    function.
 13
 14    This class is thread-safe.
 15    """
 16
 17    #References to these instances
 18    #are also held by the caller, who may change the 'resumable'
 19    #flag, so the SessionCache must return the same instances
 20    #it was passed in.
 21
 22    def __init__(self, maxEntries=10000, maxAge=14400):
 23        """Create a new SessionCache.
 24
 25        @type maxEntries: int
 26        @param maxEntries: The maximum size of the cache.  When this
 27        limit is reached, the oldest sessions will be deleted as
 28        necessary to make room for new ones.  The default is 10000.
 29
 30        @type maxAge: int
 31        @param maxAge:  The number of seconds before a session expires
 32        from the cache.  The default is 14400 (i.e. 4 hours)."""
 33
 34        self.lock = thread.allocate_lock()
 35
 36        # Maps sessionIDs to sessions
 37        self.entriesDict = {}
 38
 39        #Circular list of (sessionID, timestamp) pairs
 40        self.entriesList = [(None,None)] * maxEntries
 41
 42        self.firstIndex = 0
 43        self.lastIndex = 0
 44        self.maxAge = maxAge
 45
 46    def __getitem__(self, sessionID):
 47        self.lock.acquire()
 48        try:
 49            self._purge() #Delete old items, so we're assured of a new one
 50            session = self.entriesDict[sessionID]
 51
 52            #When we add sessions they're resumable, but it's possible
 53            #for the session to be invalidated later on (if a fatal alert
 54            #is returned), so we have to check for resumability before
 55            #returning the session.
 56
 57            if session.valid():
 58                return session
 59            else:
 60                raise KeyError()
 61        finally:
 62            self.lock.release()
 63
 64
 65    def __setitem__(self, sessionID, session):
 66        self.lock.acquire()
 67        try:
 68            #Add the new element
 69            self.entriesDict[sessionID] = session
 70            self.entriesList[self.lastIndex] = (sessionID, time.time())
 71            self.lastIndex = (self.lastIndex+1) % len(self.entriesList)
 72
 73            #If the cache is full, we delete the oldest element to make an
 74            #empty space
 75            if self.lastIndex == self.firstIndex:
 76                del(self.entriesDict[self.entriesList[self.firstIndex][0]])
 77                self.firstIndex = (self.firstIndex+1) % len(self.entriesList)
 78        finally:
 79            self.lock.release()
 80
 81    #Delete expired items
 82    def _purge(self):
 83        currentTime = time.time()
 84
 85        #Search through the circular list, deleting expired elements until
 86        #we reach a non-expired element.  Since elements in list are
 87        #ordered in time, we can break once we reach the first non-expired
 88        #element
 89        index = self.firstIndex
 90        while index != self.lastIndex:
 91            if currentTime - self.entriesList[index][1] > self.maxAge:
 92                del(self.entriesDict[self.entriesList[index][0]])
 93                index = (index+1) % len(self.entriesList)
 94            else:
 95                break
 96        self.firstIndex = index
 97
 98def _test():
 99    import doctest, SessionCache
100    return doctest.testmod(SessionCache)
101
102if __name__ == "__main__":
103    _test()