SSL_ShutdownServerSessionIDCache no longer leaks the cache memory.

Bug 222065. r=wchang0222
This commit is contained in:
nelsonb%netscape.com 2003-10-19 01:25:10 +00:00
Родитель 2584fa08fb
Коммит f8af4da928
1 изменённых файлов: 165 добавлений и 126 удалений

Просмотреть файл

@ -32,7 +32,7 @@
* may use your version of this file under either the MPL or the
* GPL.
*
* $Id: sslsnce.c,v 1.25 2003-03-27 03:07:47 nelsonb%netscape.com Exp $
* $Id: sslsnce.c,v 1.26 2003-10-19 01:25:10 nelsonb%netscape.com Exp $
*/
/* Note: ssl_FreeSID() in sslnonce.c gets used for both client and server
@ -64,7 +64,7 @@
* sidCacheEntry sidCacheData[ numSIDCacheEntries];
* certCacheEntry certCacheData[numCertCacheEntries];
* SSLWrappedSymWrappingKey keyCacheData[kt_kea_size][SSL_NUM_WRAP_MECHS];
* } sharedMemCacheData;
* } cacheMemCacheData;
*/
#include "nssrenam.h"
#include "seccomon.h"
@ -183,7 +183,7 @@ typedef struct sidCacheSetStr sidCacheSet;
struct cacheDescStr {
PRUint32 sharedMemSize;
PRUint32 cacheMemSize;
PRUint32 numSIDCacheLocks;
PRUint32 numSIDCacheSets;
@ -201,9 +201,12 @@ struct cacheDescStr {
PRUint32 ssl2Timeout;
PRUint32 ssl3Timeout;
PRUint32 numSIDCacheLocksInitialized;
/* These values are volatile, and are accessed through sharedCache-> */
PRUint32 nextCertCacheEntry; /* certCacheLock protects */
PRBool stopPolling;
PRBool everInherited;
/* The private copies of these values are pointers into shared mem */
/* The copies of these values in shared memory are merely offsets */
@ -216,11 +219,11 @@ struct cacheDescStr {
SSLWrappedSymWrappingKey * keyCacheData;
/* Only the private copies of these pointers are valid */
char * sharedMem;
char * cacheMem;
struct cacheDescStr * sharedCache; /* shared copy of this struct */
PRFileMap * cacheMemMap;
PRThread * poller;
PRBool shared;
PRBool shared;
};
typedef struct cacheDescStr cacheDesc;
@ -263,15 +266,14 @@ static sslPID myPid;
static PRUint32 ssl_max_sid_cache_locks = MAX_SID_CACHE_LOCKS;
/* forward static function declarations */
static PRUint32 SIDindex(cacheDesc *cache, const PRIPv6Addr *addr, PRUint8 *s, unsigned nl);
static PRUint32 SIDindex(cacheDesc *cache, const PRIPv6Addr *addr, PRUint8 *s,
unsigned nl);
static SECStatus LaunchLockPoller(cacheDesc *cache);
struct inheritanceStr {
PRUint32 sharedMemSize;
PRUint16 fmStrLen;
PRUint32 cacheMemSize;
PRUint32 fmStrLen;
};
typedef struct inheritanceStr inheritance;
@ -881,24 +883,60 @@ long gettid(void)
}
#endif
static void
CloseCache(cacheDesc *cache)
{
int locks_initialized = cache->numSIDCacheLocksInitialized;
if (cache->cacheMem) {
/* If everInherited is true, this shared cache was (and may still
** be) in use by multiple processes. We do not wish to destroy
** the mutexes while they are still in use.
*/
if (PR_FALSE == cache->sharedCache->everInherited) {
sidCacheLock *pLock = cache->sidCacheLocks;
for (; locks_initialized > 0; --locks_initialized, ++pLock ) {
sslMutex_Destroy(&pLock->mutex);
}
}
if (cache->shared) {
PR_MemUnmap(cache->cacheMem, cache->cacheMemSize);
} else {
PORT_Free(cache->cacheMem);
}
cache->cacheMem = NULL;
}
if (cache->cacheMemMap) {
PR_CloseFileMap(cache->cacheMemMap);
cache->cacheMemMap = NULL;
}
memset(cache, 0, sizeof *cache);
}
static SECStatus
InitCache(cacheDesc *cache, int maxCacheEntries, PRUint32 ssl2_timeout,
PRUint32 ssl3_timeout, const char *directory, PRBool shared)
{
ptrdiff_t ptr;
sidCacheLock *pLock;
char * sharedMem;
char * cacheMem;
PRFileMap * cacheMemMap;
char * cfn = NULL; /* cache file name */
int locks_initialized = 0;
int locks_to_initialize = 0;
PRUint32 init_time;
if (cache->sharedMem) {
if (cache->cacheMem) {
/* Already done */
return SECSuccess;
}
/* make sure loser can clean up properly */
cache->shared = shared;
cache->cacheMem = cacheMem = NULL;
cache->cacheMemMap = cacheMemMap = NULL;
cache->sharedCache = (cacheDesc *)0;
cache->numSIDCacheEntries = maxCacheEntries ? maxCacheEntries
: DEF_SID_CACHE_ENTRIES;
cache->numSIDCacheSets =
@ -915,7 +953,7 @@ InitCache(cacheDesc *cache, int maxCacheEntries, PRUint32 ssl2_timeout,
/* compute size of shared memory, and offsets of all pointers */
ptr = 0;
cache->sharedMem = (char *)ptr;
cache->cacheMem = (char *)ptr;
ptr += SID_ROUNDUP(sizeof(cacheDesc), SID_ALIGNMENT);
cache->sidCacheLocks = (sidCacheLock *)ptr;
@ -951,7 +989,7 @@ InitCache(cacheDesc *cache, int maxCacheEntries, PRUint32 ssl2_timeout,
ptr = (ptrdiff_t)(cache->keyCacheData + cache->numKeyCacheEntries);
ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT);
cache->sharedMemSize = ptr;
cache->cacheMemSize = ptr;
cache->keyCacheSize = (char *)ptr - (char *)cache->keyCacheData;
@ -979,67 +1017,60 @@ InitCache(cacheDesc *cache, int maxCacheEntries, PRUint32 ssl2_timeout,
cache->ssl3Timeout = DEF_SSL3_TIMEOUT;
}
/* Create file names */
if (shared) {
/* Create file names */
#if defined(XP_UNIX) || defined(XP_BEOS)
/* there's some confusion here about whether PR_OpenAnonFileMap wants
** a directory name or a file name for its first argument.
cfn = PR_smprintf("%s/.sslsvrcache.%d", directory, myPid);
*/
cfn = PR_smprintf("%s", directory);
#endif
#ifdef XP_WIN32
cfn = PR_smprintf("%s/svrcache_%d_%x.ssl", directory, myPid,
GetCurrentThreadId());
/* there's some confusion here about whether PR_OpenAnonFileMap wants
** a directory name or a file name for its first argument.
cfn = PR_smprintf("%s/.sslsvrcache.%d", directory, myPid);
*/
cfn = PR_smprintf("%s", directory);
#elif defined(XP_WIN32)
cfn = PR_smprintf("%s/svrcache_%d_%x.ssl", directory, myPid,
GetCurrentThreadId());
#elif defined(XP_OS2)
cfn = PR_smprintf("%s/svrcache_%d_%x.ssl", directory, myPid,
gettid());
#else
#error "Don't know how to create file name for this platform!"
#endif
if (!cfn) {
goto loser;
}
#ifdef XP_OS2
cfn = PR_smprintf("%s/svrcache_%d_%x.ssl", directory, myPid,
gettid());
#endif
if (!cfn) {
goto loser;
}
/* Create cache */
cacheMemMap = PR_OpenAnonFileMap(cfn, cache->cacheMemSize,
PR_PROT_READWRITE);
cache->shared = shared;
/* Create cache */
if (PR_TRUE == shared) {
cacheMemMap = PR_OpenAnonFileMap(cfn, cache->sharedMemSize,
PR_PROT_READWRITE);
PR_smprintf_free(cfn);
if(!cacheMemMap) {
goto loser;
}
cacheMem = PR_MemMap(cacheMemMap, 0, cache->cacheMemSize);
} else {
cacheMemMap = NULL;
}
PR_smprintf_free(cfn);
if( (PR_TRUE == shared) && (!cacheMemMap) ) {
goto loser;
}
if (PR_TRUE == shared) {
sharedMem = PR_MemMap(cacheMemMap, 0, cache->sharedMemSize);
} else {
sharedMem = PORT_Alloc(cache->sharedMemSize);
cacheMem = PORT_Alloc(cache->cacheMemSize);
}
if (! sharedMem) {
if (! cacheMem) {
goto loser;
}
/* Initialize shared memory. This may not be necessary on all platforms */
memset(sharedMem, 0, cache->sharedMemSize);
memset(cacheMem, 0, cache->cacheMemSize);
/* Copy cache descriptor header into shared memory */
memcpy(sharedMem, cache, sizeof *cache);
memcpy(cacheMem, cache, sizeof *cache);
/* save private copies of these values */
cache->cacheMemMap = cacheMemMap;
cache->sharedMem = sharedMem;
cache->sharedCache = (cacheDesc *)sharedMem;
cache->cacheMem = cacheMem;
cache->sharedCache = (cacheDesc *)cacheMem;
/* Fix pointers in our private copy of cache descriptor to point to
** spaces in shared memory
*/
ptr = (ptrdiff_t)cache->sharedMem;
ptr = (ptrdiff_t)cache->cacheMem;
*(ptrdiff_t *)(&cache->sidCacheLocks) += ptr;
*(ptrdiff_t *)(&cache->keyCacheLock ) += ptr;
*(ptrdiff_t *)(&cache->certCacheLock) += ptr;
@ -1055,36 +1086,20 @@ InitCache(cacheDesc *cache, int maxCacheEntries, PRUint32 ssl2_timeout,
locks_initialized < locks_to_initialize;
++locks_initialized, ++pLock ) {
SECStatus err = sslMutex_Init(&pLock->mutex, isMultiProcess);
if (err)
SECStatus err = sslMutex_Init(&pLock->mutex, shared);
if (err) {
cache->numSIDCacheLocksInitialized = locks_initialized;
goto loser;
}
pLock->timeStamp = init_time;
pLock->pid = 0;
}
cache->numSIDCacheLocksInitialized = locks_initialized;
return SECSuccess;
loser:
if (cache->cacheMemMap) {
if (cache->sharedMem) {
if (locks_initialized > 0) {
pLock = cache->sidCacheLocks;
for (; locks_initialized > 0; --locks_initialized, ++pLock ) {
sslMutex_Destroy(&pLock->mutex);
}
}
if (shared) {
PR_MemUnmap(cache->sharedMem, cache->sharedMemSize);
cache->sharedMem = NULL;
}
}
if (shared) {
PR_CloseFileMap(cache->cacheMemMap);
} else {
PORT_Free(sharedMem);
}
cache->cacheMemMap = NULL;
}
CloseCache(cache);
return SECFailure;
}
@ -1161,9 +1176,7 @@ SSL_ConfigServerSessionIDCache( int maxCacheEntries,
SECStatus
SSL_ShutdownServerSessionIDCacheInstance(cacheDesc *cache)
{
/* if single process, close down, clean up.
** if multi-process, TBD.
*/
CloseCache(cache);
return SECSuccess;
}
@ -1195,7 +1208,7 @@ SSL_ConfigMPServerSIDCache( int maxCacheEntries,
isMultiProcess = PR_TRUE;
result = SSL_ConfigServerSessionIDCacheInstance(cache, maxCacheEntries,
ssl2_timeout, ssl3_timeout, directory, PR_TRUE);
ssl2_timeout, ssl3_timeout, directory, PR_TRUE);
if (result != SECSuccess)
return result;
@ -1206,7 +1219,7 @@ SSL_ConfigMPServerSIDCache( int maxCacheEntries,
return SECFailure;
}
inherit.sharedMemSize = cache->sharedMemSize;
inherit.cacheMemSize = cache->cacheMemSize;
inherit.fmStrLen = fmStrLen;
inhValue = BTOA_DataToAscii((unsigned char *)&inherit, sizeof inherit);
@ -1240,6 +1253,7 @@ SSL_InheritMPServerSIDCacheInstance(cacheDesc *cache, const char * envString)
{
unsigned char * decoString = NULL;
char * fmString = NULL;
char * myEnvString = NULL;
unsigned int decoLen;
ptrdiff_t ptr;
inheritance inherit;
@ -1256,9 +1270,12 @@ SSL_InheritMPServerSIDCacheInstance(cacheDesc *cache, const char * envString)
** then isMultiProcess will already be set.
** If not, we'll set it below.
*/
if (isMultiProcess)
if (isMultiProcess) {
if (cache && cache->sharedCache) {
cache->sharedCache->everInherited = PR_TRUE;
}
return SECSuccess; /* already done. */
}
ssl_sid_lookup = ServerSessionIDLookup;
ssl_sid_cache = ServerSessionIDCache;
ssl_sid_uncache = ServerSessionIDUncache;
@ -1270,15 +1287,15 @@ SSL_InheritMPServerSIDCacheInstance(cacheDesc *cache, const char * envString)
return SECFailure;
}
}
envString = PORT_Strdup(envString);
if (!envString)
myEnvString = PORT_Strdup(envString);
if (!myEnvString)
return SECFailure;
fmString = strchr(envString, ',');
fmString = strchr(myEnvString, ',');
if (!fmString)
goto loser;
*fmString++ = 0;
decoString = ATOB_AsciiToData(envString, &decoLen);
decoString = ATOB_AsciiToData(myEnvString, &decoLen);
if (!decoString) {
SET_ERROR_CODE
goto loser;
@ -1294,34 +1311,39 @@ SSL_InheritMPServerSIDCacheInstance(cacheDesc *cache, const char * envString)
goto loser;
}
memset(&my, 0, sizeof my);
my.sharedMemSize = inherit.sharedMemSize;
memset(cache, 0, sizeof *cache);
cache->cacheMemSize = inherit.cacheMemSize;
/* Create cache */
my.cacheMemMap = PR_ImportFileMapFromString(fmString);
if(! my.cacheMemMap) {
cache->cacheMemMap = PR_ImportFileMapFromString(fmString);
if(! cache->cacheMemMap) {
goto loser;
}
my.sharedMem = PR_MemMap(my.cacheMemMap, 0, my.sharedMemSize);
if (! my.sharedMem) {
cache->cacheMem = PR_MemMap(cache->cacheMemMap, 0, cache->cacheMemSize);
if (! cache->cacheMem) {
goto loser;
}
my.sharedCache = (cacheDesc *)my.sharedMem;
cache->sharedCache = (cacheDesc *)cache->cacheMem;
if (my.sharedCache->sharedMemSize != my.sharedMemSize) {
if (cache->sharedCache->cacheMemSize != cache->cacheMemSize) {
SET_ERROR_CODE
goto loser;
}
memcpy(cache, my.sharedCache, sizeof *cache);
cache->cacheMemMap = my.cacheMemMap;
cache->sharedMem = my.sharedMem;
cache->sharedCache = my.sharedCache;
/* We're now going to overwrite the local cache instance with the
** shared copy of the cache struct, then update several values in
** the local cache using the values for cache->cacheMemMap and
** cache->cacheMem computed just above. So, we copy cache into
** the automatic variable "my", to preserve the variables while
** cache is overwritten.
*/
my = *cache; /* save values computed above. */
memcpy(cache, cache->sharedCache, sizeof *cache); /* overwrite */
/* Fix pointers in our private copy of cache descriptor to point to
** spaces in shared memory
** spaces in shared memory, whose address is now in "my".
*/
ptr = (ptrdiff_t)cache->sharedMem;
ptr = (ptrdiff_t)my.cacheMem;
*(ptrdiff_t *)(&cache->sidCacheLocks) += ptr;
*(ptrdiff_t *)(&cache->keyCacheLock ) += ptr;
*(ptrdiff_t *)(&cache->certCacheLock) += ptr;
@ -1330,49 +1352,66 @@ SSL_InheritMPServerSIDCacheInstance(cacheDesc *cache, const char * envString)
*(ptrdiff_t *)(&cache->certCacheData) += ptr;
*(ptrdiff_t *)(&cache->keyCacheData ) += ptr;
cache->cacheMemMap = my.cacheMemMap;
cache->cacheMem = my.cacheMem;
cache->sharedCache = (cacheDesc *)cache->cacheMem;
#ifdef WINNT
/* On Windows NT we need to "fix" the sidCacheLocks here to support fibers
When NT fibers are used in a multi-process server, a second level of
locking is needed to prevent a deadlock, in case a fiber acquires the
cross-process mutex, yields, and another fiber is later scheduled on
the same native thread and tries to acquire the cross-process mutex.
We do this by using a PRLock in the sslMutex. However, it is stored in
shared memory as part of sidCacheLocks, and we don't want to overwrite
the PRLock of the parent process. So we need to make new, private
copies of sidCacheLocks before modifying the sslMutex with our own
PRLock
** When NT fibers are used in a multi-process server, a second level of
** locking is needed to prevent a deadlock, in case a fiber acquires the
** cross-process mutex, yields, and another fiber is later scheduled on
** the same native thread and tries to acquire the cross-process mutex.
** We do this by using a PRLock in the sslMutex. However, it is stored in
** shared memory as part of sidCacheLocks, and we don't want to overwrite
** the PRLock of the parent process. So we need to make new, private
** copies of sidCacheLocks before modifying the sslMutex with our own
** PRLock
*/
newLocks = (sidCacheLock*)PORT_Alloc(sizeof(sidCacheLock)*(cache->numSIDCacheLocks + 2));
/* note from jpierre : this should be free'd in child processes when
a function is added to delete the SSL session cache in the future */
/* fix the locks */
for (locks_to_initialize = cache->numSIDCacheLocks + 2;
locks_initialized < locks_to_initialize;
++locks_initialized) {
/* copy the old lock */
memcpy(&newLocks[locks_initialized], &cache->sidCacheLocks[locks_initialized], sizeof(sidCacheLock));
/* now, make a local PRLock in this sslMutex for this child process */
sslMutex_2LevelInit(&newLocks[locks_initialized].mutex);
}
/* then, make our cache object point to our new private sidCacheLocks */
/* first the session cache */
** a function is added to delete the SSL session cache in the future.
*/
locks_to_initialize = cache->numSIDCacheLocks + 2;
newLocks = PORT_NewArray(sidCacheLock, locks_to_initialize);
cache->sidCacheLocks = newLocks;
if (!newLocks)
goto loser;
/* copy the old locks */
memcpy(newLocks, cache->sidCacheLocks,
locks_to_initialize * sizeof(sidCacheLock));
/* fix the locks */
for (; locks_initialized < locks_to_initialize; ++locks_initialized) {
/* now, make a local PRLock in this sslMutex for this child process */
SECStatus err;
err = sslMutex_2LevelInit(&newLocks[locks_initialized].mutex);
if (err != SECSuccess) {
cache->numSIDCacheLocksInitialized = locks_initialized;
goto loser;
}
}
cache->numSIDCacheLocksInitialized = locks_initialized;
/* also fix the key and cert cache which use the last 2 lock entries */
cache->keyCacheLock = cache->sidCacheLocks + cache->numSIDCacheLocks;
cache->certCacheLock = cache->keyCacheLock + 1;
#endif
PORT_Free(myEnvString);
PORT_Free(decoString);
/* mark that we have inherited this. */
cache->sharedCache->everInherited = PR_TRUE;
isMultiProcess = PR_TRUE;
return SECSuccess;
loser:
PORT_Free(myEnvString);
if (decoString)
PORT_Free(decoString);
CloseCache(cache);
return SECFailure;
}
SECStatus