diff options
Diffstat (limited to 'security/nss/lib/base')
-rw-r--r-- | security/nss/lib/base/Makefile | 40 | ||||
-rw-r--r-- | security/nss/lib/base/arena.c | 1142 | ||||
-rw-r--r-- | security/nss/lib/base/base.h | 1445 | ||||
-rw-r--r-- | security/nss/lib/base/baset.h | 158 | ||||
-rw-r--r-- | security/nss/lib/base/config.mk | 48 | ||||
-rw-r--r-- | security/nss/lib/base/error.c | 297 | ||||
-rw-r--r-- | security/nss/lib/base/errorval.c | 89 | ||||
-rw-r--r-- | security/nss/lib/base/hash.c | 404 | ||||
-rw-r--r-- | security/nss/lib/base/hashops.c | 117 | ||||
-rw-r--r-- | security/nss/lib/base/item.c | 241 | ||||
-rw-r--r-- | security/nss/lib/base/libc.c | 197 | ||||
-rw-r--r-- | security/nss/lib/base/list.c | 433 | ||||
-rw-r--r-- | security/nss/lib/base/manifest.mn | 65 | ||||
-rw-r--r-- | security/nss/lib/base/nssbase.h | 167 | ||||
-rw-r--r-- | security/nss/lib/base/nssbaset.h | 153 | ||||
-rw-r--r-- | security/nss/lib/base/tracker.c | 543 | ||||
-rw-r--r-- | security/nss/lib/base/utf8.c | 759 | ||||
-rw-r--r-- | security/nss/lib/base/whatnspr.c | 171 |
18 files changed, 6469 insertions, 0 deletions
diff --git a/security/nss/lib/base/Makefile b/security/nss/lib/base/Makefile new file mode 100644 index 000000000..4cbbfed70 --- /dev/null +++ b/security/nss/lib/base/Makefile @@ -0,0 +1,40 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code is the Netscape security libraries. +# +# The Initial Developer of the Original Code is Netscape +# Communications Corporation. Portions created by Netscape are +# Copyright (C) 1994-2000 Netscape Communications Corporation. All +# Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the +# terms of the GNU General Public License Version 2 or later (the +# "GPL"), in which case the provisions of the GPL are applicable +# instead of those above. If you wish to allow use of your +# version of this file only under the terms of the GPL and not to +# allow others to use your version of this file under the MPL, +# indicate your decision by deleting the provisions above and +# replace them with the notice and other provisions required by +# the GPL. If you do not delete the provisions above, a recipient +# may use your version of this file under either the MPL or the +# GPL. +# +MAKEFILE_CVS_ID = "@(#) $RCSfile$ $Revision$ $Date$ $Name$" + +include manifest.mn +include $(CORE_DEPTH)/coreconf/config.mk +include config.mk +include $(CORE_DEPTH)/coreconf/rules.mk + +export:: private_export diff --git a/security/nss/lib/base/arena.c b/security/nss/lib/base/arena.c new file mode 100644 index 000000000..648b7e864 --- /dev/null +++ b/security/nss/lib/base/arena.c @@ -0,0 +1,1142 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#ifdef DEBUG +static const char CVS_ID[] = "@(#) $RCSfile$ $Revision$ $Date$ $Name$"; +#endif /* DEBUG */ + +/* + * arena.c + * + * This contains the implementation of NSS's thread-safe arenas. + */ + +#ifndef BASE_H +#include "base.h" +#endif /* BASE_H */ + +#ifdef ARENA_THREADMARK +#include "prthread.h" +#endif /* ARENA_THREADMARK */ + +#include "prlock.h" +#include "plarena.h" + +#include <string.h> + +/* + * NSSArena + * + * This is based on NSPR's arena code, but it is threadsafe. + * + * The public methods relating to this type are: + * + * NSSArena_Create -- constructor + * NSSArena_Destroy + * + * The nonpublic methods relating to this type are: + * + * nssArena_Create -- constructor + * nssArena_Destroy + * nssArena_Mark + * nssArena_Release + * nssArena_Unmark + * + * nss_ZAlloc + * nss_ZFreeIf + * nss_ZRealloc + * + * In debug builds, the following calls are available: + * + * nssArena_verifyPointer + * nssArena_registerDestructor + * nssArena_deregisterDestructor + */ + +struct NSSArenaStr { + PLArenaPool pool; + PRLock *lock; +#ifdef ARENA_THREADMARK + PRThread *marking_thread; + nssArenaMark *first_mark; + nssArenaMark *last_mark; +#endif /* ARENA_THREADMARK */ +#ifdef ARENA_DESTRUCTOR_LIST + struct arena_destructor_node *first_destructor; + struct arena_destructor_node *last_destructor; +#endif /* ARENA_DESTRUCTOR_LIST */ +}; + +/* + * nssArenaMark + * + * This type is used to mark the current state of an NSSArena. + */ + +struct nssArenaMarkStr { + PRUint32 magic; + void *mark; +#ifdef ARENA_THREADMARK + nssArenaMark *next; +#endif /* ARENA_THREADMARK */ +#ifdef ARENA_DESTRUCTOR_LIST + struct arena_destructor_node *next_destructor; + struct arena_destructor_node *prev_destructor; +#endif /* ARENA_DESTRUCTOR_LIST */ +}; + +#define MARK_MAGIC 0x4d41524b /* "MARK" how original */ + +/* + * But first, the pointer-tracking code + */ +#ifdef DEBUG +extern const NSSError NSS_ERROR_INTERNAL_ERROR; + +static nssPointerTracker arena_pointer_tracker; + +static PRStatus +arena_add_pointer +( + const NSSArena *arena +) +{ + PRStatus rv; + + rv = nssPointerTracker_initialize(&arena_pointer_tracker); + if( PR_SUCCESS != rv ) { + return rv; + } + + rv = nssPointerTracker_add(&arena_pointer_tracker, arena); + if( PR_SUCCESS != rv ) { + NSSError e = NSS_GetError(); + if( NSS_ERROR_NO_MEMORY != e ) { + nss_SetError(NSS_ERROR_INTERNAL_ERROR); + } + + return rv; + } + + return PR_SUCCESS; +} + +static PRStatus +arena_remove_pointer +( + const NSSArena *arena +) +{ + PRStatus rv; + + rv = nssPointerTracker_remove(&arena_pointer_tracker, arena); + if( PR_SUCCESS != rv ) { + nss_SetError(NSS_ERROR_INTERNAL_ERROR); + } + + return rv; +} + +/* + * nssArena_verifyPointer + * + * This method is only present in debug builds. + * + * If the specified pointer is a valid pointer to an NSSArena object, + * this routine will return PR_SUCCESS. Otherwise, it will put an + * error on the error stack and return PR_FAILURE. + * + * The error may be one of the following values: + * NSS_ERROR_INVALID_ARENA + * + * Return value: + * PR_SUCCESS if the pointer is valid + * PR_FAILURE if it isn't + */ + +NSS_IMPLEMENT PRStatus +nssArena_verifyPointer +( + const NSSArena *arena +) +{ + PRStatus rv; + + rv = nssPointerTracker_initialize(&arena_pointer_tracker); + if( PR_SUCCESS != rv ) { + /* + * This is a little disingenious. We have to initialize the + * tracker, because someone could "legitimately" try to verify + * an arena pointer before one is ever created. And this step + * might fail, due to lack of memory. But the only way that + * this step can fail is if it's doing the call_once stuff, + * (later calls just no-op). And if it didn't no-op, there + * aren't any valid arenas.. so the argument certainly isn't one. + */ + nss_SetError(NSS_ERROR_INVALID_ARENA); + return PR_FAILURE; + } + + rv = nssPointerTracker_verify(&arena_pointer_tracker, arena); + if( PR_SUCCESS != rv ) { + nss_SetError(NSS_ERROR_INVALID_ARENA); + return PR_FAILURE; + } + + return PR_SUCCESS; +} +#endif /* DEBUG */ + +#ifdef ARENA_DESTRUCTOR_LIST + +struct arena_destructor_node { + struct arena_destructor_node *next; + struct arena_destructor_node *prev; + void (*destructor)(void *argument); + void *arg; +}; + +/* + * nssArena_registerDestructor + * + * This routine stores a pointer to a callback and an arbitrary + * pointer-sized argument in the arena, at the current point in + * the mark stack. If the arena is destroyed, or an "earlier" + * mark is released, then this destructor will be called at that + * time. Note that the destructor will be called with the arena + * locked, which means the destructor may free memory in that + * arena, but it may not allocate or cause to be allocated any + * memory. This callback facility was included to support our + * debug-version pointer-tracker feature; overuse runs counter to + * the the original intent of arenas. This routine returns a + * PRStatus value; if successful, it will return PR_SUCCESS. If + * unsuccessful, it will set an error on the error stack and + * return PR_FAILURE. + * + * The error may be one of the following values: + * NSS_ERROR_INVALID_ARENA + * NSS_ERROR_NO_MEMORY + * + * Return value: + * PR_SUCCESS + * PR_FAILURE + */ + +NSS_IMPLEMENT PRStatus +nssArena_registerDestructor +( + NSSArena *arena, + void (*destructor)(void *argument), + void *arg +) +{ + struct arena_destructor_node *it; + +#ifdef NSSDEBUG + if( PR_SUCCESS != nssArena_verifyPointer(arena) ) { + return PR_FAILURE; + } +#endif /* NSSDEBUG */ + + it = nss_ZNEW(arena, struct arena_destructor_node); + if( (struct arena_destructor_node *)NULL == it ) { + return PR_FAILURE; + } + + it->prev = arena->last_destructor; + arena->last_destructor->next = it; + arena->last_destructor = it; + it->destructor = destructor; + it->arg = arg; + + if( (nssArenaMark *)NULL != arena->last_mark ) { + arena->last_mark->prev_destructor = it->prev; + arena->last_mark->next_destructor = it->next; + } + + return PR_SUCCESS; +} + +NSS_IMPLEMENT PRStatus +nssArena_deregisterDestructor +( + NSSArena *arena, + void (*destructor)(void *argument), + void *arg +) +{ + struct arena_destructor_node *it; + +#ifdef NSSDEBUG + if( PR_SUCCESS != nssArena_verifyPointer(arena) ) { + return PR_FAILURE; + } +#endif /* NSSDEBUG */ + + for( it = arena->first_destructor; it; it = it->next ) { + if( (it->destructor == destructor) && (it->arg == arg) ) { + break; + } + } + + if( (struct arena_destructor_node *)NULL == it ) { + nss_SetError(NSS_ERROR_NOT_FOUND); + return PR_FAILURE; + } + + if( it == arena->first_destructor ) { + arena->first_destructor = it->next; + } + + if( it == arena->last_destructor ) { + arena->last_destructor = it->prev; + } + + if( (struct arena_destructor_node *)NULL != it->prev ) { + it->prev->next = it->next; + } + + if( (struct arena_destructor_node *)NULL != it->next ) { + it->next->prev = it->prev; + } + + { + nssArenaMark *m; + for( m = arena->first_mark; m; m = m->next ) { + if( m->next_destructor == it ) { + m->next_destructor = it->next; + } + if( m->prev_destructor == it ) { + m->prev_destructor = it->prev; + } + } + } + + nss_ZFreeIf(it); + return PR_SUCCESS; +} + +static void +nss_arena_call_destructor_chain +( + struct arena_destructor_node *it +) +{ + for( ; it ; it = it->next ) { + (*(it->destructor))(it->arg); + } +} + +#endif /* ARENA_DESTRUCTOR_LIST */ + +/* + * NSSArena_Create + * + * This routine creates a new memory arena. This routine may return + * NULL upon error, in which case it will have created an error stack. + * + * The top-level error may be one of the following values: + * NSS_ERROR_NO_MEMORY + * + * Return value: + * NULL upon error + * A pointer to an NSSArena upon success + */ + +NSS_IMPLEMENT NSSArena * +NSSArena_Create +( + void +) +{ + nss_ClearErrorStack(); + return nssArena_Create(); +} + +/* + * nssArena_Create + * + * This routine creates a new memory arena. This routine may return + * NULL upon error, in which case it will have set an error on the + * error stack. + * + * The error may be one of the following values: + * NSS_ERROR_NO_MEMORY + * + * Return value: + * NULL upon error + * A pointer to an NSSArena upon success + */ + +NSS_IMPLEMENT NSSArena * +nssArena_Create +( + void +) +{ + NSSArena *rv = (NSSArena *)NULL; + + rv = nss_ZNEW((NSSArena *)NULL, NSSArena); + if( (NSSArena *)NULL == rv ) { + nss_SetError(NSS_ERROR_NO_MEMORY); + return (NSSArena *)NULL; + } + + rv->lock = PR_NewLock(); + if( (PRLock *)NULL == rv->lock ) { + (void)nss_ZFreeIf(rv); + nss_SetError(NSS_ERROR_NO_MEMORY); + return (NSSArena *)NULL; + } + + /* + * Arena sizes. The current security code has 229 occurrences of + * PORT_NewArena. The default chunksizes specified break down as + * + * Size Mult. Specified as + * 512 1 512 + * 1024 7 1024 + * 2048 5 2048 + * 2048 5 CRMF_DEFAULT_ARENA_SIZE + * 2048 190 DER_DEFAULT_CHUNKSIZE + * 2048 20 SEC_ASN1_DEFAULT_ARENA_SIZE + * 4096 1 4096 + * + * Obviously this "default chunksize" flexibility isn't very + * useful to us, so I'll just pick 2048. + */ + + PL_InitArenaPool(&rv->pool, "NSS", 2048, sizeof(double)); + +#ifdef DEBUG + { + PRStatus st; + st = arena_add_pointer(rv); + if( PR_SUCCESS != st ) { + PL_FinishArenaPool(&rv->pool); + PR_DestroyLock(rv->lock); + (void)nss_ZFreeIf(rv); + return (NSSArena *)NULL; + } + } +#endif /* DEBUG */ + + return rv; +} + +/* + * NSSArena_Destroy + * + * This routine will destroy the specified arena, freeing all memory + * allocated from it. This routine returns a PRStatus value; if + * successful, it will return PR_SUCCESS. If unsuccessful, it will + * create an error stack and return PR_FAILURE. + * + * The top-level error may be one of the following values: + * NSS_ERROR_INVALID_ARENA + * + * Return value: + * PR_SUCCESS upon success + * PR_FAILURE upon failure + */ + +NSS_IMPLEMENT PRStatus +NSSArena_Destroy +( + NSSArena *arena +) +{ + nss_ClearErrorStack(); + +#ifdef DEBUG + if( PR_SUCCESS != nssArena_verifyPointer(arena) ) { + return PR_FAILURE; + } +#endif /* DEBUG */ + + return nssArena_Destroy(arena); +} + +/* + * nssArena_Destroy + * + * This routine will destroy the specified arena, freeing all memory + * allocated from it. This routine returns a PRStatus value; if + * successful, it will return PR_SUCCESS. If unsuccessful, it will + * set an error on the error stack and return PR_FAILURE. + * + * The error may be one of the following values: + * NSS_ERROR_INVALID_ARENA + * + * Return value: + * PR_SUCCESS + * PR_FAILURE + */ + +NSS_IMPLEMENT PRStatus +nssArena_Destroy +( + NSSArena *arena +) +{ + PRLock *lock; + +#ifdef NSSDEBUG + if( PR_SUCCESS != nssArena_verifyPointer(arena) ) { + return PR_FAILURE; + } +#endif /* NSSDEBUG */ + + PR_Lock(arena->lock); + if( (PRLock *)NULL == arena->lock ) { + /* Just got destroyed */ + nss_SetError(NSS_ERROR_INVALID_ARENA); + return PR_FAILURE; + } + +#ifdef DEBUG + if( PR_SUCCESS != arena_remove_pointer(arena) ) { + return PR_FAILURE; + } +#endif /* DEBUG */ + +#ifdef ARENA_DESTRUCTOR_LIST + /* Note that the arena is locked at this time */ + nss_arena_call_destructor_chain(arena->first_destructor); +#endif /* ARENA_DESTRUCTOR_LIST */ + + PL_FinishArenaPool(&arena->pool); + lock = arena->lock; + arena->lock = (PRLock *)NULL; + PR_Unlock(lock); + PR_DestroyLock(lock); + (void)nss_ZFreeIf(arena); + return PR_SUCCESS; +} + +static void *nss_zalloc_arena_locked(NSSArena *arena, PRUint32 size); + +/* + * nssArena_Mark + * + * This routine "marks" the current state of an arena. Space + * allocated after the arena has been marked can be freed by + * releasing the arena back to the mark with nssArena_Release, + * or committed by calling nssArena_Unmark. When successful, + * this routine returns a valid nssArenaMark pointer. This + * routine may return NULL upon error, in which case it will + * have set an error on the error stack. + * + * The error may be one of the following values: + * NSS_ERROR_INVALID_ARENA + * NSS_ERROR_NO_MEMORY + * NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD + * + * Return value: + * NULL upon failure + * An nssArenaMark pointer upon success + */ + +NSS_IMPLEMENT nssArenaMark * +nssArena_Mark +( + NSSArena *arena +) +{ + nssArenaMark *rv; + void *p; + +#ifdef NSSDEBUG + if( PR_SUCCESS != nssArena_verifyPointer(arena) ) { + return (nssArenaMark *)NULL; + } +#endif /* NSSDEBUG */ + + PR_Lock(arena->lock); + if( (PRLock *)NULL == arena->lock ) { + /* Just got destroyed */ + nss_SetError(NSS_ERROR_INVALID_ARENA); + return (nssArenaMark *)NULL; + } + +#ifdef ARENA_THREADMARK + if( (PRThread *)NULL == arena->marking_thread ) { + /* Unmarked. Store our thread ID */ + arena->marking_thread = PR_GetCurrentThread(); + /* This call never fails. */ + } else { + /* Marked. Verify it's the current thread */ + if( PR_GetCurrentThread() != arena->marking_thread ) { + PR_Unlock(arena->lock); + nss_SetError(NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD); + return (nssArenaMark *)NULL; + } + } +#endif /* ARENA_THREADMARK */ + + p = PL_ARENA_MARK(&arena->pool); + /* No error possible */ + + /* Do this after the mark */ + rv = (nssArenaMark *)nss_zalloc_arena_locked(arena, sizeof(nssArenaMark)); + if( (nssArenaMark *)NULL == rv ) { + PR_Unlock(arena->lock); + nss_SetError(NSS_ERROR_NO_MEMORY); + return (nssArenaMark *)NULL; + } + +#ifdef ARENA_THREADMARK + if ( (nssArenaMark *)NULL == arena->first_mark) { + arena->first_mark = rv; + arena->last_mark = rv; + } else { + arena->last_mark->next = rv; + arena->last_mark = rv; + } +#endif /* ARENA_THREADMARK */ + + rv->mark = p; + rv->magic = MARK_MAGIC; + +#ifdef ARENA_DESTRUCTOR_LIST + rv->prev_destructor = arena->last_destructor; +#endif /* ARENA_DESTRUCTOR_LIST */ + + PR_Unlock(arena->lock); + + return rv; +} + +/* + * nss_arena_unmark_release + * + * This static routine implements the routines nssArena_Release + * ans nssArena_Unmark, which are almost identical. + */ + +static PRStatus +nss_arena_unmark_release +( + NSSArena *arena, + nssArenaMark *arenaMark, + PRBool release +) +{ + void *inner_mark; + +#ifdef NSSDEBUG + if( PR_SUCCESS != nssArena_verifyPointer(arena) ) { + return PR_FAILURE; + } +#endif /* NSSDEBUG */ + + if( MARK_MAGIC != arenaMark->magic ) { + nss_SetError(NSS_ERROR_INVALID_ARENA_MARK); + return PR_FAILURE; + } + + PR_Lock(arena->lock); + if( (PRLock *)NULL == arena->lock ) { + /* Just got destroyed */ + nss_SetError(NSS_ERROR_INVALID_ARENA); + return PR_FAILURE; + } + +#ifdef ARENA_THREADMARK + if( (PRThread *)NULL != arena->marking_thread ) { + if( PR_GetCurrentThread() != arena->marking_thread ) { + PR_Unlock(arena->lock); + nss_SetError(NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD); + return PR_FAILURE; + } + } +#endif /* ARENA_THREADMARK */ + + if( MARK_MAGIC != arenaMark->magic ) { + /* Just got released */ + PR_Unlock(arena->lock); + nss_SetError(NSS_ERROR_INVALID_ARENA_MARK); + return PR_FAILURE; + } + + arenaMark->magic = 0; + inner_mark = arenaMark->mark; + +#ifdef ARENA_THREADMARK + { + nssArenaMark **pMark = &arena->first_mark; + nssArenaMark *rest; + nssArenaMark *last = (nssArenaMark *)NULL; + + /* Find this mark */ + while( *pMark != arenaMark ) { + last = *pMark; + pMark = &(*pMark)->next; + } + + /* Remember the pointer, then zero it */ + rest = (*pMark)->next; + *pMark = (nssArenaMark *)NULL; + + arena->last_mark = last; + + /* Invalidate any later marks being implicitly released */ + for( ; (nssArenaMark *)NULL != rest; rest = rest->next ) { + rest->magic = 0; + } + + /* If we just got rid of the first mark, clear the thread ID */ + if( (nssArenaMark *)NULL == arena->first_mark ) { + arena->marking_thread = (PRThread *)NULL; + } + } +#endif /* ARENA_THREADMARK */ + + if( release ) { +#ifdef ARENA_DESTRUCTOR_LIST + if( (struct arena_destructor_node *)NULL != arenaMark->prev_destructor ) { + arenaMark->prev_destructor->next = (struct arena_destructor_node *)NULL; + } + arena->last_destructor = arenaMark->prev_destructor; + + /* Note that the arena is locked at this time */ + nss_arena_call_destructor_chain(arenaMark->next_destructor); +#endif /* ARENA_DESTRUCTOR_LIST */ + + PR_ARENA_RELEASE(&arena->pool, inner_mark); + /* No error return */ + } + + PR_Unlock(arena->lock); + return PR_SUCCESS; +} + +/* + * nssArena_Release + * + * This routine invalidates and releases all memory allocated from + * the specified arena after the point at which the specified mark + * was obtained. This routine returns a PRStatus value; if successful, + * it will return PR_SUCCESS. If unsuccessful, it will set an error + * on the error stack and return PR_FAILURE. + * + * The error may be one of the following values: + * NSS_ERROR_INVALID_ARENA + * NSS_ERROR_INVALID_ARENA_MARK + * NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD + * + * Return value: + * PR_SUCCESS + * PR_FAILURE + */ + +NSS_IMPLEMENT PRStatus +nssArena_Release +( + NSSArena *arena, + nssArenaMark *arenaMark +) +{ + return nss_arena_unmark_release(arena, arenaMark, PR_TRUE); +} + +/* + * nssArena_Unmark + * + * This routine "commits" the indicated mark and any marks after + * it, making them unreleasable. Note that any earlier marks can + * still be released, and such a release will invalidate these + * later unmarked regions. If an arena is to be safely shared by + * more than one thread, all marks must be either released or + * unmarked. This routine returns a PRStatus value; if successful, + * it will return PR_SUCCESS. If unsuccessful, it will set an error + * on the error stack and return PR_FAILURE. + * + * The error may be one of the following values: + * NSS_ERROR_INVALID_ARENA + * NSS_ERROR_INVALID_ARENA_MARK + * NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD + * + * Return value: + * PR_SUCCESS + * PR_FAILURE + */ + +NSS_IMPLEMENT PRStatus +nssArena_Unmark +( + NSSArena *arena, + nssArenaMark *arenaMark +) +{ + return nss_arena_unmark_release(arena, arenaMark, PR_FALSE); +} + +/* + * We prefix this header to all allocated blocks. It is a multiple + * of the alignment size. Note that this usage of a header may make + * purify spew bogus warnings about "potentially leaked blocks" of + * memory; if that gets too annoying we can add in a pointer to the + * header in the header itself. There's not a lot of safety here; + * maybe we should add a magic value? + */ +struct pointer_header { + NSSArena *arena; + PRUint32 size; +}; + +static void * +nss_zalloc_arena_locked +( + NSSArena *arena, + PRUint32 size +) +{ + void *p; + void *rv; + struct pointer_header *h; + PRUint32 my_size = size + sizeof(struct pointer_header); + PR_ARENA_ALLOCATE(p, &arena->pool, my_size); + if( (void *)NULL == p ) { + nss_SetError(NSS_ERROR_NO_MEMORY); + return (void *)NULL; + } + /* + * Do this before we unlock. This way if the user is using + * an arena in one thread while destroying it in another, he'll + * fault/FMR in his code, not ours. + */ + h = (struct pointer_header *)p; + h->arena = arena; + h->size = size; + rv = (void *)((char *)h + sizeof(struct pointer_header)); + (void)nsslibc_memset(rv, 0, size); + return rv; +} + +/* + * nss_ZAlloc + * + * This routine allocates and zeroes a section of memory of the + * size, and returns to the caller a pointer to that memory. If + * the optional arena argument is non-null, the memory will be + * obtained from that arena; otherwise, the memory will be obtained + * from the heap. This routine may return NULL upon error, in + * which case it will have set an error upon the error stack. The + * value specified for size may be zero; in which case a valid + * zero-length block of memory will be allocated. This block may + * be expanded by calling nss_ZRealloc. + * + * The error may be one of the following values: + * NSS_ERROR_INVALID_ARENA + * NSS_ERROR_NO_MEMORY + * NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD + * + * Return value: + * NULL upon error + * A pointer to the new segment of zeroed memory + */ + +NSS_IMPLEMENT void * +nss_ZAlloc +( + NSSArena *arenaOpt, + PRUint32 size +) +{ + struct pointer_header *h; + PRUint32 my_size = size + sizeof(struct pointer_header); + + if( my_size < sizeof(struct pointer_header) ) { + /* Wrapped */ + nss_SetError(NSS_ERROR_NO_MEMORY); + return (void *)NULL; + } + + if( (NSSArena *)NULL == arenaOpt ) { + /* Heap allocation, no locking required. */ + h = (struct pointer_header *)PR_Calloc(1, my_size); + if( (struct pointer_header *)NULL == h ) { + nss_SetError(NSS_ERROR_NO_MEMORY); + return (void *)NULL; + } + + h->arena = (NSSArena *)NULL; + h->size = size; + /* We used calloc: it's already zeroed */ + + return (void *)((char *)h + sizeof(struct pointer_header)); + } else { + void *rv; + /* Arena allocation */ +#ifdef NSSDEBUG + if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) { + return (void *)NULL; + } +#endif /* NSSDEBUG */ + + PR_Lock(arenaOpt->lock); + if( (PRLock *)NULL == arenaOpt->lock ) { + /* Just got destroyed */ + nss_SetError(NSS_ERROR_INVALID_ARENA); + return (void *)NULL; + } + +#ifdef ARENA_THREADMARK + if( (PRThread *)NULL != arenaOpt->marking_thread ) { + if( PR_GetCurrentThread() != arenaOpt->marking_thread ) { + nss_SetError(NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD); + PR_Unlock(arenaOpt->lock); + return (void *)NULL; + } + } +#endif /* ARENA_THREADMARK */ + + rv = nss_zalloc_arena_locked(arenaOpt, size); + + PR_Unlock(arenaOpt->lock); + return rv; + } + /*NOTREACHED*/ +} + +/* + * nss_ZFreeIf + * + * If the specified pointer is non-null, then the region of memory + * to which it points -- which must have been allocated with + * nss_ZAlloc -- will be zeroed and released. This routine + * returns a PRStatus value; if successful, it will return PR_SUCCESS. + * If unsuccessful, it will set an error on the error stack and return + * PR_FAILURE. + * + * The error may be one of the following values: + * NSS_ERROR_INVALID_POINTER + * + * Return value: + * PR_SUCCESS + * PR_FAILURE + */ + +NSS_IMPLEMENT PRStatus +nss_ZFreeIf +( + void *pointer +) +{ + struct pointer_header *h; + + if( (void *)NULL == pointer ) { + return PR_SUCCESS; + } + + h = (struct pointer_header *)&((char *)pointer) + [ - sizeof(struct pointer_header) ]; + + /* Check any magic here */ + + if( (NSSArena *)NULL == h->arena ) { + /* Heap */ + (void)nsslibc_memset(pointer, 0, h->size); + PR_Free(h); + return PR_SUCCESS; + } else { + /* Arena */ +#ifdef NSSDEBUG + if( PR_SUCCESS != nssArena_verifyPointer(h->arena) ) { + return PR_FAILURE; + } +#endif /* NSSDEBUG */ + + PR_Lock(h->arena->lock); + if( (PRLock *)NULL == h->arena->lock ) { + /* Just got destroyed.. so this pointer is invalid */ + nss_SetError(NSS_ERROR_INVALID_POINTER); + return PR_FAILURE; + } + + (void)nsslibc_memset(pointer, 0, h->size); + + /* No way to "free" it within an NSPR arena. */ + + PR_Unlock(h->arena->lock); + return PR_SUCCESS; + } + /*NOTREACHED*/ +} + +/* + * nss_ZRealloc + * + * This routine reallocates a block of memory obtained by calling + * nss_ZAlloc or nss_ZRealloc. The portion of memory + * between the new and old sizes -- which is either being newly + * obtained or released -- is in either case zeroed. This routine + * may return NULL upon failure, in which case it will have placed + * an error on the error stack. + * + * The error may be one of the following values: + * NSS_ERROR_INVALID_POINTER + * NSS_ERROR_NO_MEMORY + * NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD + * + * Return value: + * NULL upon error + * A pointer to the replacement segment of memory + */ + +NSS_EXTERN void * +nss_ZRealloc +( + void *pointer, + PRUint32 newSize +) +{ + struct pointer_header *h, *new_h; + PRUint32 my_newSize = newSize + sizeof(struct pointer_header); + void *rv; + + if( my_newSize < sizeof(struct pointer_header) ) { + /* Wrapped */ + nss_SetError(NSS_ERROR_NO_MEMORY); + return (void *)NULL; + } + + if( (void *)NULL == pointer ) { + nss_SetError(NSS_ERROR_INVALID_POINTER); + return (void *)NULL; + } + + h = (struct pointer_header *)&((char *)pointer) + [ - sizeof(struct pointer_header) ]; + + /* Check any magic here */ + + if( newSize == h->size ) { + /* saves thrashing */ + return pointer; + } + + if( (NSSArena *)NULL == h->arena ) { + /* Heap */ + new_h = (struct pointer_header *)PR_Calloc(1, my_newSize); + if( (struct pointer_header *)NULL == new_h ) { + nss_SetError(NSS_ERROR_NO_MEMORY); + return (void *)NULL; + } + + new_h->arena = (NSSArena *)NULL; + new_h->size = newSize; + rv = (void *)((char *)new_h + sizeof(struct pointer_header)); + + if( newSize > h->size ) { + (void)nsslibc_memcpy(rv, pointer, h->size); + (void)nsslibc_memset(&((char *)rv)[ h->size ], + 0, (newSize - h->size)); + } else { + (void)nsslibc_memcpy(rv, pointer, newSize); + } + + (void)nsslibc_memset(pointer, 0, h->size); + h->size = 0; + PR_Free(h); + + return rv; + } else { + void *p; + /* Arena */ +#ifdef NSSDEBUG + if( PR_SUCCESS != nssArena_verifyPointer(h->arena) ) { + return (void *)NULL; + } +#endif /* NSSDEBUG */ + + PR_Lock(h->arena->lock); + if( (PRLock *)NULL == h->arena->lock ) { + /* Just got destroyed.. so this pointer is invalid */ + nss_SetError(NSS_ERROR_INVALID_POINTER); + return (void *)NULL; + } + +#ifdef ARENA_THREADMARK + if( (PRThread *)NULL != h->arena->marking_thread ) { + if( PR_GetCurrentThread() != h->arena->marking_thread ) { + PR_Unlock(h->arena->lock); + nss_SetError(NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD); + return (void *)NULL; + } + } +#endif /* ARENA_THREADMARK */ + + if( newSize < h->size ) { + /* + * We have no general way of returning memory to the arena + * (mark/release doesn't work because things may have been + * allocated after this object), so the memory is gone + * anyway. We might as well just return the same pointer to + * the user, saying "yeah, uh-hunh, you can only use less of + * it now." We'll zero the leftover part, of course. And + * in fact we might as well *not* adjust h->size-- this way, + * if the user reallocs back up to something not greater than + * the original size, then voila, there's the memory! This + * way a thrash big/small/big/small doesn't burn up the arena. + */ + char *extra = &((char *)pointer)[ newSize ]; + (void)nsslibc_memset(extra, 0, (h->size - newSize)); + PR_Unlock(h->arena->lock); + return pointer; + } + + PR_ARENA_ALLOCATE(p, &h->arena->pool, my_newSize); + if( (void *)NULL == p ) { + PR_Unlock(h->arena->lock); + nss_SetError(NSS_ERROR_NO_MEMORY); + return (void *)NULL; + } + + new_h = (struct pointer_header *)p; + new_h->arena = h->arena; + new_h->size = newSize; + rv = (void *)((char *)new_h + sizeof(struct pointer_header)); + if (rv != pointer) { + (void)nsslibc_memcpy(rv, pointer, h->size); + (void)nsslibc_memset(pointer, 0, h->size); + } + (void)nsslibc_memset(&((char *)rv)[ h->size ], 0, (newSize - h->size)); + h->arena = (NSSArena *)NULL; + h->size = 0; + PR_Unlock(new_h->arena->lock); + return rv; + } + /*NOTREACHED*/ +} diff --git a/security/nss/lib/base/base.h b/security/nss/lib/base/base.h new file mode 100644 index 000000000..9a8d2d294 --- /dev/null +++ b/security/nss/lib/base/base.h @@ -0,0 +1,1445 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#ifndef BASE_H +#define BASE_H + +#ifdef DEBUG +static const char BASE_CVS_ID[] = "@(#) $RCSfile$ $Revision$ $Date$ $Name$"; +#endif /* DEBUG */ + +/* + * base.h + * + * This header file contains basic prototypes and preprocessor + * definitions used throughout nss but not available publicly. + */ + +#ifndef BASET_H +#include "baset.h" +#endif /* BASET_H */ + +#ifndef NSSBASE_H +#include "nssbase.h" +#endif /* NSSBASE_H */ + +#include "plhash.h" +#include "prthread.h" + +PR_BEGIN_EXTERN_C + +/* + * NSSArena + * + * The nonpublic methods relating to this type are: + * + * nssArena_Create -- constructor + * nssArena_Destroy + * nssArena_Mark + * nssArena_Release + * nssArena_Unmark + * + * nss_ZAlloc + * nss_ZFreeIf + * nss_ZRealloc + * + * Additionally, there are some preprocessor macros: + * + * nss_ZNEW + * nss_ZNEWARRAY + * + * In debug builds, the following calls are available: + * + * nssArena_verifyPointer + * nssArena_registerDestructor + * nssArena_deregisterDestructor + * + * The following preprocessor macro is also always available: + * + * nssArena_VERIFYPOINTER + * + * A constant PLHashAllocOps structure is available for users + * of the NSPL PLHashTable routines. + * + * nssArenaHashAllocOps + */ + +/* + * nssArena_Create + * + * This routine creates a new memory arena. This routine may return + * NULL upon error, in which case it will have set an error on the + * error stack. + * + * The error may be one of the following values: + * NSS_ERROR_NO_MEMORY + * + * Return value: + * NULL upon error + * A pointer to an NSSArena upon success + */ + +/* + * XXX fgmr + * Arenas can be named upon creation; this is mostly of use when + * debugging. Should we expose that here, allowing an optional + * "const char *name" argument? Should the public version of this + * call (NSSArena_Create) have it too? + */ + +NSS_EXTERN NSSArena * +nssArena_Create +( + void +); + +extern const NSSError NSS_ERROR_NO_MEMORY; + +/* + * nssArena_Destroy + * + * This routine will destroy the specified arena, freeing all memory + * allocated from it. This routine returns a PRStatus value; if + * successful, it will return PR_SUCCESS. If unsuccessful, it will + * set an error on the error stack and return PR_FAILURE. + * + * The error may be one of the following values: + * NSS_ERROR_INVALID_ARENA + * + * Return value: + * PR_SUCCESS + * PR_FAILURE + */ + +NSS_EXTERN PRStatus +nssArena_Destroy +( + NSSArena *arena +); + +extern const NSSError NSS_ERROR_INVALID_ARENA; + +/* + * nssArena_Mark + * + * This routine "marks" the current state of an arena. Space + * allocated after the arena has been marked can be freed by + * releasing the arena back to the mark with nssArena_Release, + * or committed by calling nssArena_Unmark. When successful, + * this routine returns a valid nssArenaMark pointer. This + * routine may return NULL upon error, in which case it will + * have set an error on the error stack. + * + * The error may be one of the following values: + * NSS_ERROR_INVALID_ARENA + * NSS_ERROR_NO_MEMORY + * NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD + * + * Return value: + * NULL upon failure + * An nssArenaMark pointer upon success + */ + +NSS_EXTERN nssArenaMark * +nssArena_Mark +( + NSSArena *arena +); + +extern const NSSError NSS_ERROR_INVALID_ARENA; +extern const NSSError NSS_ERROR_NO_MEMORY; +extern const NSSError NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD; + +/* + * nssArena_Release + * + * This routine invalidates and releases all memory allocated from + * the specified arena after the point at which the specified mark + * was obtained. This routine returns a PRStatus value; if successful, + * it will return PR_SUCCESS. If unsuccessful, it will set an error + * on the error stack and return PR_FAILURE. + * + * The error may be one of the following values: + * NSS_ERROR_INVALID_ARENA + * NSS_ERROR_INVALID_ARENA_MARK + * NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD + * + * Return value: + * PR_SUCCESS + * PR_FAILURE + */ + +NSS_EXTERN PRStatus +nssArena_Release +( + NSSArena *arena, + nssArenaMark *arenaMark +); + +extern const NSSError NSS_ERROR_INVALID_ARENA; +extern const NSSError NSS_ERROR_INVALID_ARENA_MARK; + +/* + * nssArena_Unmark + * + * This routine "commits" the indicated mark and any marks after + * it, making them unreleasable. Note that any earlier marks can + * still be released, and such a release will invalidate these + * later unmarked regions. If an arena is to be safely shared by + * more than one thread, all marks must be either released or + * unmarked. This routine returns a PRStatus value; if successful, + * it will return PR_SUCCESS. If unsuccessful, it will set an error + * on the error stack and return PR_FAILURE. + * + * The error may be one of the following values: + * NSS_ERROR_INVALID_ARENA + * NSS_ERROR_INVALID_ARENA_MARK + * NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD + * + * Return value: + * PR_SUCCESS + * PR_FAILURE + */ + +NSS_EXTERN PRStatus +nssArena_Unmark +( + NSSArena *arena, + nssArenaMark *arenaMark +); + +extern const NSSError NSS_ERROR_INVALID_ARENA; +extern const NSSError NSS_ERROR_INVALID_ARENA_MARK; +extern const NSSError NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD; + +#ifdef ARENA_DESTRUCTOR_LIST + +/* + * nssArena_registerDestructor + * + * This routine stores a pointer to a callback and an arbitrary + * pointer-sized argument in the arena, at the current point in + * the mark stack. If the arena is destroyed, or an "earlier" + * mark is released, then this destructor will be called at that + * time. Note that the destructor will be called with the arena + * locked, which means the destructor may free memory in that + * arena, but it may not allocate or cause to be allocated any + * memory. This callback facility was included to support our + * debug-version pointer-tracker feature; overuse runs counter to + * the the original intent of arenas. This routine returns a + * PRStatus value; if successful, it will return PR_SUCCESS. If + * unsuccessful, it will set an error on the error stack and + * return PR_FAILURE. + * + * The error may be one of the following values: + * NSS_ERROR_INVALID_ARENA + * NSS_ERROR_NO_MEMORY + * + * Return value: + * PR_SUCCESS + * PR_FAILURE + */ + +NSS_EXTERN PRStatus +nssArena_registerDestructor +( + NSSArena *arena, + void (*destructor)(void *argument), + void *arg +); + +extern const NSSError NSS_ERROR_INVALID_ARENA; +extern const NSSError NSS_ERROR_NO_MEMORY; + +/* + * nssArena_deregisterDestructor + * + * This routine will remove the first destructor in the specified + * arena which has the specified destructor and argument values. + * The destructor will not be called. This routine returns a + * PRStatus value; if successful, it will return PR_SUCCESS. If + * unsuccessful, it will set an error on the error stack and + * return PR_FAILURE. + * + * The error may be one of the following values: + * NSS_ERROR_INVALID_ARENA + * NSS_ERROR_NOT_FOUND + * + * Return value: + * PR_SUCCESS + * PR_FAILURE + */ + +NSS_EXTERN PRStatus +nssArena_deregisterDestructor +( + NSSArena *arena, + void (*destructor)(void *argument), + void *arg +); + +extern const NSSError NSS_ERROR_INVALID_ITEM; +extern const NSSError NSS_ERROR_INVALID_ARENA; +extern const NSSError NSS_ERROR_NOT_FOUND; + +#endif /* ARENA_DESTRUCTOR_LIST */ + +/* + * nss_ZAlloc + * + * This routine allocates and zeroes a section of memory of the + * size, and returns to the caller a pointer to that memory. If + * the optional arena argument is non-null, the memory will be + * obtained from that arena; otherwise, the memory will be obtained + * from the heap. This routine may return NULL upon error, in + * which case it will have set an error upon the error stack. The + * value specified for size may be zero; in which case a valid + * zero-length block of memory will be allocated. This block may + * be expanded by calling nss_ZRealloc. + * + * The error may be one of the following values: + * NSS_ERROR_INVALID_ARENA + * NSS_ERROR_NO_MEMORY + * NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD + * + * Return value: + * NULL upon error + * A pointer to the new segment of zeroed memory + */ + +NSS_EXTERN void * +nss_ZAlloc +( + NSSArena *arenaOpt, + PRUint32 size +); + +extern const NSSError NSS_ERROR_INVALID_ARENA; +extern const NSSError NSS_ERROR_NO_MEMORY; +extern const NSSError NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD; + +/* + * nss_ZFreeIf + * + * If the specified pointer is non-null, then the region of memory + * to which it points -- which must have been allocated with + * nss_ZAlloc -- will be zeroed and released. This routine + * returns a PRStatus value; if successful, it will return PR_SUCCESS. + * If unsuccessful, it will set an error on the error stack and return + * PR_FAILURE. + * + * The error may be one of the following values: + * NSS_ERROR_INVALID_POINTER + * + * Return value: + * PR_SUCCESS + * PR_FAILURE + */ + +NSS_EXTERN PRStatus +nss_ZFreeIf +( + void *pointer +); + +extern const NSSError NSS_ERROR_INVALID_POINTER; + +/* + * nss_ZRealloc + * + * This routine reallocates a block of memory obtained by calling + * nss_ZAlloc or nss_ZRealloc. The portion of memory + * between the new and old sizes -- which is either being newly + * obtained or released -- is in either case zeroed. This routine + * may return NULL upon failure, in which case it will have placed + * an error on the error stack. + * + * The error may be one of the following values: + * NSS_ERROR_INVALID_POINTER + * NSS_ERROR_NO_MEMORY + * NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD + * + * Return value: + * NULL upon error + * A pointer to the replacement segment of memory + */ + +NSS_EXTERN void * +nss_ZRealloc +( + void *pointer, + PRUint32 newSize +); + +extern const NSSError NSS_ERROR_INVALID_POINTER; +extern const NSSError NSS_ERROR_NO_MEMORY; +extern const NSSError NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD; + +/* + * nss_ZNEW + * + * This preprocessor macro will allocate memory for a new object + * of the specified type with nss_ZAlloc, and will cast the + * return value appropriately. If the optional arena argument is + * non-null, the memory will be obtained from that arena; otherwise, + * the memory will be obtained from the heap. This routine may + * return NULL upon error, in which case it will have set an error + * upon the error stack. + * + * The error may be one of the following values: + * NSS_ERROR_INVALID_ARENA + * NSS_ERROR_NO_MEMORY + * + * Return value: + * NULL upon error + * A pointer to the new segment of zeroed memory + */ + +/* The following line exceeds 72 characters, but emacs screws up if I split it. */ +#define nss_ZNEW(arenaOpt, type) ((type *)nss_ZAlloc((arenaOpt), sizeof(type))) + +/* + * nss_ZNEWARRAY + * + * This preprocessor macro will allocate memory for an array of + * new objects, and will cast the return value appropriately. + * If the optional arena argument is non-null, the memory will + * be obtained from that arena; otherwise, the memory will be + * obtained from the heap. This routine may return NULL upon + * error, in which case it will have set an error upon the error + * stack. The array size may be specified as zero. + * + * The error may be one of the following values: + * NSS_ERROR_INVALID_ARENA + * NSS_ERROR_NO_MEMORY + * + * Return value: + * NULL upon error + * A pointer to the new segment of zeroed memory + */ + +/* The following line exceeds 72 characters, but emacs screws up if I split it. */ +#define nss_ZNEWARRAY(arenaOpt, type, quantity) ((type *)nss_ZAlloc((arenaOpt), sizeof(type) * (quantity))) + +/* + * nss_ZREALLOCARRAY + * + * This preprocessor macro will reallocate memory for an array of + * new objects, and will cast the return value appropriately. + * This routine may return NULL upon error, in which case it will + * have set an error upon the error stack. + * + * The error may be one of the following values: + * NSS_ERROR_INVALID_POINTER + * NSS_ERROR_NO_MEMORY + * NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD + * + * Return value: + * NULL upon error + * A pointer to the replacement segment of memory + */ +#define nss_ZREALLOCARRAY(p, type, quantity) ((type *)nss_ZRealloc((p), sizeof(type) * (quantity))) + +/* + * nssArena_verifyPointer + * + * This method is only present in debug builds. + * + * If the specified pointer is a valid pointer to an NSSArena object, + * this routine will return PR_SUCCESS. Otherwise, it will put an + * error on the error stack and return PR_FAILURE. + * + * The error may be one of the following values: + * NSS_ERROR_INVALID_ARENA + * + * Return value: + * PR_SUCCESS if the pointer is valid + * PR_FAILURE if it isn't + */ + +#ifdef DEBUG +NSS_EXTERN PRStatus +nssArena_verifyPointer +( + const NSSArena *arena +); + +extern const NSSError NSS_ERROR_INVALID_ARENA; +#endif /* DEBUG */ + +/* + * nssArena_VERIFYPOINTER + * + * This macro is always available. In debug builds it will call + * nssArena_verifyPointer; in non-debug builds, it will merely + * check that the pointer is not null. Note that in non-debug + * builds it cannot place an error on the error stack. + * + * Return value: + * PR_SUCCESS if the pointer is valid + * PR_FAILURE if it isn't + */ + +#ifdef DEBUG +#define nssArena_VERIFYPOINTER(p) nssArena_verifyPointer(p) +#else /* DEBUG */ +/* The following line exceeds 72 characters, but emacs screws up if I split it. */ +#define nssArena_VERIFYPOINTER(p) (((NSSArena *)NULL == (p))?PR_FAILURE:PR_SUCCESS) +#endif /* DEBUG */ + +/* + * nssArenaHashAllocOps + * + * This constant structure contains allocation callbacks designed for + * use with the NSPL routine PL_NewHashTable. For example: + * + * NSSArena *hashTableArena = nssArena_Create(); + * PLHashTable *t = PL_NewHashTable(n, hasher, key_compare, + * value_compare, nssArenaHashAllocOps, hashTableArena); + */ + +NSS_EXTERN_DATA PLHashAllocOps nssArenaHashAllocOps; + +/* + * The error stack + * + * The nonpublic methods relating to the error stack are: + * + * nss_SetError + * nss_ClearErrorStack + */ + +/* + * nss_SetError + * + * This routine places a new error code on the top of the calling + * thread's error stack. Calling this routine wiht an error code + * of zero will clear the error stack. + */ + +NSS_EXTERN void +nss_SetError +( + PRUint32 error +); + +/* + * nss_ClearErrorStack + * + * This routine clears the calling thread's error stack. + */ + +NSS_EXTERN void +nss_ClearErrorStack +( + void +); + +/* + * NSSItem + * + * nssItem_Create + * nssItem_Duplicate + * nssItem_Equal + */ + +NSS_EXTERN NSSItem * +nssItem_Create +( + NSSArena *arenaOpt, + NSSItem *rvOpt, + PRUint32 length, + const void *data +); + +NSS_EXTERN void +nssItem_Destroy +( + NSSItem *item +); + +NSS_EXTERN NSSItem * +nssItem_Duplicate +( + NSSItem *obj, + NSSArena *arenaOpt, + NSSItem *rvOpt +); + +NSS_EXTERN PRBool +nssItem_Equal +( + const NSSItem *one, + const NSSItem *two, + PRStatus *statusOpt +); + +/* + * NSSUTF8 + * + * nssUTF8_CaseIgnoreMatch + * nssUTF8_Duplicate + * nssUTF8_Size + * nssUTF8_Length + * nssUTF8_CopyIntoFixedBuffer + */ + +/* + * nssUTF8_CaseIgnoreMatch + * + * Returns true if the two UTF8-encoded strings pointed to by the + * two specified NSSUTF8 pointers differ only in typcase. + * + * The error may be one of the following values: + * NSS_ERROR_INVALID_POINTER + * + * Return value: + * PR_TRUE if the strings match, ignoring case + * PR_FALSE if they don't + * PR_FALSE upon error + */ + +NSS_EXTERN PRBool +nssUTF8_CaseIgnoreMatch +( + const NSSUTF8 *a, + const NSSUTF8 *b, + PRStatus *statusOpt +); + +/* + * nssUTF8_Duplicate + * + * This routine duplicates the UTF8-encoded string pointed to by the + * specified NSSUTF8 pointer. If the optional arenaOpt argument is + * not null, the memory required will be obtained from that arena; + * otherwise, the memory required will be obtained from the heap. + * A pointer to the new string will be returned. In case of error, + * an error will be placed on the error stack and NULL will be + * returned. + * + * The error may be one of the following values: + * NSS_ERROR_INVALID_POINTER + * NSS_ERROR_INVALID_ARENA + * NSS_ERROR_NO_MEMORY + */ + +NSS_EXTERN NSSUTF8 * +nssUTF8_Duplicate +( + const NSSUTF8 *s, + NSSArena *arenaOpt +); + +/* + * nssUTF8_PrintableMatch + * + * Returns true if the two Printable strings pointed to by the + * two specified NSSUTF8 pointers match when compared with the + * rules for Printable String (leading and trailing spaces are + * disregarded, extents of whitespace match irregardless of length, + * and case is not significant), then PR_TRUE will be returned. + * Otherwise, PR_FALSE will be returned. Upon failure, PR_FALSE + * will be returned. If the optional statusOpt argument is not + * NULL, then PR_SUCCESS or PR_FAILURE will be stored in that + * location. + * + * The error may be one of the following values: + * NSS_ERROR_INVALID_POINTER + * + * Return value: + * PR_TRUE if the strings match, ignoring case + * PR_FALSE if they don't + * PR_FALSE upon error + */ + +NSS_EXTERN PRBool +nssUTF8_PrintableMatch +( + const NSSUTF8 *a, + const NSSUTF8 *b, + PRStatus *statusOpt +); + +/* + * nssUTF8_Size + * + * This routine returns the length in bytes (including the terminating + * null) of the UTF8-encoded string pointed to by the specified + * NSSUTF8 pointer. Zero is returned on error. + * + * The error may be one of the following values: + * NSS_ERROR_INVALID_POINTER + * NSS_ERROR_VALUE_TOO_LARGE + * + * Return value: + * nonzero size of the string + * 0 on error + */ + +NSS_EXTERN PRUint32 +nssUTF8_Size +( + const NSSUTF8 *s, + PRStatus *statusOpt +); + +extern const NSSError NSS_ERROR_INVALID_POINTER; +extern const NSSError NSS_ERROR_VALUE_TOO_LARGE; + +/* + * nssUTF8_Length + * + * This routine returns the length in characters (not including the + * terminating null) of the UTF8-encoded string pointed to by the + * specified NSSUTF8 pointer. + * + * The error may be one of the following values: + * NSS_ERROR_INVALID_POINTER + * NSS_ERROR_VALUE_TOO_LARGE + * NSS_ERROR_INVALID_STRING + * + * Return value: + * length of the string (which may be zero) + * 0 on error + */ + +NSS_EXTERN PRUint32 +nssUTF8_Length +( + const NSSUTF8 *s, + PRStatus *statusOpt +); + +extern const NSSError NSS_ERROR_INVALID_POINTER; +extern const NSSError NSS_ERROR_VALUE_TOO_LARGE; +extern const NSSError NSS_ERROR_INVALID_STRING; + +/* + * nssUTF8_Create + * + * This routine creates a UTF8 string from a string in some other + * format. Some types of string may include embedded null characters, + * so for them the length parameter must be used. For string types + * that are null-terminated, the length parameter is optional; if it + * is zero, it will be ignored. If the optional arena argument is + * non-null, the memory used for the new string will be obtained from + * that arena, otherwise it will be obtained from the heap. This + * routine may return NULL upon error, in which case it will have + * placed an error on the error stack. + * + * The error may be one of the following: + * NSS_ERROR_INVALID_POINTER + * NSS_ERROR_NO_MEMORY + * NSS_ERROR_UNSUPPORTED_TYPE + * + * Return value: + * NULL upon error + * A non-null pointer to a new UTF8 string otherwise + */ + +NSS_EXTERN NSSUTF8 * +nssUTF8_Create +( + NSSArena *arenaOpt, + nssStringType type, + const void *inputString, + PRUint32 size /* in bytes, not characters */ +); + +extern const NSSError NSS_ERROR_INVALID_POINTER; +extern const NSSError NSS_ERROR_NO_MEMORY; +extern const NSSError NSS_ERROR_UNSUPPORTED_TYPE; + +NSS_EXTERN NSSItem * +nssUTF8_GetEncoding +( + NSSArena *arenaOpt, + NSSItem *rvOpt, + nssStringType type, + NSSUTF8 *string +); + +/* + * nssUTF8_CopyIntoFixedBuffer + * + * This will copy a UTF8 string into a fixed-length buffer, making + * sure that the all characters are valid. Any remaining space will + * be padded with the specified ASCII character, typically either + * null or space. + * + * Blah, blah, blah. + */ + +extern const NSSError NSS_ERROR_INVALID_POINTER; +extern const NSSError NSS_ERROR_INVALID_ARGUMENT; + +NSS_EXTERN PRStatus +nssUTF8_CopyIntoFixedBuffer +( + NSSUTF8 *string, + char *buffer, + PRUint32 bufferSize, + char pad +); + +/* + * nssUTF8_Equal + * + */ + +NSS_EXTERN PRBool +nssUTF8_Equal +( + const NSSUTF8 *a, + const NSSUTF8 *b, + PRStatus *statusOpt +); + +/* + * nssList + * + * The goal is to provide a simple, optionally threadsafe, linked list + * class. Since NSS did not seem to use the circularity of PRCList + * much before, this provides a list that appears to be a linear, + * NULL-terminated list. + */ + +/* + * nssList_Create + * + * If threadsafe is true, the list will be locked during modifications + * and traversals. + */ +NSS_EXTERN nssList * +nssList_Create +( + NSSArena *arenaOpt, + PRBool threadSafe +); + +/* + * nssList_Destroy + */ +NSS_EXTERN PRStatus +nssList_Destroy +( + nssList *list +); + +NSS_EXTERN void +nssList_Clear +( + nssList *list, + nssListElementDestructorFunc destructor +); + +/* + * nssList_SetCompareFunction + * + * By default, two list elements will be compared by comparing their + * data pointers. By setting this function, the user can control + * how elements are compared. + */ +NSS_EXTERN void +nssList_SetCompareFunction +( + nssList *list, + nssListCompareFunc compareFunc +); + +/* + * nssList_SetSortFunction + * + * Sort function to use for an ordered list. + */ +NSS_EXTERN void +nssList_SetSortFunction +( + nssList *list, + nssListSortFunc sortFunc +); + +/* + * nssList_Add + */ +NSS_EXTERN PRStatus +nssList_Add +( + nssList *list, + void *data +); + +/* + * nssList_AddUnique + * + * This will use the compare function to see if the element is already + * in the list. + */ +NSS_EXTERN PRStatus +nssList_AddUnique +( + nssList *list, + void *data +); + +/* + * nssList_Remove + * + * Uses the compare function to locate the element and remove it. + */ +NSS_EXTERN PRStatus +nssList_Remove(nssList *list, void *data); + +/* + * nssList_Get + * + * Uses the compare function to locate an element. Also serves as + * nssList_Exists. + */ +NSS_EXTERN void * +nssList_Get +( + nssList *list, + void *data +); + +/* + * nssList_Count + */ +NSS_EXTERN PRUint32 +nssList_Count +( + nssList *list +); + +/* + * nssList_GetArray + * + * Fill rvArray, up to maxElements, with elements in the list. The + * array is NULL-terminated, so its allocated size must be maxElements + 1. + */ +NSS_EXTERN PRStatus +nssList_GetArray +( + nssList *list, + void **rvArray, + PRUint32 maxElements +); + +/* + * nssList_CreateIterator + * + * Create an iterator for list traversal. + */ +NSS_EXTERN nssListIterator * +nssList_CreateIterator +( + nssList *list +); + +NSS_EXTERN nssList * +nssList_Clone +( + nssList *list +); + +/* + * nssListIterator_Destroy + */ +NSS_EXTERN void +nssListIterator_Destroy +( + nssListIterator *iter +); + +/* + * nssListIterator_Start + * + * Begin a list iteration. After this call, if the list is threadSafe, + * the list is *locked*. + */ +NSS_EXTERN void * +nssListIterator_Start +( + nssListIterator *iter +); + +/* + * nssListIterator_Next + * + * Continue a list iteration. + */ +NSS_EXTERN void * +nssListIterator_Next +( + nssListIterator *iter +); + +/* + * nssListIterator_Finish + * + * Complete a list iteration. This *must* be called in order for the + * lock to be released. + */ +NSS_EXTERN PRStatus +nssListIterator_Finish +( + nssListIterator *iter +); + +/* + * nssHash + * + * nssHash_Create + * nssHash_Destroy + * nssHash_Add + * nssHash_Remove + * nssHash_Count + * nssHash_Exists + * nssHash_Lookup + * nssHash_Iterate + */ + +/* + * nssHash_Create + * + */ + +NSS_EXTERN nssHash * +nssHash_Create +( + NSSArena *arenaOpt, + PRUint32 numBuckets, + PLHashFunction keyHash, + PLHashComparator keyCompare, + PLHashComparator valueCompare +); + +NSS_EXTERN nssHash * +nssHash_CreatePointer +( + NSSArena *arenaOpt, + PRUint32 numBuckets +); + +NSS_EXTERN nssHash * +nssHash_CreateString +( + NSSArena *arenaOpt, + PRUint32 numBuckets +); + +NSS_EXTERN nssHash * +nssHash_CreateItem +( + NSSArena *arenaOpt, + PRUint32 numBuckets +); + +/* + * nssHash_Destroy + * + */ +NSS_EXTERN void +nssHash_Destroy +( + nssHash *hash +); + +/* + * nssHash_Add + * + */ + +extern const NSSError NSS_ERROR_HASH_COLLISION; + +NSS_EXTERN PRStatus +nssHash_Add +( + nssHash *hash, + const void *key, + const void *value +); + +/* + * nssHash_Remove + * + */ +NSS_EXTERN void +nssHash_Remove +( + nssHash *hash, + const void *it +); + +/* + * nssHash_Count + * + */ +NSS_EXTERN PRUint32 +nssHash_Count +( + nssHash *hash +); + +/* + * nssHash_Exists + * + */ +NSS_EXTERN PRBool +nssHash_Exists +( + nssHash *hash, + const void *it +); + +/* + * nssHash_Lookup + * + */ +NSS_EXTERN void * +nssHash_Lookup +( + nssHash *hash, + const void *it +); + +/* + * nssHash_Iterate + * + */ +NSS_EXTERN void +nssHash_Iterate +( + nssHash *hash, + nssHashIterator fcn, + void *closure +); + + +/* + * nssPointerTracker + * + * This type and these methods are only present in debug builds. + * + * The nonpublic methods relating to this type are: + * + * nssPointerTracker_initialize + * nssPointerTracker_finalize + * nssPointerTracker_add + * nssPointerTracker_remove + * nssPointerTracker_verify + */ + +/* + * nssPointerTracker_initialize + * + * This method is only present in debug builds. + * + * This routine initializes an nssPointerTracker object. Note that + * the object must have been declared *static* to guarantee that it + * is in a zeroed state initially. This routine is idempotent, and + * may even be safely called by multiple threads simultaneously with + * the same argument. This routine returns a PRStatus value; if + * successful, it will return PR_SUCCESS. On failure it will set an + * error on the error stack and return PR_FAILURE. + * + * The error may be one of the following values: + * NSS_ERROR_NO_MEMORY + * + * Return value: + * PR_SUCCESS + * PR_FAILURE + */ + +#ifdef DEBUG +NSS_EXTERN PRStatus +nssPointerTracker_initialize +( + nssPointerTracker *tracker +); + +extern const NSSError NSS_ERROR_NO_MEMORY; +#endif /* DEBUG */ + +/* + * nssPointerTracker_finalize + * + * This method is only present in debug builds. + * + * This routine returns the nssPointerTracker object to the pre- + * initialized state, releasing all resources used by the object. + * It will *NOT* destroy the objects being tracked by the pointer + * (should any remain), and therefore cannot be used to "sweep up" + * remaining objects. This routine returns a PRStatus value; if + * successful, it will return PR_SUCCES. On failure it will set an + * error on the error stack and return PR_FAILURE. If any objects + * remain in the tracker when it is finalized, that will be treated + * as an error. + * + * The error may be one of the following values: + * NSS_ERROR_TRACKER_NOT_EMPTY + * + * Return value: + * PR_SUCCESS + * PR_FAILURE + */ + +#ifdef DEBUG +NSS_EXTERN PRStatus +nssPointerTracker_finalize +( + nssPointerTracker *tracker +); + +extern const NSSError NSS_ERROR_TRACKER_NOT_EMPTY; +#endif /* DEBUG */ + +/* + * nssPointerTracker_add + * + * This method is only present in debug builds. + * + * This routine adds the specified pointer to the nssPointerTracker + * object. It should be called in constructor objects to register + * new valid objects. The nssPointerTracker is threadsafe, but this + * call is not idempotent. This routine returns a PRStatus value; + * if successful it will return PR_SUCCESS. On failure it will set + * an error on the error stack and return PR_FAILURE. + * + * The error may be one of the following values: + * NSS_ERROR_NO_MEMORY + * NSS_ERROR_TRACKER_NOT_INITIALIZED + * NSS_ERROR_DUPLICATE_POINTER + * + * Return value: + * PR_SUCCESS + * PR_FAILURE + */ + +#ifdef DEBUG +NSS_EXTERN PRStatus +nssPointerTracker_add +( + nssPointerTracker *tracker, + const void *pointer +); + +extern const NSSError NSS_ERROR_NO_MEMORY; +extern const NSSError NSS_ERROR_TRACKER_NOT_INITIALIZED; +extern const NSSError NSS_ERROR_DUPLICATE_POINTER; +#endif /* DEBUG */ + +/* + * nssPointerTracker_remove + * + * This method is only present in debug builds. + * + * This routine removes the specified pointer from the + * nssPointerTracker object. It does not call any destructor for the + * object; rather, this should be called from the object's destructor. + * The nssPointerTracker is threadsafe, but this call is not + * idempotent. This routine returns a PRStatus value; if successful + * it will return PR_SUCCESS. On failure it will set an error on the + * error stack and return PR_FAILURE. + * + * The error may be one of the following values: + * NSS_ERROR_TRACKER_NOT_INITIALIZED + * NSS_ERROR_POINTER_NOT_REGISTERED + * + * Return value: + * PR_SUCCESS + * PR_FAILURE + */ + +#ifdef DEBUG +NSS_EXTERN PRStatus +nssPointerTracker_remove +( + nssPointerTracker *tracker, + const void *pointer +); + +extern const NSSError NSS_ERROR_TRACKER_NOT_INITIALIZED; +extern const NSSError NSS_ERROR_POINTER_NOT_REGISTERED; +#endif /* DEBUG */ + +/* + * nssPointerTracker_verify + * + * This method is only present in debug builds. + * + * This routine verifies that the specified pointer has been registered + * with the nssPointerTracker object. The nssPointerTracker object is + * threadsafe, and this call may be safely called from multiple threads + * simultaneously with the same arguments. This routine returns a + * PRStatus value; if the pointer is registered this will return + * PR_SUCCESS. Otherwise it will set an error on the error stack and + * return PR_FAILURE. Although the error is suitable for leaving on + * the stack, callers may wish to augment the information available by + * placing a more type-specific error on the stack. + * + * The error may be one of the following values: + * NSS_ERROR_POINTER_NOT_REGISTERED + * + * Return value: + * PR_SUCCESS + * PR_FAILRUE + */ + +#ifdef DEBUG +NSS_EXTERN PRStatus +nssPointerTracker_verify +( + nssPointerTracker *tracker, + const void *pointer +); + +extern const NSSError NSS_ERROR_POINTER_NOT_REGISTERED; +#endif /* DEBUG */ + +/* + * libc + * + * nsslibc_memcpy + * nsslibc_memset + * nsslibc_offsetof + */ + +/* + * nsslibc_memcpy + * + * Errors: + * NSS_ERROR_INVALID_POINTER + * + * Return value: + * NULL on error + * The destination pointer on success + */ + +NSS_EXTERN void * +nsslibc_memcpy +( + void *dest, + const void *source, + PRUint32 n +); + +extern const NSSError NSS_ERROR_INVALID_POINTER; + +/* + * nsslibc_memset + * + * Errors: + * NSS_ERROR_INVALID_POINTER + * + * Return value: + * NULL on error + * The destination pointer on success + */ + +NSS_EXTERN void * +nsslibc_memset +( + void *dest, + PRUint8 byte, + PRUint32 n +); + +extern const NSSError NSS_ERROR_INVALID_POINTER; + +/* + * nsslibc_memequal + * + * Errors: + * NSS_ERROR_INVALID_POINTER + * + * Return value: + * PR_TRUE if they match + * PR_FALSE if they don't + * PR_FALSE upon error + */ + +NSS_EXTERN PRBool +nsslibc_memequal +( + const void *a, + const void *b, + PRUint32 len, + PRStatus *statusOpt +); + +extern const NSSError NSS_ERROR_INVALID_POINTER; + +#define nsslibc_offsetof(str, memb) ((PRPtrdiff)(&(((str *)0)->memb))) + +/* + * nss_NewThreadPrivateIndex + * + */ + +NSS_EXTERN PRStatus +nss_NewThreadPrivateIndex +( + PRUintn *ip, + PRThreadPrivateDTOR dtor +); + +/* + * nss_GetThreadPrivate + * + */ + +NSS_EXTERN void * +nss_GetThreadPrivate +( + PRUintn i +); + +/* + * nss_SetThreadPrivate + * + */ + +NSS_EXTERN void +nss_SetThreadPrivate +( + PRUintn i, + void *v +); + + +PR_END_EXTERN_C + +#endif /* BASE_H */ diff --git a/security/nss/lib/base/baset.h b/security/nss/lib/base/baset.h new file mode 100644 index 000000000..6df6da5aa --- /dev/null +++ b/security/nss/lib/base/baset.h @@ -0,0 +1,158 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#ifndef BASET_H +#define BASET_H + +#ifdef DEBUG +static const char BASET_CVS_ID[] = "@(#) $RCSfile$ $Revision$ $Date$ $Name$"; +#endif /* DEBUG */ + +/* + * baset.h + * + * This file contains definitions for the basic types used throughout + * nss but not available publicly. + */ + +#ifndef NSSBASET_H +#include "nssbaset.h" +#endif /* NSSBASET_H */ + +#include "plhash.h" + +PR_BEGIN_EXTERN_C + +/* + * nssArenaMark + * + * This type is used to mark the current state of an NSSArena. + */ + +struct nssArenaMarkStr; +typedef struct nssArenaMarkStr nssArenaMark; + +#ifdef DEBUG +/* + * ARENA_THREADMARK + * + * Optionally, this arena implementation can be compiled with some + * runtime checking enabled, which will catch the situation where + * one thread "marks" the arena, another thread allocates memory, + * and then the mark is released. Usually this is a surprise to + * the second thread, and this leads to weird runtime errors. + * Define ARENA_THREADMARK to catch these cases; we define it for all + * (internal and external) debug builds. + */ +#define ARENA_THREADMARK + +/* + * ARENA_DESTRUCTOR_LIST + * + * Unfortunately, our pointer-tracker facility, used in debug + * builds to agressively fight invalid pointers, requries that + * pointers be deregistered when objects are destroyed. This + * conflicts with the standard arena usage where "memory-only" + * objects (that don't hold onto resources outside the arena) + * can be allocated in an arena, and never destroyed other than + * when the arena is destroyed. Therefore we have added a + * destructor-registratio facility to our arenas. This was not + * a simple decision, since we're getting ever-further away from + * the original arena philosophy. However, it was felt that + * adding this in debug builds wouldn't be so bad; as it would + * discourage them from being used for "serious" purposes. + * This facility requires ARENA_THREADMARK to be defined. + */ +#ifdef ARENA_THREADMARK +#define ARENA_DESTRUCTOR_LIST +#endif /* ARENA_THREADMARK */ + +#endif /* DEBUG */ + +typedef struct nssListStr nssList; +typedef struct nssListIteratorStr nssListIterator; +typedef PRBool (* nssListCompareFunc)(void *a, void *b); +typedef PRIntn (* nssListSortFunc)(void *a, void *b); +typedef void (* nssListElementDestructorFunc)(void *el); + +typedef struct nssHashStr nssHash; +typedef void (PR_CALLBACK *nssHashIterator)(const void *key, + void *value, + void *arg); + +/* + * nssPointerTracker + * + * This type is used in debug builds (both external and internal) to + * track our object pointers. Objects of this type must be statically + * allocated, which means the structure size must be available to the + * compiler. Therefore we must expose the contents of this structure. + * But please don't access elements directly; use the accessors. + */ + +#ifdef DEBUG +struct nssPointerTrackerStr { + PRCallOnceType once; + PZLock *lock; + PLHashTable *table; +}; +typedef struct nssPointerTrackerStr nssPointerTracker; +#endif /* DEBUG */ + +/* + * nssStringType + * + * There are several types of strings in the real world. We try to + * use only UTF8 and avoid the rest, but that's not always possible. + * So we have a couple converter routines to go to and from the other + * string types. We have to be able to specify those string types, + * so we have this enumeration. + */ + +enum nssStringTypeEnum { + nssStringType_DirectoryString, + nssStringType_TeletexString, /* Not "teletext" with trailing 't' */ + nssStringType_PrintableString, + nssStringType_UniversalString, + nssStringType_BMPString, + nssStringType_UTF8String, + nssStringType_PHGString, + nssStringType_GeneralString, + + nssStringType_Unknown = -1 +}; +typedef enum nssStringTypeEnum nssStringType; + +PR_END_EXTERN_C + +#endif /* BASET_H */ diff --git a/security/nss/lib/base/config.mk b/security/nss/lib/base/config.mk new file mode 100644 index 000000000..4a9ed7dda --- /dev/null +++ b/security/nss/lib/base/config.mk @@ -0,0 +1,48 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code is the Netscape security libraries. +# +# The Initial Developer of the Original Code is Netscape +# Communications Corporation. Portions created by Netscape are +# Copyright (C) 1994-2000 Netscape Communications Corporation. All +# Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the +# terms of the GNU General Public License Version 2 or later (the +# "GPL"), in which case the provisions of the GPL are applicable +# instead of those above. If you wish to allow use of your +# version of this file only under the terms of the GPL and not to +# allow others to use your version of this file under the MPL, +# indicate your decision by deleting the provisions above and +# replace them with the notice and other provisions required by +# the GPL. If you do not delete the provisions above, a recipient +# may use your version of this file under either the MPL or the +# GPL. +# +CONFIG_CVS_ID = "@(#) $RCSfile$ $Revision$ $Date$ $Name$" + +ifdef BUILD_IDG +DEFINES += -DNSSDEBUG +endif + +# +# Override TARGETS variable so that only static libraries +# are specifed as dependencies within rules.mk. +# + +TARGETS = $(LIBRARY) +SHARED_LIBRARY = +IMPORT_LIBRARY = +PROGRAM = + diff --git a/security/nss/lib/base/error.c b/security/nss/lib/base/error.c new file mode 100644 index 000000000..3e736b2b0 --- /dev/null +++ b/security/nss/lib/base/error.c @@ -0,0 +1,297 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#ifdef DEBUG +static const char CVS_ID[] = "@(#) $RCSfile$ $Revision$ $Date$ $Name$"; +#endif /* DEBUG */ + +/* + * error.c + * + * This file contains the code implementing the per-thread error + * stacks upon which most NSS routines report their errors. + */ + +#ifndef BASE_H +#include "base.h" +#endif /* BASE_H */ + +/* + * The stack itself has a header, and a sequence of integers. + * The header records the amount of space (as measured in stack + * slots) already allocated for the stack, and the count of the + * number of records currently being used. + */ + +struct stack_header_str { + PRUint16 space; + PRUint16 count; +}; + +struct error_stack_str { + struct stack_header_str header; + PRInt32 stack[1]; +}; +typedef struct error_stack_str error_stack; + +/* + * error_stack_index + * + * Thread-private data must be indexed. This is that index. + * See PR_NewThreadPrivateIndex for more information. + */ + +static PRUintn error_stack_index; + +/* + * call_once + * + * The thread-private index must be obtained (once!) at runtime. + * This block is used for that one-time call. + */ + +static PRCallOnceType error_call_once; + +/* + * error_once_function + * + * This is the once-called callback. + */ + +static PRStatus +error_once_function +( + void +) +{ + return nss_NewThreadPrivateIndex(&error_stack_index,PR_Free); + /* return PR_NewThreadPrivateIndex(&error_stack_index, PR_Free); */ +} + +/* + * error_get_my_stack + * + * This routine returns the calling thread's error stack, creating + * it if necessary. It may return NULL upon error, which implicitly + * means that it ran out of memory. + */ + +static error_stack * +error_get_my_stack +( + void +) +{ + PRStatus st; + error_stack *rv; + PRUintn new_size; + PRUint32 new_bytes; + error_stack *new_stack; + + if( 0 == error_stack_index ) { + st = PR_CallOnce(&error_call_once, error_once_function); + if( PR_SUCCESS != st ) { + return (error_stack *)NULL; + } + } + + rv = (error_stack *)nss_GetThreadPrivate(error_stack_index); + if( (error_stack *)NULL == rv ) { + /* Doesn't exist; create one */ + new_size = 16; + } else { + if( rv->header.count == rv->header.space ) { + /* Too small, expand it */ + new_size = rv->header.space + 16; + } else { + /* Okay, return it */ + return rv; + } + } + + new_bytes = (new_size * sizeof(PRInt32)) + + sizeof(struct stack_header_str); + /* Use NSPR's calloc/realloc, not NSS's, to avoid loops! */ + new_stack = PR_Calloc(1, new_bytes); + + if( (error_stack *)NULL != new_stack ) { + if( (error_stack *)NULL != rv ) { + (void)nsslibc_memcpy(new_stack,rv,rv->header.space); + } + new_stack->header.space = new_size; + } + + /* Set the value, whether or not the allocation worked */ + nss_SetThreadPrivate(error_stack_index, new_stack); + return new_stack; +} + +/* + * The error stack + * + * The public methods relating to the error stack are: + * + * NSS_GetError + * NSS_GetErrorStack + * + * The nonpublic methods relating to the error stack are: + * + * nss_SetError + * nss_ClearErrorStack + * + */ + +/* + * NSS_GetError + * + * This routine returns the highest-level (most general) error set + * by the most recent NSS library routine called by the same thread + * calling this routine. + * + * This routine cannot fail. However, it may return zero, which + * indicates that the previous NSS library call did not set an error. + * + * Return value: + * 0 if no error has been set + * A nonzero error number + */ + +NSS_IMPLEMENT PRInt32 +NSS_GetError +( + void +) +{ + error_stack *es = error_get_my_stack(); + + if( (error_stack *)NULL == es ) { + return NSS_ERROR_NO_MEMORY; /* Good guess! */ + } + + if( 0 == es->header.count ) { + return 0; + } + + return es->stack[ es->header.count-1 ]; +} + +/* + * NSS_GetErrorStack + * + * This routine returns a pointer to an array of integers, containing + * the entire sequence or "stack" of errors set by the most recent NSS + * library routine called by the same thread calling this routine. + * NOTE: the caller DOES NOT OWN the memory pointed to by the return + * value. The pointer will remain valid until the calling thread + * calls another NSS routine. The lowest-level (most specific) error + * is first in the array, and the highest-level is last. The array is + * zero-terminated. This routine may return NULL upon error; this + * indicates a low-memory situation. + * + * Return value: + * NULL upon error, which is an implied NSS_ERROR_NO_MEMORY + * A NON-caller-owned pointer to an array of integers + */ + +NSS_IMPLEMENT PRInt32 * +NSS_GetErrorStack +( + void +) +{ + error_stack *es = error_get_my_stack(); + + if( (error_stack *)NULL == es ) { + return (PRInt32 *)NULL; + } + + /* Make sure it's terminated */ + es->stack[ es->header.count ] = 0; + + return es->stack; +} + +/* + * nss_SetError + * + * This routine places a new error code on the top of the calling + * thread's error stack. Calling this routine wiht an error code + * of zero will clear the error stack. + */ + +NSS_IMPLEMENT void +nss_SetError +( + PRUint32 error +) +{ + error_stack *es; + + if( 0 == error ) { + nss_ClearErrorStack(); + return; + } + + es = error_get_my_stack(); + if( (error_stack *)NULL == es ) { + /* Oh, well. */ + return; + } + + es->stack[ es->header.count ] = error; + es->header.count++; + return; +} + +/* + * nss_ClearErrorStack + * + * This routine clears the calling thread's error stack. + */ + +NSS_IMPLEMENT void +nss_ClearErrorStack +( + void +) +{ + error_stack *es = error_get_my_stack(); + if( (error_stack *)NULL == es ) { + /* Oh, well. */ + return; + } + + es->header.count = 0; + es->stack[0] = 0; + return; +} diff --git a/security/nss/lib/base/errorval.c b/security/nss/lib/base/errorval.c new file mode 100644 index 000000000..2f2bfcce7 --- /dev/null +++ b/security/nss/lib/base/errorval.c @@ -0,0 +1,89 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#ifdef DEBUG +static const char CVS_ID[] = "@(#) $RCSfile$ $Revision$ $Date$ $Name$"; +#endif /* DEBUG */ + +/* + * errorval.c + * + * This file contains the actual error constants used in NSS. + */ + +#ifndef NSSBASET_H +#include "nssbaset.h" +#endif /* NSSBASET_H */ + +const NSSError NSS_ERROR_NO_ERROR = 0; +const NSSError NSS_ERROR_INTERNAL_ERROR = 1; +const NSSError NSS_ERROR_NO_MEMORY = 2; +const NSSError NSS_ERROR_INVALID_POINTER = 3; +const NSSError NSS_ERROR_INVALID_ARENA = 4; +const NSSError NSS_ERROR_INVALID_ARENA_MARK = 5; +const NSSError NSS_ERROR_DUPLICATE_POINTER = 6; +const NSSError NSS_ERROR_POINTER_NOT_REGISTERED = 7; +const NSSError NSS_ERROR_TRACKER_NOT_EMPTY = 8; +const NSSError NSS_ERROR_TRACKER_NOT_INITIALIZED = 9; +const NSSError NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD = 10; +const NSSError NSS_ERROR_VALUE_TOO_LARGE = 11; +const NSSError NSS_ERROR_UNSUPPORTED_TYPE = 12; +const NSSError NSS_ERROR_BUFFER_TOO_SHORT = 13; +const NSSError NSS_ERROR_INVALID_ATOB_CONTEXT = 14; +const NSSError NSS_ERROR_INVALID_BASE64 = 15; +const NSSError NSS_ERROR_INVALID_BTOA_CONTEXT = 16; +const NSSError NSS_ERROR_INVALID_ITEM = 17; +const NSSError NSS_ERROR_INVALID_STRING = 18; +const NSSError NSS_ERROR_INVALID_ASN1ENCODER = 19; +const NSSError NSS_ERROR_INVALID_ASN1DECODER = 20; + +const NSSError NSS_ERROR_INVALID_BER = 21; +const NSSError NSS_ERROR_INVALID_ATAV = 22; +const NSSError NSS_ERROR_INVALID_ARGUMENT = 23; +const NSSError NSS_ERROR_INVALID_UTF8 = 24; +const NSSError NSS_ERROR_INVALID_NSSOID = 25; +const NSSError NSS_ERROR_UNKNOWN_ATTRIBUTE = 26; + +const NSSError NSS_ERROR_NOT_FOUND = 27; + +const NSSError NSS_ERROR_INVALID_PASSWORD = 28; +const NSSError NSS_ERROR_USER_CANCELED = 29; + +const NSSError NSS_ERROR_MAXIMUM_FOUND = 30; + +const NSSError NSS_ERROR_CERTIFICATE_ISSUER_NOT_FOUND = 31; + +const NSSError NSS_ERROR_CERTIFICATE_IN_CACHE = 32; + +const NSSError NSS_ERROR_HASH_COLLISION = 33; + diff --git a/security/nss/lib/base/hash.c b/security/nss/lib/base/hash.c new file mode 100644 index 000000000..811fcd593 --- /dev/null +++ b/security/nss/lib/base/hash.c @@ -0,0 +1,404 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#ifdef DEBUG +static const char CVS_ID[] = "@(#) $RCSfile$ $Revision$ $Date$ $Name$"; +#endif /* DEBUG */ + +/* + * hash.c + * + * This is merely a couple wrappers around NSPR's PLHashTable, using + * the identity hash and arena-aware allocators. + * This is a copy of ckfw/hash.c, with modifications to use NSS types + * (not Cryptoki types). Would like for this to be a single implementation, + * but doesn't seem like it will work. + */ + +#ifndef BASE_H +#include "base.h" +#endif /* BASE_H */ + +/* + * nssHash + * + * nssHash_Create + * nssHash_Destroy + * nssHash_Add + * nssHash_Remove + * nssHash_Count + * nssHash_Exists + * nssHash_Lookup + * nssHash_Iterate + */ + +struct nssHashStr { + NSSArena *arena; + PRBool i_alloced_arena; + PRLock *mutex; + + /* + * The invariant that mutex protects is: + * The count accurately reflects the hashtable state. + */ + + PLHashTable *plHashTable; + PRUint32 count; +}; + +static PLHashNumber +nss_identity_hash +( + const void *key +) +{ + PRUint32 i = (PRUint32)key; + PR_ASSERT(sizeof(PLHashNumber) == sizeof(PRUint32)); + return (PLHashNumber)i; +} + +static PLHashNumber +nss_item_hash +( + const void *key +) +{ + int i; + PLHashNumber h; + NSSItem *it = (NSSItem *)key; + h = 0; + for (i=0; i<it->size; i++) + h = (h >> 28) ^ (h << 4) ^ ((unsigned char *)it->data)[i]; + return h; +} + +static int +nss_compare_items(const void *v1, const void *v2) +{ + PRStatus ignore; + return (int)nssItem_Equal((NSSItem *)v1, (NSSItem *)v2, &ignore); +} + +/* + * nssHash_create + * + */ +NSS_IMPLEMENT nssHash * +nssHash_Create +( + NSSArena *arenaOpt, + PRUint32 numBuckets, + PLHashFunction keyHash, + PLHashComparator keyCompare, + PLHashComparator valueCompare +) +{ + nssHash *rv; + NSSArena *arena; + PRBool i_alloced; + +#ifdef NSSDEBUG + if( arenaOpt && PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) { + nss_SetError(NSS_ERROR_INVALID_POINTER); + return (nssHash *)NULL; + } +#endif /* NSSDEBUG */ + + if (arenaOpt) { + arena = arenaOpt; + i_alloced = PR_FALSE; + } else { + arena = nssArena_Create(); + i_alloced = PR_TRUE; + } + + rv = nss_ZNEW(arena, nssHash); + if( (nssHash *)NULL == rv ) { + goto loser; + } + + rv->mutex = PZ_NewLock(nssILockOther); + if( (PZLock *)NULL == rv->mutex ) { + goto loser; + } + + rv->plHashTable = PL_NewHashTable(numBuckets, + keyHash, keyCompare, valueCompare, + &nssArenaHashAllocOps, arena); + if( (PLHashTable *)NULL == rv->plHashTable ) { + (void)PZ_DestroyLock(rv->mutex); + goto loser; + } + + rv->count = 0; + rv->arena = arena; + rv->i_alloced_arena = i_alloced; + + return rv; +loser: + (void)nss_ZFreeIf(rv); + return (nssHash *)NULL; +} + +/* + * nssHash_CreatePointer + * + */ +NSS_IMPLEMENT nssHash * +nssHash_CreatePointer +( + NSSArena *arenaOpt, + PRUint32 numBuckets +) +{ + return nssHash_Create(arenaOpt, numBuckets, + nss_identity_hash, PL_CompareValues, PL_CompareValues); +} + +/* + * nssHash_CreateString + * + */ +NSS_IMPLEMENT nssHash * +nssHash_CreateString +( + NSSArena *arenaOpt, + PRUint32 numBuckets +) +{ + return nssHash_Create(arenaOpt, numBuckets, + PL_HashString, PL_CompareStrings, PL_CompareStrings); +} + +/* + * nssHash_CreateItem + * + */ +NSS_IMPLEMENT nssHash * +nssHash_CreateItem +( + NSSArena *arenaOpt, + PRUint32 numBuckets +) +{ + return nssHash_Create(arenaOpt, numBuckets, + nss_item_hash, nss_compare_items, PL_CompareValues); +} + +/* + * nssHash_Destroy + * + */ +NSS_IMPLEMENT void +nssHash_Destroy +( + nssHash *hash +) +{ + (void)PZ_DestroyLock(hash->mutex); + PL_HashTableDestroy(hash->plHashTable); + if (hash->i_alloced_arena) { + nssArena_Destroy(hash->arena); + } else { + nss_ZFreeIf(hash); + } +} + +/* + * nssHash_Add + * + */ +NSS_IMPLEMENT PRStatus +nssHash_Add +( + nssHash *hash, + const void *key, + const void *value +) +{ + PRStatus error = PR_FAILURE; + PLHashEntry *he; + + PZ_Lock(hash->mutex); + + he = PL_HashTableAdd(hash->plHashTable, key, (void *)value); + if( (PLHashEntry *)NULL == he ) { + nss_SetError(NSS_ERROR_NO_MEMORY); + } else if (he->value != value) { + nss_SetError(NSS_ERROR_HASH_COLLISION); + } else { + hash->count++; + error = PR_SUCCESS; + } + + (void)PZ_Unlock(hash->mutex); + + return error; +} + +/* + * nssHash_Remove + * + */ +NSS_IMPLEMENT void +nssHash_Remove +( + nssHash *hash, + const void *it +) +{ + PRBool found; + + PZ_Lock(hash->mutex); + + found = PL_HashTableRemove(hash->plHashTable, it); + if( found ) { + hash->count--; + } + + (void)PZ_Unlock(hash->mutex); + return; +} + +/* + * nssHash_Count + * + */ +NSS_IMPLEMENT PRUint32 +nssHash_Count +( + nssHash *hash +) +{ + PRUint32 count; + + PZ_Lock(hash->mutex); + + count = hash->count; + + (void)PZ_Unlock(hash->mutex); + + return count; +} + +/* + * nssHash_Exists + * + */ +NSS_IMPLEMENT PRBool +nssHash_Exists +( + nssHash *hash, + const void *it +) +{ + void *value; + + PZ_Lock(hash->mutex); + + value = PL_HashTableLookup(hash->plHashTable, it); + + (void)PZ_Unlock(hash->mutex); + + if( (void *)NULL == value ) { + return PR_FALSE; + } else { + return PR_TRUE; + } +} + +/* + * nssHash_Lookup + * + */ +NSS_IMPLEMENT void * +nssHash_Lookup +( + nssHash *hash, + const void *it +) +{ + void *rv; + + PZ_Lock(hash->mutex); + + rv = PL_HashTableLookup(hash->plHashTable, it); + + (void)PZ_Unlock(hash->mutex); + + return rv; +} + +struct arg_str { + nssHashIterator fcn; + void *closure; +}; + +static PRIntn +nss_hash_enumerator +( + PLHashEntry *he, + PRIntn index, + void *arg +) +{ + struct arg_str *as = (struct arg_str *)arg; + as->fcn(he->key, he->value, as->closure); + return HT_ENUMERATE_NEXT; +} + +/* + * nssHash_Iterate + * + * NOTE that the iteration function will be called with the hashtable locked. + */ +NSS_IMPLEMENT void +nssHash_Iterate +( + nssHash *hash, + nssHashIterator fcn, + void *closure +) +{ + struct arg_str as; + as.fcn = fcn; + as.closure = closure; + + PZ_Lock(hash->mutex); + + PL_HashTableEnumerateEntries(hash->plHashTable, nss_hash_enumerator, &as); + + (void)PZ_Unlock(hash->mutex); + + return; +} diff --git a/security/nss/lib/base/hashops.c b/security/nss/lib/base/hashops.c new file mode 100644 index 000000000..031f92649 --- /dev/null +++ b/security/nss/lib/base/hashops.c @@ -0,0 +1,117 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#ifdef DEBUG +static const char CVS_ID[] = "@(#) $RCSfile$ $Revision$ $Date$ $Name$"; +#endif /* DEBUG */ + +/* + * hashops.c + * + * This file includes a set of PLHashAllocOps that use NSSArenas. + */ + +#ifndef BASE_H +#include "base.h" +#endif /* BASE_H */ + +static void * PR_CALLBACK +nss_arena_hash_alloc_table +( + void *pool, + PRSize size +) +{ + NSSArena *arena = (NSSArena *)NULL; + +#ifdef NSSDEBUG + if( (void *)NULL != arena ) { + if( PR_SUCCESS != nssArena_verifyPointer(arena) ) { + return (void *)NULL; + } + } +#endif /* NSSDEBUG */ + + return nss_ZAlloc(arena, size); +} + +static void PR_CALLBACK +nss_arena_hash_free_table +( + void *pool, + void *item +) +{ + (void)nss_ZFreeIf(item); +} + +static PLHashEntry * PR_CALLBACK +nss_arena_hash_alloc_entry +( + void *pool, + const void *key +) +{ + NSSArena *arena = NULL; + +#ifdef NSSDEBUG + if( (void *)NULL != arena ) { + if( PR_SUCCESS != nssArena_verifyPointer(arena) ) { + return (void *)NULL; + } + } +#endif /* NSSDEBUG */ + + return nss_ZNEW(arena, PLHashEntry); +} + +static void PR_CALLBACK +nss_arena_hash_free_entry +( + void *pool, + PLHashEntry *he, + PRUintn flag +) +{ + if( HT_FREE_ENTRY == flag ) { + (void)nss_ZFreeIf(he); + } +} + +NSS_IMPLEMENT_DATA PLHashAllocOps +nssArenaHashAllocOps = { + nss_arena_hash_alloc_table, + nss_arena_hash_free_table, + nss_arena_hash_alloc_entry, + nss_arena_hash_free_entry +}; diff --git a/security/nss/lib/base/item.c b/security/nss/lib/base/item.c new file mode 100644 index 000000000..efa9d1200 --- /dev/null +++ b/security/nss/lib/base/item.c @@ -0,0 +1,241 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#ifdef DEBUG +static const char CVS_ID[] = "@(#) $RCSfile$ $Revision$ $Date$ $Name$"; +#endif /* DEBUG */ + +/* + * item.c + * + * This contains some item-manipulation code. + */ + +#ifndef BASE_H +#include "base.h" +#endif /* BASE_H */ + +/* + * nssItem_Create + * + * -- fgmr comments -- + * + * The error may be one of the following values: + * NSS_ERROR_INVALID_ARENA + * NSS_ERROR_NO_MEMORY + * NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD + * NSS_ERROR_INVALID_POINTER + * + * Return value: + * A pointer to an NSSItem upon success + * NULL upon failure + */ + +NSS_IMPLEMENT NSSItem * +nssItem_Create +( + NSSArena *arenaOpt, + NSSItem *rvOpt, + PRUint32 length, + const void *data +) +{ + NSSItem *rv = (NSSItem *)NULL; + +#ifdef DEBUG + if( (NSSArena *)NULL != arenaOpt ) { + if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) { + return (NSSItem *)NULL; + } + } + + if( (const void *)NULL == data ) { + if( length > 0 ) { + nss_SetError(NSS_ERROR_INVALID_POINTER); + return (NSSItem *)NULL; + } + } +#endif /* DEBUG */ + + if( (NSSItem *)NULL == rvOpt ) { + rv = (NSSItem *)nss_ZNEW(arenaOpt, NSSItem); + if( (NSSItem *)NULL == rv ) { + goto loser; + } + } else { + rv = rvOpt; + } + + rv->size = length; + rv->data = nss_ZAlloc(arenaOpt, length); + if( (void *)NULL == rv->data ) { + goto loser; + } + + if( length > 0 ) { + (void)nsslibc_memcpy(rv->data, data, length); + } + + return rv; + + loser: + if( rv != rvOpt ) { + nss_ZFreeIf(rv); + } + + return (NSSItem *)NULL; +} + +NSS_IMPLEMENT void +nssItem_Destroy +( + NSSItem *item +) +{ + nss_ClearErrorStack(); + + nss_ZFreeIf(item->data); + nss_ZFreeIf(item); + +} + +/* + * nssItem_Duplicate + * + * -- fgmr comments -- + * + * The error may be one of the following values: + * NSS_ERROR_INVALID_ARENA + * NSS_ERROR_NO_MEMORY + * NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD + * NSS_ERROR_INVALID_ITEM + * + * Return value: + * A pointer to an NSSItem upon success + * NULL upon failure + */ + +NSS_IMPLEMENT NSSItem * +nssItem_Duplicate +( + NSSItem *obj, + NSSArena *arenaOpt, + NSSItem *rvOpt +) +{ +#ifdef DEBUG + if( (NSSArena *)NULL != arenaOpt ) { + if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) { + return (NSSItem *)NULL; + } + } + + if( (NSSItem *)NULL == obj ) { + nss_SetError(NSS_ERROR_INVALID_ITEM); + return (NSSItem *)NULL; + } +#endif /* DEBUG */ + + return nssItem_Create(arenaOpt, rvOpt, obj->size, obj->data); +} + +#ifdef DEBUG +/* + * nssItem_verifyPointer + * + * -- fgmr comments -- + * + * The error may be one of the following values: + * NSS_ERROR_INVALID_ITEM + * + * Return value: + * PR_SUCCESS upon success + * PR_FAILURE upon failure + */ + +NSS_IMPLEMENT PRStatus +nssItem_verifyPointer +( + const NSSItem *item +) +{ + if( ((const NSSItem *)NULL == item) || + (((void *)NULL == item->data) && (item->size > 0)) ) { + nss_SetError(NSS_ERROR_INVALID_ITEM); + return PR_FAILURE; + } + + return PR_SUCCESS; +} +#endif /* DEBUG */ + +/* + * nssItem_Equal + * + * -- fgmr comments -- + * + * The error may be one of the following values: + * NSS_ERROR_INVALID_ITEM + * + * Return value: + * PR_TRUE if the items are identical + * PR_FALSE if they aren't + * PR_FALSE upon error + */ + +NSS_IMPLEMENT PRBool +nssItem_Equal +( + const NSSItem *one, + const NSSItem *two, + PRStatus *statusOpt +) +{ + if( (PRStatus *)NULL != statusOpt ) { + *statusOpt = PR_SUCCESS; + } + + if( ((const NSSItem *)NULL == one) && ((const NSSItem *)NULL == two) ) { + return PR_TRUE; + } + + if( ((const NSSItem *)NULL == one) || ((const NSSItem *)NULL == two) ) { + return PR_FALSE; + } + + if( one->size != two->size ) { + return PR_FALSE; + } + + return nsslibc_memequal(one->data, two->data, one->size, statusOpt); +} diff --git a/security/nss/lib/base/libc.c b/security/nss/lib/base/libc.c new file mode 100644 index 000000000..68ab9d920 --- /dev/null +++ b/security/nss/lib/base/libc.c @@ -0,0 +1,197 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#ifdef DEBUG +static const char CVS_ID[] = "@(#) $RCSfile$ $Revision$ $Date$ $Name$"; +#endif /* DEBUG */ + +/* + * libc.c + * + * This file contains our wrappers/reimplementations for "standard" + * libc functions. Things like "memcpy." We add to this as we need + * it. Oh, and let's keep it in alphabetical order, should it ever + * get large. Most string/character stuff should be in utf8.c, not + * here. This file (and maybe utf8.c) should be the only ones in + * NSS to include files with angle brackets. + */ + +#ifndef BASE_H +#include "base.h" +#endif /* BASE_H */ + +#include <string.h> /* memcpy, memset */ + +/* + * nsslibc_memcpy + * nsslibc_memset + * nsslibc_offsetof + * nsslibc_memequal + */ + +/* + * nsslibc_memcpy + * + * Errors: + * NSS_ERROR_INVALID_POINTER + * + * Return value: + * NULL on error + * The destination pointer on success + */ + +NSS_IMPLEMENT void * +nsslibc_memcpy +( + void *dest, + const void *source, + PRUint32 n +) +{ +#ifdef NSSDEBUG + if( ((void *)NULL == dest) || ((const void *)NULL == source) ) { + nss_SetError(NSS_ERROR_INVALID_POINTER); + return (void *)NULL; + } +#endif /* NSSDEBUG */ + + return memcpy(dest, source, (size_t)n); +} + +/* + * nsslibc_memset + * + * Errors: + * NSS_ERROR_INVALID_POINTER + * + * Return value: + * NULL on error + * The destination pointer on success + */ + +NSS_IMPLEMENT void * +nsslibc_memset +( + void *dest, + PRUint8 byte, + PRUint32 n +) +{ +#ifdef NSSDEBUG + if( ((void *)NULL == dest) ) { + nss_SetError(NSS_ERROR_INVALID_POINTER); + return (void *)NULL; + } +#endif /* NSSDEBUG */ + + return memset(dest, (int)byte, (size_t)n); +} + +/* + * nsslibc_memequal + * + * Errors: + * NSS_ERROR_INVALID_POINTER + * + * Return value: + * PR_TRUE if they match + * PR_FALSE if they don't + * PR_FALSE upon error + */ + +NSS_IMPLEMENT PRBool +nsslibc_memequal +( + const void *a, + const void *b, + PRUint32 len, + PRStatus *statusOpt +) +{ +#ifdef NSSDEBUG + if( (((void *)NULL == a) || ((void *)NULL == b)) ) { + nss_SetError(NSS_ERROR_INVALID_POINTER); + if( (PRStatus *)NULL != statusOpt ) { + *statusOpt = PR_FAILURE; + } + return PR_FALSE; + } +#endif /* NSSDEBUG */ + + if( (PRStatus *)NULL != statusOpt ) { + *statusOpt = PR_SUCCESS; + } + + if( 0 == memcmp(a, b, len) ) { + return PR_TRUE; + } else { + return PR_FALSE; + } +} + +/* + * nsslibc_memcmp + */ + +NSS_IMPLEMENT PRInt32 +nsslibc_memcmp +( + const void *a, + const void *b, + PRUint32 len, + PRStatus *statusOpt +) +{ + int v; + +#ifdef NSSDEBUG + if( (((void *)NULL == a) || ((void *)NULL == b)) ) { + nss_SetError(NSS_ERROR_INVALID_POINTER); + if( (PRStatus *)NULL != statusOpt ) { + *statusOpt = PR_FAILURE; + } + return -2; + } +#endif /* NSSDEBUG */ + + if( (PRStatus *)NULL != statusOpt ) { + *statusOpt = PR_SUCCESS; + } + + v = memcmp(a, b, len); + return (PRInt32)v; +} + +/* + * offsetof is a preprocessor definition + */ diff --git a/security/nss/lib/base/list.c b/security/nss/lib/base/list.c new file mode 100644 index 000000000..ae601d50c --- /dev/null +++ b/security/nss/lib/base/list.c @@ -0,0 +1,433 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#ifdef DEBUG +static const char CVS_ID[] = "@(#) $RCSfile$ $Revision$ $Date$ $Name$"; +#endif /* DEBUG */ + +/* + * list.c + * + * This contains the implementation of NSS's thread-safe linked list. + */ + +#ifndef BASE_H +#include "base.h" +#endif /* BASE_H */ + +struct nssListElementStr { + PRCList link; + void *data; +}; + +typedef struct nssListElementStr nssListElement; + +struct nssListStr { + NSSArena *arena; + PZLock *lock; + nssListElement *head; + PRUint32 count; + nssListCompareFunc compareFunc; + nssListSortFunc sortFunc; + PRBool i_alloced_arena; +}; + +struct nssListIteratorStr { + PZLock *lock; + nssList *list; + nssListElement *current; +}; + +#define NSSLIST_LOCK_IF(list) \ + if ((list)->lock) PZ_Lock((list)->lock) + +#define NSSLIST_UNLOCK_IF(list) \ + if ((list)->lock) PZ_Unlock((list)->lock) + +static PRBool +pointer_compare(void *a, void *b) +{ + return (PRBool)(a == b); +} + +static nssListElement * +nsslist_get_matching_element(nssList *list, void *data) +{ + PRCList *link; + nssListElement *node; + node = list->head; + if (!node) { + return NULL; + } + link = &node->link; + while (node) { + /* using a callback slows things down when it's just compare ... */ + if (list->compareFunc(node->data, data)) { + break; + } + link = &node->link; + if (link == PR_LIST_TAIL(&list->head->link)) { + node = NULL; + break; + } + node = (nssListElement *)PR_NEXT_LINK(&node->link); + } + return node; +} + +NSS_IMPLEMENT nssList * +nssList_Create +( + NSSArena *arenaOpt, + PRBool threadSafe +) +{ + NSSArena *arena; + nssList *list; + PRBool i_alloced; + if (arenaOpt) { + arena = arenaOpt; + i_alloced = PR_FALSE; + } else { + arena = nssArena_Create(); + i_alloced = PR_TRUE; + } + if (!arena) { + return (nssList *)NULL; + } + list = nss_ZNEW(arena, nssList); + if (!list) { + if (!arenaOpt) { + NSSArena_Destroy(arena); + } + return (nssList *)NULL; + } + if (threadSafe) { + list->lock = PZ_NewLock(nssILockOther); + if (!list->lock) { + if (arenaOpt) { + nss_ZFreeIf(list); + } else { + NSSArena_Destroy(arena); + } + return (nssList *)NULL; + } + } + list->arena = arena; + list->i_alloced_arena = i_alloced; + list->compareFunc = pointer_compare; + return list; +} + +NSS_IMPLEMENT PRStatus +nssList_Destroy(nssList *list) +{ + if (!list->i_alloced_arena) { + nssList_Clear(list, NULL); + } + if (list->lock) { + (void)PZ_DestroyLock(list->lock); + } + if (list->i_alloced_arena) { + NSSArena_Destroy(list->arena); + list = NULL; + } + nss_ZFreeIf(list); + return PR_SUCCESS; +} + +NSS_IMPLEMENT void +nssList_SetCompareFunction(nssList *list, nssListCompareFunc compareFunc) +{ + list->compareFunc = compareFunc; +} + +NSS_IMPLEMENT void +nssList_SetSortFunction(nssList *list, nssListSortFunc sortFunc) +{ + /* XXX if list already has elements, sort them */ + list->sortFunc = sortFunc; +} + +NSS_IMPLEMENT nssListCompareFunc +nssList_GetCompareFunction(nssList *list) +{ + return list->compareFunc; +} + +NSS_IMPLEMENT void +nssList_Clear(nssList *list, nssListElementDestructorFunc destructor) +{ + PRCList *link; + nssListElement *node, *tmp; + NSSLIST_LOCK_IF(list); + node = list->head; + list->head = NULL; + while (node && list->count > 0) { + if (destructor) (*destructor)(node->data); + link = &node->link; + tmp = (nssListElement *)PR_NEXT_LINK(link); + PR_REMOVE_LINK(link); + nss_ZFreeIf(node); + node = tmp; + --list->count; + } + NSSLIST_UNLOCK_IF(list); +} + +static PRStatus +nsslist_add_element(nssList *list, void *data) +{ + nssListElement *node = nss_ZNEW(list->arena, nssListElement); + if (!node) { + return PR_FAILURE; + } + PR_INIT_CLIST(&node->link); + node->data = data; + if (list->head) { + if (list->sortFunc) { + PRCList *link; + nssListElement *currNode; + currNode = list->head; + /* insert in ordered list */ + while (currNode) { + link = &currNode->link; + if (list->sortFunc(data, currNode->data) <= 0) { + /* new element goes before current node */ + PR_INSERT_BEFORE(&node->link, link); + /* reset head if this is first */ + if (currNode == list->head) list->head = node; + break; + } + if (link == PR_LIST_TAIL(&list->head->link)) { + /* reached end of list, append */ + PR_INSERT_AFTER(&node->link, link); + break; + } + currNode = (nssListElement *)PR_NEXT_LINK(&currNode->link); + } + } else { + /* not sorting */ + PR_APPEND_LINK(&node->link, &list->head->link); + } + } else { + list->head = node; + } + ++list->count; + return PR_SUCCESS; +} + +NSS_IMPLEMENT PRStatus +nssList_Add(nssList *list, void *data) +{ + PRStatus nssrv; + NSSLIST_LOCK_IF(list); + nssrv = nsslist_add_element(list, data); + NSSLIST_UNLOCK_IF(list); + return PR_SUCCESS; +} + +NSS_IMPLEMENT PRStatus +nssList_AddUnique(nssList *list, void *data) +{ + PRStatus nssrv; + nssListElement *node; + NSSLIST_LOCK_IF(list); + node = nsslist_get_matching_element(list, data); + if (node) { + /* already in, finish */ + NSSLIST_UNLOCK_IF(list); + return PR_SUCCESS; + } + nssrv = nsslist_add_element(list, data); + NSSLIST_UNLOCK_IF(list); + return nssrv; +} + +NSS_IMPLEMENT PRStatus +nssList_Remove(nssList *list, void *data) +{ + nssListElement *node; + NSSLIST_LOCK_IF(list); + node = nsslist_get_matching_element(list, data); + if (node) { + if (node == list->head) { + list->head = (nssListElement *)PR_NEXT_LINK(&node->link); + } + PR_REMOVE_LINK(&node->link); + nss_ZFreeIf(node); + if (--list->count == 0) { + list->head = NULL; + } + } + NSSLIST_UNLOCK_IF(list); + return PR_SUCCESS; +} + +NSS_IMPLEMENT void * +nssList_Get(nssList *list, void *data) +{ + nssListElement *node; + NSSLIST_LOCK_IF(list); + node = nsslist_get_matching_element(list, data); + NSSLIST_UNLOCK_IF(list); + return (node) ? node->data : NULL; +} + +NSS_IMPLEMENT PRUint32 +nssList_Count(nssList *list) +{ + return list->count; +} + +NSS_IMPLEMENT PRStatus +nssList_GetArray(nssList *list, void **rvArray, PRUint32 maxElements) +{ + nssListElement *node; + PRUint32 i = 0; + PR_ASSERT(maxElements > 0); + node = list->head; + if (!node) { + return PR_SUCCESS; + } + NSSLIST_LOCK_IF(list); + while (node) { + rvArray[i++] = node->data; + if (i == maxElements) break; + node = (nssListElement *)PR_NEXT_LINK(&node->link); + if (node == list->head) { + break; + } + } + NSSLIST_UNLOCK_IF(list); + return PR_SUCCESS; +} + +NSS_IMPLEMENT nssList * +nssList_Clone(nssList *list) +{ + nssList *rvList; + nssListElement *node; + rvList = nssList_Create(NULL, (list->lock != NULL)); + if (!rvList) { + return NULL; + } + NSSLIST_LOCK_IF(list); + if (list->count > 0) { + node = list->head; + while (PR_TRUE) { + nssList_Add(rvList, node->data); + node = (nssListElement *)PR_NEXT_LINK(&node->link); + if (node == list->head) { + break; + } + } + } + NSSLIST_UNLOCK_IF(list); + return rvList; +} + +NSS_IMPLEMENT nssListIterator * +nssList_CreateIterator(nssList *list) +{ + nssListIterator *rvIterator; + rvIterator = nss_ZNEW(NULL, nssListIterator); + if (!rvIterator) { + return NULL; + } + rvIterator->list = nssList_Clone(list); + if (!rvIterator->list) { + nss_ZFreeIf(rvIterator); + return NULL; + } + rvIterator->current = rvIterator->list->head; + if (list->lock) { + rvIterator->lock = PZ_NewLock(nssILockOther); + if (!rvIterator->lock) { + nssList_Destroy(rvIterator->list); + nss_ZFreeIf(rvIterator); + } + } + return rvIterator; +} + +NSS_IMPLEMENT void +nssListIterator_Destroy(nssListIterator *iter) +{ + if (iter->lock) { + (void)PZ_DestroyLock(iter->lock); + } + nssList_Destroy(iter->list); + nss_ZFreeIf(iter); +} + +NSS_IMPLEMENT void * +nssListIterator_Start(nssListIterator *iter) +{ + NSSLIST_LOCK_IF(iter); + if (iter->list->count == 0) { + return NULL; + } + iter->current = iter->list->head; + return iter->current->data; +} + +NSS_IMPLEMENT void * +nssListIterator_Next(nssListIterator *iter) +{ + nssListElement *node; + PRCList *link; + if (iter->list->count == 1 || iter->current == NULL) { + /* Reached the end of the list. Don't change the state, force to + * user to call nssList_Finish to clean up. + */ + return NULL; + } + node = (nssListElement *)PR_NEXT_LINK(&iter->current->link); + link = &node->link; + if (link == PR_LIST_TAIL(&iter->list->head->link)) { + /* Signal the end of the list. */ + iter->current = NULL; + return node->data; + } + iter->current = node; + return node->data; +} + +NSS_IMPLEMENT PRStatus +nssListIterator_Finish(nssListIterator *iter) +{ + iter->current = iter->list->head; + return (iter->lock) ? PZ_Unlock(iter->lock) : PR_SUCCESS; +} + diff --git a/security/nss/lib/base/manifest.mn b/security/nss/lib/base/manifest.mn new file mode 100644 index 000000000..13cf9447b --- /dev/null +++ b/security/nss/lib/base/manifest.mn @@ -0,0 +1,65 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code is the Netscape security libraries. +# +# The Initial Developer of the Original Code is Netscape +# Communications Corporation. Portions created by Netscape are +# Copyright (C) 1994-2000 Netscape Communications Corporation. All +# Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the +# terms of the GNU General Public License Version 2 or later (the +# "GPL"), in which case the provisions of the GPL are applicable +# instead of those above. If you wish to allow use of your +# version of this file only under the terms of the GPL and not to +# allow others to use your version of this file under the MPL, +# indicate your decision by deleting the provisions above and +# replace them with the notice and other provisions required by +# the GPL. If you do not delete the provisions above, a recipient +# may use your version of this file under either the MPL or the +# GPL. +# +MANIFEST_CVS_ID = "@(#) $RCSfile$ $Revision$ $Date$ $Name$" + +CORE_DEPTH = ../../.. + +PRIVATE_EXPORTS = \ + baset.h \ + base.h \ + $(NULL) + +EXPORTS = \ + nssbaset.h \ + nssbase.h \ + $(NULL) + +MODULE = security + +CSRCS = \ + arena.c \ + error.c \ + errorval.c \ + hashops.c \ + libc.c \ + tracker.c \ + item.c \ + utf8.c \ + list.c \ + hash.c \ + whatnspr.c \ + $(NULL) + +REQUIRES = security nspr + +LIBRARY_NAME = nssb diff --git a/security/nss/lib/base/nssbase.h b/security/nss/lib/base/nssbase.h new file mode 100644 index 000000000..3960a7810 --- /dev/null +++ b/security/nss/lib/base/nssbase.h @@ -0,0 +1,167 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#ifndef NSSBASE_H +#define NSSBASE_H + +#ifdef DEBUG +static const char NSSBASE_CVS_ID[] = "@(#) $RCSfile$ $Revision$ $Date$ $Name$"; +#endif /* DEBUG */ + +/* + * nssbase.h + * + * This header file contains the prototypes of the basic public + * NSS routines. + */ + +#ifndef NSSBASET_H +#include "nssbaset.h" +#endif /* NSSBASET_H */ + +PR_BEGIN_EXTERN_C + +/* + * NSSArena + * + * The public methods relating to this type are: + * + * NSSArena_Create -- constructor + * NSSArena_Destroy + */ + +/* + * NSSArena_Create + * + * This routine creates a new memory arena. This routine may return + * NULL upon error, in which case it will have created an error stack. + * + * The top-level error may be one of the following values: + * NSS_ERROR_NO_MEMORY + * + * Return value: + * NULL upon error + * A pointer to an NSSArena upon success + */ + +NSS_EXTERN NSSArena * +NSSArena_Create +( + void +); + +extern const NSSError NSS_ERROR_NO_MEMORY; + +/* + * NSSArena_Destroy + * + * This routine will destroy the specified arena, freeing all memory + * allocated from it. This routine returns a PRStatus value; if + * successful, it will return PR_SUCCESS. If unsuccessful, it will + * create an error stack and return PR_FAILURE. + * + * The top-level error may be one of the following values: + * NSS_ERROR_INVALID_ARENA + * + * Return value: + * PR_SUCCESS upon success + * PR_FAILURE upon failure + */ + +NSS_EXTERN PRStatus +NSSArena_Destroy +( + NSSArena *arena +); + +extern const NSSError NSS_ERROR_INVALID_ARENA; + +/* + * The error stack + * + * The public methods relating to the error stack are: + * + * NSS_GetError + * NSS_GetErrorStack + */ + +/* + * NSS_GetError + * + * This routine returns the highest-level (most general) error set + * by the most recent NSS library routine called by the same thread + * calling this routine. + * + * This routine cannot fail. It may return NSS_ERROR_NO_ERROR, which + * indicates that the previous NSS library call did not set an error. + * + * Return value: + * 0 if no error has been set + * A nonzero error number + */ + +NSS_EXTERN NSSError +NSS_GetError +( + void +); + +extern const NSSError NSS_ERROR_NO_ERROR; + +/* + * NSS_GetErrorStack + * + * This routine returns a pointer to an array of NSSError values, + * containingthe entire sequence or "stack" of errors set by the most + * recent NSS library routine called by the same thread calling this + * routine. NOTE: the caller DOES NOT OWN the memory pointed to by + * the return value. The pointer will remain valid until the calling + * thread calls another NSS routine. The lowest-level (most specific) + * error is first in the array, and the highest-level is last. The + * array is zero-terminated. This routine may return NULL upon error; + * this indicates a low-memory situation. + * + * Return value: + * NULL upon error, which is an implied NSS_ERROR_NO_MEMORY + * A NON-caller-owned pointer to an array of NSSError values + */ + +NSS_EXTERN NSSError * +NSS_GetErrorStack +( + void +); + +PR_END_EXTERN_C + +#endif /* NSSBASE_H */ diff --git a/security/nss/lib/base/nssbaset.h b/security/nss/lib/base/nssbaset.h new file mode 100644 index 000000000..c3e84c46e --- /dev/null +++ b/security/nss/lib/base/nssbaset.h @@ -0,0 +1,153 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#ifndef NSSBASET_H +#define NSSBASET_H + +#ifdef DEBUG +static const char NSSBASET_CVS_ID[] = "@(#) $RCSfile$ $Revision$ $Date$ $Name$"; +#endif /* DEBUG */ + +/* + * nssbaset.h + * + * This file contains the most low-level, fundamental public types. + */ + +#include "nspr.h" +#include "nssilock.h" + +/* + * NSS_EXTERN, NSS_IMPLEMENT, NSS_EXTERN_DATA, NSS_IMPLEMENT_DATA + * + * NSS has its own versions of these NSPR macros, in a form which + * does not confuse ctags and other related utilities. NSPR + * defines these macros to take the type as an argument, because + * of a requirement to support win16 dlls. We do not have that + * requirement, so we can drop that restriction. + */ + +#define DUMMY /* dummy */ +#define NSS_EXTERN PR_EXTERN(DUMMY) +#define NSS_IMPLEMENT PR_IMPLEMENT(DUMMY) +#define NSS_EXTERN_DATA PR_EXTERN_DATA(DUMMY) +#define NSS_IMPLEMENT_DATA PR_IMPLEMENT_DATA(DUMMY) + +PR_BEGIN_EXTERN_C + +/* + * NSSError + * + * Calls to NSS routines may result in one or more errors being placed + * on the calling thread's "error stack." Every possible error that + * may be returned from a function is declared where the function is + * prototyped. All errors are of the following type. + */ + +typedef PRInt32 NSSError; + +/* + * NSSArena + * + * Arenas are logical sets of heap memory, from which memory may be + * allocated. When an arena is destroyed, all memory allocated within + * that arena is implicitly freed. These arenas are thread-safe: + * an arena pointer may be used by multiple threads simultaneously. + * However, as they are not backed by shared memory, they may only be + * used within one process. + */ + +struct NSSArenaStr; +typedef struct NSSArenaStr NSSArena; + +/* + * NSSItem + * + * This is the basic type used to refer to an unconstrained datum of + * arbitrary size. + */ + +struct NSSItemStr { + void *data; + PRUint32 size; +}; +typedef struct NSSItemStr NSSItem; + + +/* + * NSSBER + * + * Data packed according to the Basic Encoding Rules of ASN.1. + */ + +typedef NSSItem NSSBER; + +/* + * NSSDER + * + * Data packed according to the Distinguished Encoding Rules of ASN.1; + * this form is also known as the Canonical Encoding Rules form (CER). + */ + +typedef NSSBER NSSDER; + +/* + * NSSBitString + * + * Some ASN.1 types use "bit strings," which are passed around as + * octet strings but whose length is counted in bits. We use this + * typedef of NSSItem to point out the occasions when the length + * is counted in bits, not octets. + */ + +typedef NSSItem NSSBitString; + +/* + * NSSUTF8 + * + * Character strings encoded in UTF-8, as defined by RFC 2279. + */ + +typedef char NSSUTF8; + +/* + * NSSASCII7 + * + * Character strings guaranteed to be 7-bit ASCII. + */ + +typedef char NSSASCII7; + +PR_END_EXTERN_C + +#endif /* NSSBASET_H */ diff --git a/security/nss/lib/base/tracker.c b/security/nss/lib/base/tracker.c new file mode 100644 index 000000000..5be77b7cf --- /dev/null +++ b/security/nss/lib/base/tracker.c @@ -0,0 +1,543 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#ifdef DEBUG +static const char CVS_ID[] = "@(#) $RCSfile$ $Revision$ $Date$ $Name$"; +#endif /* DEBUG */ + +/* + * tracker.c + * + * This file contains the code used by the pointer-tracking calls used + * in the debug builds to catch bad pointers. The entire contents are + * only available in debug builds (both internal and external builds). + */ + +#ifndef BASE_H +#include "base.h" +#endif /* BASE_H */ + +#ifdef DEBUG + +/* + * call_once + * + * Unfortunately, NSPR's PR_CallOnce function doesn't accept a closure + * variable. So I have a static version here which does. This code + * is based on NSPR's, and uses the NSPR function to initialize the + * required lock. + */ + +/* + * The is the "once block" that's passed to the "real" PR_CallOnce + * function, to call the local initializer myOnceFunction once. + */ +static PRCallOnceType myCallOnce; + +/* + * This structure is used by the call_once function to make sure that + * any "other" threads calling the call_once don't return too quickly, + * before the initializer has finished. + */ +static struct { + PZLock *ml; + PZCondVar *cv; +} mod_init; + +/* + * This is the initializer for the above mod_init structure. + */ +static PRStatus +myOnceFunction +( + void +) +{ + mod_init.ml = PZ_NewLock(nssILockOther); + if( (PZLock *)NULL == mod_init.ml ) { + return PR_FAILURE; + } + + mod_init.cv = PZ_NewCondVar(mod_init.ml); + if( (PZCondVar *)NULL == mod_init.cv ) { + PZ_DestroyLock(mod_init.ml); + mod_init.ml = (PZLock *)NULL; + return PR_FAILURE; + } + + return PR_SUCCESS; +} + +/* + * The nss call_once callback takes a closure argument. + */ +typedef PRStatus (PR_CALLBACK *nssCallOnceFN)(void *arg); + +/* + * NSS's call_once function. + */ +static PRStatus +call_once +( + PRCallOnceType *once, + nssCallOnceFN func, + void *arg +) +{ + PRStatus rv; + + if( !myCallOnce.initialized ) { + rv = PR_CallOnce(&myCallOnce, myOnceFunction); + if( PR_SUCCESS != rv ) { + return rv; + } + } + + if( !once->initialized ) { + if( 0 == PR_AtomicSet(&once->inProgress, 1) ) { + once->status = (*func)(arg); + PZ_Lock(mod_init.ml); + once->initialized = 1; + PZ_NotifyAllCondVar(mod_init.cv); + PZ_Unlock(mod_init.ml); + } else { + PZ_Lock(mod_init.ml); + while( !once->initialized ) { + PZ_WaitCondVar(mod_init.cv, PR_INTERVAL_NO_TIMEOUT); + } + PZ_Unlock(mod_init.ml); + } + } + + return once->status; +} + +/* + * Now we actually get to my own "call once" payload function. + * But wait, to create the hash, I need a hash function! + */ + +/* + * identity_hash + * + * This static callback is a PLHashFunction as defined in plhash.h + * It merely returns the value of the object pointer as its hash. + * There are no possible errors. + */ + +static PLHashNumber PR_CALLBACK +identity_hash +( + const void *key +) +{ + return (PLHashNumber)key; +} + +/* + * trackerOnceFunc + * + * This function is called once, using the nssCallOnce function above. + * It creates a new pointer tracker object; initialising its hash + * table and protective lock. + */ + +static PRStatus +trackerOnceFunc +( + void *arg +) +{ + nssPointerTracker *tracker = (nssPointerTracker *)arg; + + tracker->lock = PZ_NewLock(nssILockOther); + if( (PZLock *)NULL == tracker->lock ) { + return PR_FAILURE; + } + + tracker->table = PL_NewHashTable(0, + identity_hash, + PL_CompareValues, + PL_CompareValues, + (PLHashAllocOps *)NULL, + (void *)NULL); + if( (PLHashTable *)NULL == tracker->table ) { + PZ_DestroyLock(tracker->lock); + tracker->lock = (PZLock *)NULL; + return PR_FAILURE; + } + + return PR_SUCCESS; +} + +/* + * nssPointerTracker_initialize + * + * This method is only present in debug builds. + * + * This routine initializes an nssPointerTracker object. Note that + * the object must have been declared *static* to guarantee that it + * is in a zeroed state initially. This routine is idempotent, and + * may even be safely called by multiple threads simultaneously with + * the same argument. This routine returns a PRStatus value; if + * successful, it will return PR_SUCCESS. On failure it will set an + * error on the error stack and return PR_FAILURE. + * + * The error may be one of the following values: + * NSS_ERROR_NO_MEMORY + * + * Return value: + * PR_SUCCESS + * PR_FAILURE + */ + +NSS_IMPLEMENT PRStatus +nssPointerTracker_initialize +( + nssPointerTracker *tracker +) +{ + PRStatus rv = call_once(&tracker->once, trackerOnceFunc, tracker); + if( PR_SUCCESS != rv ) { + nss_SetError(NSS_ERROR_NO_MEMORY); + } + + return rv; +} + +#ifdef DONT_DESTROY_EMPTY_TABLES +/* See same #ifdef below */ +/* + * count_entries + * + * This static routine is a PLHashEnumerator, as defined in plhash.h. + * It merely causes the enumeration function to count the number of + * entries. + */ + +static PRIntn PR_CALLBACK +count_entries +( + PLHashEntry *he, + PRIntn index, + void *arg +) +{ + return HT_ENUMERATE_NEXT; +} +#endif /* DONT_DESTROY_EMPTY_TABLES */ + +/* + * zero_once + * + * This is a guaranteed zeroed once block. It's used to help clear + * the tracker. + */ + +static const PRCallOnceType zero_once; + +/* + * nssPointerTracker_finalize + * + * This method is only present in debug builds. + * + * This routine returns the nssPointerTracker object to the pre- + * initialized state, releasing all resources used by the object. + * It will *NOT* destroy the objects being tracked by the pointer + * (should any remain), and therefore cannot be used to "sweep up" + * remaining objects. This routine returns a PRStatus value; if + * successful, it will return PR_SUCCES. On failure it will set an + * error on the error stack and return PR_FAILURE. If any objects + * remain in the tracker when it is finalized, that will be treated + * as an error. + * + * The error may be one of the following values: + * NSS_ERROR_INVALID_POINTER + * NSS_ERROR_TRACKER_NOT_INITIALIZED + * NSS_ERROR_TRACKER_NOT_EMPTY + * + * Return value: + * PR_SUCCESS + * PR_FAILURE + */ + +NSS_IMPLEMENT PRStatus +nssPointerTracker_finalize +( + nssPointerTracker *tracker +) +{ + PZLock *lock; + + if( (nssPointerTracker *)NULL == tracker ) { + nss_SetError(NSS_ERROR_INVALID_POINTER); + return PR_FAILURE; + } + + if( (PZLock *)NULL == tracker->lock ) { + nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED); + return PR_FAILURE; + } + + lock = tracker->lock; + PZ_Lock(lock); + + if( (PLHashTable *)NULL == tracker->table ) { + PZ_Unlock(lock); + nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED); + return PR_FAILURE; + } + +#ifdef DONT_DESTROY_EMPTY_TABLES + /* + * I changed my mind; I think we don't want this after all. + * Comments? + */ + count = PL_HashTableEnumerateEntries(tracker->table, + count_entries, + (void *)NULL); + + if( 0 != count ) { + PZ_Unlock(lock); + nss_SetError(NSS_ERROR_TRACKER_NOT_EMPTY); + return PR_FAILURE; + } +#endif /* DONT_DESTROY_EMPTY_TABLES */ + + PL_HashTableDestroy(tracker->table); + /* memset(tracker, 0, sizeof(nssPointerTracker)); */ + tracker->once = zero_once; + tracker->lock = (PZLock *)NULL; + tracker->table = (PLHashTable *)NULL; + + PZ_Unlock(lock); + PZ_DestroyLock(lock); + + return PR_SUCCESS; +} + +/* + * nssPointerTracker_add + * + * This method is only present in debug builds. + * + * This routine adds the specified pointer to the nssPointerTracker + * object. It should be called in constructor objects to register + * new valid objects. The nssPointerTracker is threadsafe, but this + * call is not idempotent. This routine returns a PRStatus value; + * if successful it will return PR_SUCCESS. On failure it will set + * an error on the error stack and return PR_FAILURE. + * + * The error may be one of the following values: + * NSS_ERROR_INVALID_POINTER + * NSS_ERROR_NO_MEMORY + * NSS_ERROR_TRACKER_NOT_INITIALIZED + * NSS_ERROR_DUPLICATE_POINTER + * + * Return value: + * PR_SUCCESS + * PR_FAILURE + */ + +NSS_IMPLEMENT PRStatus +nssPointerTracker_add +( + nssPointerTracker *tracker, + const void *pointer +) +{ + void *check; + PLHashEntry *entry; + + if( (nssPointerTracker *)NULL == tracker ) { + nss_SetError(NSS_ERROR_INVALID_POINTER); + return PR_FAILURE; + } + + if( (PZLock *)NULL == tracker->lock ) { + nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED); + return PR_FAILURE; + } + + PZ_Lock(tracker->lock); + + if( (PLHashTable *)NULL == tracker->table ) { + PZ_Unlock(tracker->lock); + nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED); + return PR_FAILURE; + } + + check = PL_HashTableLookup(tracker->table, pointer); + if( (void *)NULL != check ) { + PZ_Unlock(tracker->lock); + nss_SetError(NSS_ERROR_DUPLICATE_POINTER); + return PR_FAILURE; + } + + entry = PL_HashTableAdd(tracker->table, pointer, (void *)pointer); + + PZ_Unlock(tracker->lock); + + if( (PLHashEntry *)NULL == entry ) { + nss_SetError(NSS_ERROR_NO_MEMORY); + return PR_FAILURE; + } + + return PR_SUCCESS; +} + +/* + * nssPointerTracker_remove + * + * This method is only present in debug builds. + * + * This routine removes the specified pointer from the + * nssPointerTracker object. It does not call any destructor for the + * object; rather, this should be called from the object's destructor. + * The nssPointerTracker is threadsafe, but this call is not + * idempotent. This routine returns a PRStatus value; if successful + * it will return PR_SUCCESS. On failure it will set an error on the + * error stack and return PR_FAILURE. + * + * The error may be one of the following values: + * NSS_ERROR_INVALID_POINTER + * NSS_ERROR_TRACKER_NOT_INITIALIZED + * NSS_ERROR_POINTER_NOT_REGISTERED + * + * Return value: + * PR_SUCCESS + * PR_FAILURE + */ + +NSS_IMPLEMENT PRStatus +nssPointerTracker_remove +( + nssPointerTracker *tracker, + const void *pointer +) +{ + PRBool registered; + + if( (nssPointerTracker *)NULL == tracker ) { + nss_SetError(NSS_ERROR_INVALID_POINTER); + return PR_FAILURE; + } + + if( (PZLock *)NULL == tracker->lock ) { + nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED); + return PR_FAILURE; + } + + PZ_Lock(tracker->lock); + + if( (PLHashTable *)NULL == tracker->table ) { + PZ_Unlock(tracker->lock); + nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED); + return PR_FAILURE; + } + + registered = PL_HashTableRemove(tracker->table, pointer); + PZ_Unlock(tracker->lock); + + if( !registered ) { + nss_SetError(NSS_ERROR_POINTER_NOT_REGISTERED); + return PR_FAILURE; + } + + return PR_SUCCESS; +} + +/* + * nssPointerTracker_verify + * + * This method is only present in debug builds. + * + * This routine verifies that the specified pointer has been registered + * with the nssPointerTracker object. The nssPointerTracker object is + * threadsafe, and this call may be safely called from multiple threads + * simultaneously with the same arguments. This routine returns a + * PRStatus value; if the pointer is registered this will return + * PR_SUCCESS. Otherwise it will set an error on the error stack and + * return PR_FAILURE. Although the error is suitable for leaving on + * the stack, callers may wish to augment the information available by + * placing a more type-specific error on the stack. + * + * The error may be one of the following values: + * NSS_ERROR_INVALID_POINTER + * NSS_ERROR_TRACKER_NOT_INITIALIZED + * NSS_ERROR_POINTER_NOT_REGISTERED + * + * Return value: + * PR_SUCCESS + * PR_FAILRUE + */ + +NSS_IMPLEMENT PRStatus +nssPointerTracker_verify +( + nssPointerTracker *tracker, + const void *pointer +) +{ + void *check; + + if( (nssPointerTracker *)NULL == tracker ) { + nss_SetError(NSS_ERROR_INVALID_POINTER); + return PR_FAILURE; + } + + if( (PZLock *)NULL == tracker->lock ) { + nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED); + return PR_FAILURE; + } + + PZ_Lock(tracker->lock); + + if( (PLHashTable *)NULL == tracker->table ) { + PZ_Unlock(tracker->lock); + nss_SetError(NSS_ERROR_TRACKER_NOT_INITIALIZED); + return PR_FAILURE; + } + + check = PL_HashTableLookup(tracker->table, pointer); + PZ_Unlock(tracker->lock); + + if( (void *)NULL == check ) { + nss_SetError(NSS_ERROR_POINTER_NOT_REGISTERED); + return PR_FAILURE; + } + + return PR_SUCCESS; +} + +#endif /* DEBUG */ diff --git a/security/nss/lib/base/utf8.c b/security/nss/lib/base/utf8.c new file mode 100644 index 000000000..3a8641f95 --- /dev/null +++ b/security/nss/lib/base/utf8.c @@ -0,0 +1,759 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#ifdef DEBUG +static const char CVS_ID[] = "@(#) $RCSfile$ $Revision$ $Date$ $Name$"; +#endif /* DEBUG */ + +/* + * utf8.c + * + * This file contains some additional utility routines required for + * handling UTF8 strings. + */ + +#ifndef BASE_H +#include "base.h" +#endif /* BASE_H */ + +#include "plstr.h" + +/* + * NOTES: + * + * There's an "is hex string" function in pki1/atav.c. If we need + * it in more places, pull that one out. + */ + +/* + * nssUTF8_CaseIgnoreMatch + * + * Returns true if the two UTF8-encoded strings pointed to by the + * two specified NSSUTF8 pointers differ only in typcase. + * + * The error may be one of the following values: + * NSS_ERROR_INVALID_POINTER + * + * Return value: + * PR_TRUE if the strings match, ignoring case + * PR_FALSE if they don't + * PR_FALSE upon error + */ + +NSS_IMPLEMENT PRBool +nssUTF8_CaseIgnoreMatch +( + const NSSUTF8 *a, + const NSSUTF8 *b, + PRStatus *statusOpt +) +{ +#ifdef NSSDEBUG + if( ((const NSSUTF8 *)NULL == a) || + ((const NSSUTF8 *)NULL == b) ) { + nss_SetError(NSS_ERROR_INVALID_POINTER); + if( (PRStatus *)NULL != statusOpt ) { + *statusOpt = PR_FAILURE; + } + return PR_FALSE; + } +#endif /* NSSDEBUG */ + + if( (PRStatus *)NULL != statusOpt ) { + *statusOpt = PR_SUCCESS; + } + + /* + * XXX fgmr + * + * This is, like, so wrong! + */ + if( 0 == PL_strcasecmp((const char *)a, (const char *)b) ) { + return PR_TRUE; + } else { + return PR_FALSE; + } +} + +/* + * nssUTF8_PrintableMatch + * + * Returns true if the two Printable strings pointed to by the + * two specified NSSUTF8 pointers match when compared with the + * rules for Printable String (leading and trailing spaces are + * disregarded, extents of whitespace match irregardless of length, + * and case is not significant), then PR_TRUE will be returned. + * Otherwise, PR_FALSE will be returned. Upon failure, PR_FALSE + * will be returned. If the optional statusOpt argument is not + * NULL, then PR_SUCCESS or PR_FAILURE will be stored in that + * location. + * + * The error may be one of the following values: + * NSS_ERROR_INVALID_POINTER + * + * Return value: + * PR_TRUE if the strings match, ignoring case + * PR_FALSE if they don't + * PR_FALSE upon error + */ + +NSS_IMPLEMENT PRBool +nssUTF8_PrintableMatch +( + const NSSUTF8 *a, + const NSSUTF8 *b, + PRStatus *statusOpt +) +{ + PRUint8 *c; + PRUint8 *d; + +#ifdef NSSDEBUG + if( ((const NSSUTF8 *)NULL == a) || + ((const NSSUTF8 *)NULL == b) ) { + nss_SetError(NSS_ERROR_INVALID_POINTER); + if( (PRStatus *)NULL != statusOpt ) { + *statusOpt = PR_FAILURE; + } + return PR_FALSE; + } +#endif /* NSSDEBUG */ + + if( (PRStatus *)NULL != statusOpt ) { + *statusOpt = PR_SUCCESS; + } + + c = (PRUint8 *)a; + d = (PRUint8 *)b; + + while( ' ' == *c ) { + c++; + } + + while( ' ' == *d ) { + d++; + } + + while( ('\0' != *c) && ('\0' != *d) ) { + PRUint8 e, f; + + e = *c; + f = *d; + + if( ('a' <= e) && (e <= 'z') ) { + e -= ('a' - 'A'); + } + + if( ('a' <= f) && (f <= 'z') ) { + f -= ('a' - 'A'); + } + + if( e != f ) { + return PR_FALSE; + } + + c++; + d++; + + if( ' ' == *c ) { + while( ' ' == *c ) { + c++; + } + c--; + } + + if( ' ' == *d ) { + while( ' ' == *d ) { + d++; + } + d--; + } + } + + while( ' ' == *c ) { + c++; + } + + while( ' ' == *d ) { + d++; + } + + if( *c == *d ) { + /* And both '\0', btw */ + return PR_TRUE; + } else { + return PR_FALSE; + } +} + +/* + * nssUTF8_Duplicate + * + * This routine duplicates the UTF8-encoded string pointed to by the + * specified NSSUTF8 pointer. If the optional arenaOpt argument is + * not null, the memory required will be obtained from that arena; + * otherwise, the memory required will be obtained from the heap. + * A pointer to the new string will be returned. In case of error, + * an error will be placed on the error stack and NULL will be + * returned. + * + * The error may be one of the following values: + * NSS_ERROR_INVALID_POINTER + * NSS_ERROR_INVALID_ARENA + * NSS_ERROR_NO_MEMORY + */ + +NSS_IMPLEMENT NSSUTF8 * +nssUTF8_Duplicate +( + const NSSUTF8 *s, + NSSArena *arenaOpt +) +{ + NSSUTF8 *rv; + PRUint32 len; + +#ifdef NSSDEBUG + if( (const NSSUTF8 *)NULL == s ) { + nss_SetError(NSS_ERROR_INVALID_POINTER); + return (NSSUTF8 *)NULL; + } + + if( (NSSArena *)NULL != arenaOpt ) { + if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) { + return (NSSUTF8 *)NULL; + } + } +#endif /* NSSDEBUG */ + + len = PL_strlen((const char *)s); +#ifdef PEDANTIC + if( '\0' != ((const char *)s)[ len ] ) { + /* must have wrapped, e.g., too big for PRUint32 */ + nss_SetError(NSS_ERROR_NO_MEMORY); + return (NSSUTF8 *)NULL; + } +#endif /* PEDANTIC */ + len++; /* zero termination */ + + rv = nss_ZAlloc(arenaOpt, len); + if( (void *)NULL == rv ) { + return (NSSUTF8 *)NULL; + } + + (void)nsslibc_memcpy(rv, s, len); + return rv; +} + +/* + * nssUTF8_Size + * + * This routine returns the length in bytes (including the terminating + * null) of the UTF8-encoded string pointed to by the specified + * NSSUTF8 pointer. Zero is returned on error. + * + * The error may be one of the following values: + * NSS_ERROR_INVALID_POINTER + * NSS_ERROR_VALUE_TOO_LARGE + * + * Return value: + * 0 on error + * nonzero length of the string. + */ + +NSS_IMPLEMENT PRUint32 +nssUTF8_Size +( + const NSSUTF8 *s, + PRStatus *statusOpt +) +{ + PRUint32 sv; + +#ifdef NSSDEBUG + if( (const NSSUTF8 *)NULL == s ) { + nss_SetError(NSS_ERROR_INVALID_POINTER); + if( (PRStatus *)NULL != statusOpt ) { + *statusOpt = PR_FAILURE; + } + return 0; + } +#endif /* NSSDEBUG */ + + sv = PL_strlen((const char *)s) + 1; +#ifdef PEDANTIC + if( '\0' != ((const char *)s)[ sv-1 ] ) { + /* wrapped */ + nss_SetError(NSS_ERROR_VALUE_TOO_LARGE); + if( (PRStatus *)NULL != statusOpt ) { + *statusOpt = PR_FAILURE; + } + return 0; + } +#endif /* PEDANTIC */ + + if( (PRStatus *)NULL != statusOpt ) { + *statusOpt = PR_SUCCESS; + } + + return sv; +} + +/* + * nssUTF8_Length + * + * This routine returns the length in characters (not including the + * terminating null) of the UTF8-encoded string pointed to by the + * specified NSSUTF8 pointer. + * + * The error may be one of the following values: + * NSS_ERROR_INVALID_POINTER + * NSS_ERROR_VALUE_TOO_LARGE + * NSS_ERROR_INVALID_STRING + * + * Return value: + * length of the string (which may be zero) + * 0 on error + */ + +NSS_IMPLEMENT PRUint32 +nssUTF8_Length +( + const NSSUTF8 *s, + PRStatus *statusOpt +) +{ + PRUint32 l = 0; + const PRUint8 *c = (const PRUint8 *)s; + +#ifdef NSSDEBUG + if( (const NSSUTF8 *)NULL == s ) { + nss_SetError(NSS_ERROR_INVALID_POINTER); + goto loser; + } +#endif /* NSSDEBUG */ + + /* + * From RFC 2044: + * + * UCS-4 range (hex.) UTF-8 octet sequence (binary) + * 0000 0000-0000 007F 0xxxxxxx + * 0000 0080-0000 07FF 110xxxxx 10xxxxxx + * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx + * 0001 0000-001F FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + * 0020 0000-03FF FFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + * 0400 0000-7FFF FFFF 1111110x 10xxxxxx ... 10xxxxxx + */ + + while( 0 != *c ) { + PRUint32 incr; + if( (*c & 0x80) == 0 ) { + incr = 1; + } else if( (*c & 0xE0) == 0xC0 ) { + incr = 2; + } else if( (*c & 0xF0) == 0xE0 ) { + incr = 3; + } else if( (*c & 0xF8) == 0xF0 ) { + incr = 4; + } else if( (*c & 0xFC) == 0xF8 ) { + incr = 5; + } else if( (*c & 0xFE) == 0xFC ) { + incr = 6; + } else { + nss_SetError(NSS_ERROR_INVALID_STRING); + goto loser; + } + + l += incr; + +#ifdef PEDANTIC + if( l < incr ) { + /* Wrapped-- too big */ + nss_SetError(NSS_ERROR_VALUE_TOO_LARGE); + goto loser; + } + + { + PRUint8 *d; + for( d = &c[1]; d < &c[incr]; d++ ) { + if( (*d & 0xC0) != 0xF0 ) { + nss_SetError(NSS_ERROR_INVALID_STRING); + goto loser; + } + } + } +#endif /* PEDANTIC */ + + c += incr; + } + + if( (PRStatus *)NULL != statusOpt ) { + *statusOpt = PR_SUCCESS; + } + + return l; + + loser: + if( (PRStatus *)NULL != statusOpt ) { + *statusOpt = PR_FAILURE; + } + + return 0; +} + + +/* + * nssUTF8_Create + * + * This routine creates a UTF8 string from a string in some other + * format. Some types of string may include embedded null characters, + * so for them the length parameter must be used. For string types + * that are null-terminated, the length parameter is optional; if it + * is zero, it will be ignored. If the optional arena argument is + * non-null, the memory used for the new string will be obtained from + * that arena, otherwise it will be obtained from the heap. This + * routine may return NULL upon error, in which case it will have + * placed an error on the error stack. + * + * The error may be one of the following: + * NSS_ERROR_INVALID_POINTER + * NSS_ERROR_NO_MEMORY + * NSS_ERROR_UNSUPPORTED_TYPE + * + * Return value: + * NULL upon error + * A non-null pointer to a new UTF8 string otherwise + */ + +extern const NSSError NSS_ERROR_INTERNAL_ERROR; /* XXX fgmr */ + +NSS_IMPLEMENT NSSUTF8 * +nssUTF8_Create +( + NSSArena *arenaOpt, + nssStringType type, + const void *inputString, + PRUint32 size /* in bytes, not characters */ +) +{ + NSSUTF8 *rv = NULL; + +#ifdef NSSDEBUG + if( (NSSArena *)NULL != arenaOpt ) { + if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) { + return (NSSUTF8 *)NULL; + } + } + + if( (const void *)NULL == inputString ) { + nss_SetError(NSS_ERROR_INVALID_POINTER); + return (NSSUTF8 *)NULL; + } +#endif /* NSSDEBUG */ + + switch( type ) { + case nssStringType_DirectoryString: + /* This is a composite type requiring BER */ + nss_SetError(NSS_ERROR_UNSUPPORTED_TYPE); + break; + case nssStringType_TeletexString: + /* + * draft-ietf-pkix-ipki-part1-11 says in part: + * + * In addition, many legacy implementations support names encoded + * in the ISO 8859-1 character set (Latin1String) but tag them as + * TeletexString. The Latin1String includes characters used in + * Western European countries which are not part of the + * TeletexString charcter set. Implementations that process + * TeletexString SHOULD be prepared to handle the entire ISO + * 8859-1 character set.[ISO 8859-1]. + */ + nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */ + break; + case nssStringType_PrintableString: + /* + * PrintableString consists of A-Za-z0-9 ,()+,-./:=? + * This is a subset of ASCII, which is a subset of UTF8. + * So we can just duplicate the string over. + */ + + if( 0 == size ) { + rv = nssUTF8_Duplicate((const NSSUTF8 *)inputString, arenaOpt); + } else { + rv = nss_ZAlloc(arenaOpt, size+1); + if( (NSSUTF8 *)NULL == rv ) { + return (NSSUTF8 *)NULL; + } + + (void)nsslibc_memcpy(rv, inputString, size); + } + + break; + case nssStringType_UniversalString: + /* 4-byte unicode */ + nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */ + break; + case nssStringType_BMPString: + /* Base Multilingual Plane of Unicode */ + nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */ + break; + case nssStringType_UTF8String: + if( 0 == size ) { + rv = nssUTF8_Duplicate((const NSSUTF8 *)inputString, arenaOpt); + } else { + rv = nss_ZAlloc(arenaOpt, size+1); + if( (NSSUTF8 *)NULL == rv ) { + return (NSSUTF8 *)NULL; + } + + (void)nsslibc_memcpy(rv, inputString, size); + } + + break; + case nssStringType_PHGString: + /* + * PHGString is an IA5String (with case-insensitive comparisons). + * IA5 is ~almost~ ascii; ascii has dollar-sign where IA5 has + * currency symbol. + */ + nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */ + break; + case nssStringType_GeneralString: + nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */ + break; + default: + nss_SetError(NSS_ERROR_UNSUPPORTED_TYPE); + break; + } + + return rv; +} + +NSS_IMPLEMENT NSSItem * +nssUTF8_GetEncoding +( + NSSArena *arenaOpt, + NSSItem *rvOpt, + nssStringType type, + NSSUTF8 *string +) +{ + NSSItem *rv = (NSSItem *)NULL; + PRStatus status = PR_SUCCESS; + +#ifdef NSSDEBUG + if( (NSSArena *)NULL != arenaOpt ) { + if( PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) { + return (NSSItem *)NULL; + } + } + + if( (NSSUTF8 *)NULL == string ) { + nss_SetError(NSS_ERROR_INVALID_POINTER); + return (NSSItem *)NULL; + } +#endif /* NSSDEBUG */ + + switch( type ) { + case nssStringType_DirectoryString: + nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */ + break; + case nssStringType_TeletexString: + nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */ + break; + case nssStringType_PrintableString: + nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */ + break; + case nssStringType_UniversalString: + nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */ + break; + case nssStringType_BMPString: + nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */ + break; + case nssStringType_UTF8String: + { + NSSUTF8 *dup = nssUTF8_Duplicate(string, arenaOpt); + if( (NSSUTF8 *)NULL == dup ) { + return (NSSItem *)NULL; + } + + if( (NSSItem *)NULL == rvOpt ) { + rv = nss_ZNEW(arenaOpt, NSSItem); + if( (NSSItem *)NULL == rv ) { + (void)nss_ZFreeIf(dup); + return (NSSItem *)NULL; + } + } else { + rv = rvOpt; + } + + rv->data = dup; + dup = (NSSUTF8 *)NULL; + rv->size = nssUTF8_Size(rv->data, &status); + if( (0 == rv->size) && (PR_SUCCESS != status) ) { + if( (NSSItem *)NULL == rvOpt ) { + (void)nss_ZFreeIf(rv); + } + return (NSSItem *)NULL; + } + } + break; + case nssStringType_PHGString: + nss_SetError(NSS_ERROR_INTERNAL_ERROR); /* unimplemented */ + break; + default: + nss_SetError(NSS_ERROR_UNSUPPORTED_TYPE); + break; + } + + return rv; +} + +/* + * nssUTF8_CopyIntoFixedBuffer + * + * This will copy a UTF8 string into a fixed-length buffer, making + * sure that the all characters are valid. Any remaining space will + * be padded with the specified ASCII character, typically either + * null or space. + * + * Blah, blah, blah. + */ + +NSS_IMPLEMENT PRStatus +nssUTF8_CopyIntoFixedBuffer +( + NSSUTF8 *string, + char *buffer, + PRUint32 bufferSize, + char pad +) +{ + PRUint32 stringSize = 0; + +#ifdef NSSDEBUG + if( (char *)NULL == buffer ) { + nss_SetError(NSS_ERROR_INVALID_POINTER); + return PR_FALSE; + } + + if( 0 == bufferSize ) { + nss_SetError(NSS_ERROR_INVALID_ARGUMENT); + return PR_FALSE; + } + + if( (pad & 0x80) != 0x00 ) { + nss_SetError(NSS_ERROR_INVALID_ARGUMENT); + return PR_FALSE; + } +#endif /* NSSDEBUG */ + + if( (NSSUTF8 *)NULL == string ) { + string = (NSSUTF8 *) ""; + } + + stringSize = nssUTF8_Size(string, (PRStatus *)NULL); + stringSize--; /* don't count the trailing null */ + if( stringSize > bufferSize ) { + PRUint32 bs = bufferSize; + (void)nsslibc_memcpy(buffer, string, bufferSize); + + if( ( ((buffer[ bs-1 ] & 0x80) == 0x00)) || + ((bs > 1) && ((buffer[ bs-2 ] & 0xE0) == 0xC0)) || + ((bs > 2) && ((buffer[ bs-3 ] & 0xF0) == 0xE0)) || + ((bs > 3) && ((buffer[ bs-4 ] & 0xF8) == 0xF0)) || + ((bs > 4) && ((buffer[ bs-5 ] & 0xFC) == 0xF8)) || + ((bs > 5) && ((buffer[ bs-6 ] & 0xFE) == 0xFC)) ) { + /* It fit exactly */ + return PR_SUCCESS; + } + + /* Too long. We have to trim the last character */ + for( /*bs*/; bs != 0; bs-- ) { + if( (buffer[bs-1] & 0xC0) != 0x80 ) { + buffer[bs-1] = pad; + break; + } else { + buffer[bs-1] = pad; + } + } + } else { + (void)nsslibc_memset(buffer, pad, bufferSize); + (void)nsslibc_memcpy(buffer, string, stringSize); + } + + return PR_SUCCESS; +} + +/* + * nssUTF8_Equal + * + */ + +NSS_IMPLEMENT PRBool +nssUTF8_Equal +( + const NSSUTF8 *a, + const NSSUTF8 *b, + PRStatus *statusOpt +) +{ + PRUint32 la, lb; + +#ifdef NSSDEBUG + if( ((const NSSUTF8 *)NULL == a) || + ((const NSSUTF8 *)NULL == b) ) { + nss_SetError(NSS_ERROR_INVALID_POINTER); + if( (PRStatus *)NULL != statusOpt ) { + *statusOpt = PR_FAILURE; + } + return PR_FALSE; + } +#endif /* NSSDEBUG */ + + la = nssUTF8_Size(a, statusOpt); + if( 0 == la ) { + return PR_FALSE; + } + + lb = nssUTF8_Size(b, statusOpt); + if( 0 == lb ) { + return PR_FALSE; + } + + if( la != lb ) { + return PR_FALSE; + } + + return nsslibc_memequal(a, b, la, statusOpt); +} diff --git a/security/nss/lib/base/whatnspr.c b/security/nss/lib/base/whatnspr.c new file mode 100644 index 000000000..5303ec256 --- /dev/null +++ b/security/nss/lib/base/whatnspr.c @@ -0,0 +1,171 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#ifdef DEBUG +static const char CVS_ID[] = "@(#) $RCSfile$ $Revision$ $Date$ $Name$"; +#endif /* DEBUG */ + +#ifndef BASE_H +#include "base.h" +#endif /* BASE_H */ + +/* + * This file isolates us from differences in NSPR versions. + * We have to detect the library with which we're running at + * runtime, and switch behaviours there. This lets us do + * stuff like load cryptoki modules in Communicator. + * + * Hey, it's the PORT layer all over again! + */ + +static int whatnspr = 0; + +static int +set_whatnspr +( + void +) +{ + /* + * The only runtime difference I could find was the + * return value of PR_dtoa. We can't just look for + * a symbol in NSPR >=2, because it'll always be + * found (because we compile against NSPR >=2). + * Maybe we could look for a symbol merely in NSPR 1? + * + */ + + char buffer[64]; + int decpt = 0, sign = 0; + char *rve = (char *)0; + /* extern int PR_dtoa(double, int, int, int *, int *, char **, char *, int); */ + int r = (int)PR_dtoa((double)1.0, 0, 5, &decpt, &sign, &rve, + buffer, sizeof(buffer)); + + switch( r ) { + case 0: + case -1: + whatnspr = 2; + /* + * If we needed to, *now* we could look up "libVersionPoint" + * and get more data there.. except all current NSPR's (up + * to NSPR 4.x at time of writing) still say 2 in their + * version structure. + */ + break; + default: + whatnspr = 1; + break; + } + + return whatnspr; +} + +#define WHATNSPR (whatnspr ? whatnspr : set_whatnspr()) + +NSS_IMPLEMENT PRStatus +nss_NewThreadPrivateIndex +( + PRUintn *ip, + PRThreadPrivateDTOR dtor +) +{ + switch( WHATNSPR ) { + case 1: + { + PRLibrary *l = (PRLibrary *)0; + void *f = PR_FindSymbolAndLibrary("PR_NewThreadPrivateID", &l); + typedef PRInt32 (*ntpt)(void); + ntpt ntp = (ntpt) f; + + PR_ASSERT((void *)0 != f); + + *ip = ntp(); + return PR_SUCCESS; + } + case 2: + default: + return PR_NewThreadPrivateIndex(ip, dtor); + } +} + +NSS_IMPLEMENT void * +nss_GetThreadPrivate +( + PRUintn i +) +{ + switch( WHATNSPR ) { + case 1: + { + PRLibrary *l = (PRLibrary *)0; + void *f = PR_FindSymbolAndLibrary("PR_GetThreadPrivate", &l); + typedef void *(*gtpt)(PRThread *, PRInt32); + gtpt gtp = (gtpt) f; + + PR_ASSERT((void *)0 != f); + + return gtp(PR_CurrentThread(), i); + } + case 2: + default: + return PR_GetThreadPrivate(i); + } +} + +NSS_IMPLEMENT void +nss_SetThreadPrivate +( + PRUintn i, + void *v +) +{ + switch( WHATNSPR ) { + case 1: + { + PRLibrary *l = (PRLibrary *)0; + void *f = PR_FindSymbolAndLibrary("PR_SetThreadPrivate", &l); + typedef PRStatus (*stpt)(PRThread *, PRInt32, void *); + stpt stp = (stpt) f; + + PR_ASSERT((void *)0 != f); + + (void)stp(PR_CurrentThread(), i, v); + return; + } + case 2: + default: + (void)PR_SetThreadPrivate(i, v); + return; + } +} |