diff options
Diffstat (limited to '')
-rw-r--r-- | security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_object.c | 1440 |
1 files changed, 1440 insertions, 0 deletions
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_object.c b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_object.c new file mode 100644 index 0000000000..7dafa0b204 --- /dev/null +++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_object.c @@ -0,0 +1,1440 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* + * pkix_pl_object.c + * + * Object Construction, Destruction and Callback Functions + * + */ + +#include "pkix_pl_object.h" + +#ifdef PKIX_USER_OBJECT_TYPE +/* --Class-Table-Initializers------------------------------------ */ + +/* + * Create storage space for 20 Class Table buckets. + * These are only for user-defined types. System types are registered + * separately by PKIX_PL_Initialize. + */ + +static pkix_pl_HT_Elem* +pkix_Raw_ClassTable_Buckets[] = { + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL +}; + +/* + * Allocate static memory for a ClassTable. + * XXX This assumes the bucket pointer will fit into a PKIX_UInt32 + */ +static pkix_pl_PrimHashTable pkix_Raw_ClassTable = { + (void *)pkix_Raw_ClassTable_Buckets, /* Buckets */ + 20 /* Number of Buckets */ +}; +static pkix_pl_PrimHashTable * classTable = &pkix_Raw_ClassTable; +#endif /* PKIX_USER_OBJECT_TYPE */ + +/* --Private-Functions-------------------------------------------- */ + +/* + * FUNCTION: pkix_pl_Object_GetHeader + * DESCRIPTION: + * + * Shifts Object pointed to by "object" by the sizeof(PKIX_PL_Object) and + * stores the value at "pObjectHeader". + * + * PARAMETERS: + * "object" + * Address of Object to shift. Must be non-NULL. + * "pObjectHeader" + * Address where object pointer will be stored. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_Object_GetHeader( + PKIX_PL_Object *object, + PKIX_PL_Object **pObjectHeader, + void *plContext) +{ + PKIX_PL_Object *header = NULL; + PKIX_UInt32 objType; + + PKIX_ENTER(OBJECT, "pkix_pl_Object_GetHeader"); + PKIX_NULLCHECK_TWO(object, pObjectHeader); + + PKIX_OBJECT_DEBUG("\tShifting object pointer).\n"); + + /* The header is sizeof(PKIX_PL_Object) before the object pointer */ + header = (PKIX_PL_Object *)((char *)object - sizeof(PKIX_PL_Object)); + + objType = header->type; + + if (objType >= PKIX_NUMTYPES) { /* if this is a user-defined type */ +#ifdef PKIX_USER_OBJECT_TYPE + pkix_ClassTable_Entry *ctEntry = NULL; + + PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n"); + PR_Lock(classTableLock); + + PKIX_CHECK(pkix_pl_PrimHashTable_Lookup + (classTable, + (void *)&objType, + objType, + NULL, + (void **)&ctEntry, + plContext), + PKIX_ERRORGETTINGCLASSTABLEENTRY); + + PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n"); + PR_Unlock(classTableLock); + + if (ctEntry == NULL) { + PKIX_ERROR_FATAL(PKIX_UNKNOWNOBJECTTYPE); + } +#else + PORT_Assert(objType < PKIX_NUMTYPES); + pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE; + pkixErrorClass = PKIX_FATAL_ERROR; + goto cleanup; +#endif /* PKIX_USER_OBJECT_TYPE */ + } + +#ifdef PKIX_OBJECT_LEAK_TEST + PORT_Assert(header && header->magicHeader == PKIX_MAGIC_HEADER); +#endif /* PKIX_OBJECT_LEAK_TEST */ + + if ((header == NULL)|| + (header->magicHeader != PKIX_MAGIC_HEADER)) { + PKIX_ERROR_ALLOC_ERROR(); + } + + *pObjectHeader = header; + +cleanup: + + PKIX_RETURN(OBJECT); +} + +/* + * FUNCTION: pkix_Destroy_Object + * DESCRIPTION: + * + * Destroys and deallocates Object pointed to by "object". The caller is + * assumed to hold the Object's lock, which is acquired in + * PKIX_PL_Object_DecRef(). + * + * PARAMETERS: + * "object" + * Address of Object to destroy. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_Object_Destroy( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_Object *objectHeader = NULL; + + PKIX_ENTER(OBJECT, "pkix_pl_Object_Destroy"); + PKIX_NULLCHECK_ONE(object); + +#ifdef PKIX_OBJECT_LEAK_TEST + PKIX_CHECK_FATAL(pkix_pl_Object_GetHeader(object, &objectHeader, plContext), + PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT); +#else + PKIX_CHECK(pkix_pl_Object_GetHeader(object, &objectHeader, plContext), + PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT); +#endif /* PKIX_OBJECT_LEAK_TEST */ + + /* Attempt to delete an object still being used */ + if (objectHeader->references != 0) { + PKIX_ERROR_FATAL(PKIX_OBJECTSTILLREFERENCED); + } + + PKIX_DECREF(objectHeader->stringRep); + + /* Destroy this object's lock */ + PKIX_OBJECT_DEBUG("\tCalling PR_DestroyLock).\n"); + PR_DestroyLock(objectHeader->lock); + objectHeader->lock = NULL; + object = NULL; + + objectHeader->magicHeader = PKIX_MAGIC_HEADER_DESTROYED; + +#ifdef PKIX_OBJECT_LEAK_TEST + memset(objectHeader, 0xbf, systemClasses[PKIX_OBJECT_TYPE].typeObjectSize); +#endif + + PKIX_FREE(objectHeader); + +cleanup: +#ifdef PKIX_OBJECT_LEAK_TEST +fatal: +#endif + + PKIX_RETURN(OBJECT); +} + +/* --Default-Callbacks-------------------------------------------- */ + +/* + * FUNCTION: pkix_pl_Object_Equals_Default + * DESCRIPTION: + * + * Default Object_Equals callback: Compares the address of the Object pointed + * to by "firstObject" with the address of the Object pointed to by + * "secondObject" and stores the Boolean result at "pResult". + * + * PARAMETERS: + * "firstObject" + * Address of first Object to compare. Must be non-NULL. + * "secondObject" + * Address of second Object to compare. Must be non-NULL. + * "pResult" + * Address where Boolean result will be stored. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_Object_Equals_Default( + PKIX_PL_Object *firstObject, + PKIX_PL_Object *secondObject, + PKIX_Boolean *pResult, + void *plContext) +{ + PKIX_ENTER(OBJECT, "pkix_pl_Object_Equals_Default"); + PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); + + /* Just compare pointer values */ + *pResult = (firstObject == secondObject)?PKIX_TRUE:PKIX_FALSE; + + PKIX_RETURN(OBJECT); +} + +/* + * FUNCTION: pkix_pl_Object_ToString_Default + * DESCRIPTION: + * + * Default Object_ToString callback: Creates a string consisting of the + * typename and address of the Object pointed to by "object" and stores + * the result at "pString". The format for the string is + * "TypeName@Address: <address>", where the default typename is "Object". + * + * PARAMETERS: + * "object" + * Address of Object to convert to a string. Must be non-NULL. + * "pString" + * Address where object pointer will be stored. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns an Object Error if the function fails in a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_Object_ToString_Default( + PKIX_PL_Object *object, + PKIX_PL_String **pString, + void *plContext) +{ + PKIX_PL_String *formatString = NULL; + PKIX_PL_String *descString = NULL; + char *format = "%s@Address: %x"; + char *description = NULL; + PKIX_UInt32 objType; + + PKIX_ENTER(OBJECT, "pkix_pl_Object_ToString_Default"); + PKIX_NULLCHECK_TWO(object, pString); + + PKIX_CHECK(PKIX_PL_Object_GetType(object, &objType, plContext), + PKIX_OBJECTGETTYPEFAILED); + + if (objType >= PKIX_NUMTYPES){ +#ifdef PKIX_USER_OBJECT_TYPE + pkix_ClassTable_Entry *ctEntry = NULL; + + PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n"); + PR_Lock(classTableLock); + pkixErrorResult = pkix_pl_PrimHashTable_Lookup + (classTable, + (void *)&objType, + objType, + NULL, + (void **)&ctEntry, + plContext); + PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n"); + PR_Unlock(classTableLock); + if (pkixErrorResult){ + PKIX_ERROR_FATAL(PKIX_ERRORGETTINGCLASSTABLEENTRY); + } + + if (ctEntry == NULL){ + PKIX_ERROR_FATAL(PKIX_UNDEFINEDCLASSTABLEENTRY); + } else { + description = ctEntry->description; + if (description == NULL) { + description = "User Type Object"; + } + } +#else + PORT_Assert (0); + pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE; + pkixErrorClass = PKIX_FATAL_ERROR; + goto cleanup; +#endif /* PKIX_USER_OBJECT_TYPE */ + } else { + description = systemClasses[objType].description; + } + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, + (void *)format, + 0, + &formatString, + plContext), + PKIX_STRINGCREATEFAILED); + + PKIX_CHECK(PKIX_PL_String_Create + (PKIX_ESCASCII, + (void *)description, + 0, + &descString, + plContext), + PKIX_STRINGCREATEFAILED); + + PKIX_CHECK(PKIX_PL_Sprintf + (pString, + plContext, + formatString, + descString, + object), + PKIX_SPRINTFFAILED); + +cleanup: + + PKIX_DECREF(formatString); + PKIX_DECREF(descString); + + PKIX_RETURN(OBJECT); +} + +/* + * FUNCTION: pkix_pl_Object_Hashcode_Default + * DESCRIPTION: + * + * Default Object_Hashcode callback. Creates the a hashcode value using the + * address of the Object pointed to by "object" and stores the result at + * "pValue". + * + * XXX This isn't great since addresses are not uniformly distributed. + * + * PARAMETERS: + * "object" + * Address of Object to compute hashcode for. Must be non-NULL. + * "pValue" + * Address where PKIX_UInt32 will be stored. Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +static PKIX_Error * +pkix_pl_Object_Hashcode_Default( + PKIX_PL_Object *object, + PKIX_UInt32 *pValue, + void *plContext) +{ + PKIX_ENTER(OBJECT, "pkix_pl_Object_Hashcode_Default"); + PKIX_NULLCHECK_TWO(object, pValue); + + *pValue = (PKIX_UInt32)((char *)object - (char *)NULL); + + PKIX_RETURN(OBJECT); +} + +/* + * FUNCTION: pkix_pl_Object_RetrieveEqualsCallback + * DESCRIPTION: + * + * Retrieves Equals callback function of Object pointed to by "object and + * stores it at "pEqualsCallback". If the object's type is one of the system + * types, its callback function is retrieved from the systemClasses array; + * otherwise, its callback function is retrieve from the classTable hash + * table where user-defined types are stored. + * + * PARAMETERS: + * "object" + * Address of Object whose equals callback is desired. Must be non-NULL. + * "pEqualsCallback" + * Address where EqualsCallback function pointer will be stored. + * Must be non-NULL. + * "plContext" + * Platform-specific context pointer. + * THREAD SAFETY: + * Thread Safe (see Thread Safety Definitions in Programmer's Guide) + * RETURNS: + * Returns NULL if the function succeeds. + * Returns an Object Error if the function fails in a non-fatal way. + * Returns a Fatal Error if the function fails in an unrecoverable way. + */ +PKIX_Error * +pkix_pl_Object_RetrieveEqualsCallback( + PKIX_PL_Object *object, + PKIX_PL_EqualsCallback *pEqualsCallback, + void *plContext) +{ + PKIX_PL_Object *objectHeader = NULL; + PKIX_PL_EqualsCallback func = NULL; + pkix_ClassTable_Entry entry; + PKIX_UInt32 objType; + + PKIX_ENTER(OBJECT, "pkix_pl_Object_RetrieveEqualsCallback"); + PKIX_NULLCHECK_TWO(object, pEqualsCallback); + + PKIX_CHECK(pkix_pl_Object_GetHeader + (object, &objectHeader, plContext), + PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT); + + objType = objectHeader->type; + + if (objType >= PKIX_NUMTYPES){ +#ifdef PKIX_USER_OBJECT_TYPE + pkix_ClassTable_Entry *ctEntry = NULL; + + PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n"); + PR_Lock(classTableLock); + pkixErrorResult = pkix_pl_PrimHashTable_Lookup + (classTable, + (void *)&objType, + objType, + NULL, + (void **)&ctEntry, + plContext); + PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n"); + PR_Unlock(classTableLock); + if (pkixErrorResult){ + PKIX_ERROR(PKIX_ERRORGETTINGCLASSTABLEENTRY); + } + + if ((ctEntry == NULL) || (ctEntry->equalsFunction == NULL)) { + PKIX_ERROR(PKIX_UNDEFINEDEQUALSCALLBACK); + } else { + *pEqualsCallback = ctEntry->equalsFunction; + } +#else + PORT_Assert (0); + pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE; + pkixErrorClass = PKIX_FATAL_ERROR; + goto cleanup; +#endif /* PKIX_USER_OBJECT_TYPE */ + } else { + entry = systemClasses[objType]; + func = entry.equalsFunction; + if (func == NULL){ + func = pkix_pl_Object_Equals_Default; + } + *pEqualsCallback = func; + } + +cleanup: + + PKIX_RETURN(OBJECT); +} + +/* + * FUNCTION: pkix_pl_Object_RegisterSelf + * DESCRIPTION: + * Registers PKIX_OBJECT_TYPE and its related functions with systemClasses[] + * THREAD SAFETY: + * Not Thread Safe - for performance and complexity reasons + * + * Since this function is only called by PKIX_PL_Initialize, which should + * only be called once, it is acceptable that this function is not + * thread-safe. + * + * PKIX_PL_Object should have all function pointes to be to NULL: they + * work as proxy function to a real objects. + * + */ +PKIX_Error * +pkix_pl_Object_RegisterSelf(void *plContext) +{ + pkix_ClassTable_Entry entry; + + PKIX_ENTER(ERROR, "pkix_pl_Object_RegisterSelf"); + + entry.description = "Object"; + entry.objCounter = 0; + entry.typeObjectSize = sizeof(PKIX_PL_Object); + entry.destructor = NULL; + entry.equalsFunction = NULL; + entry.hashcodeFunction = NULL; + entry.toStringFunction = NULL; + entry.comparator = NULL; + entry.duplicateFunction = NULL; + + systemClasses[PKIX_OBJECT_TYPE] = entry; + + PKIX_RETURN(ERROR); +} + +/* --Public-Functions------------------------------------------------------- */ + +/* + * FUNCTION: PKIX_PL_Object_Alloc (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_Object_Alloc( + PKIX_TYPENUM objType, + PKIX_UInt32 size, + PKIX_PL_Object **pObject, + void *plContext) +{ + PKIX_PL_Object *object = NULL; + pkix_ClassTable_Entry *ctEntry = NULL; + + PKIX_ENTER(OBJECT, "PKIX_PL_Object_Alloc"); + PKIX_NULLCHECK_ONE(pObject); + + /* + * We need to ensure that user-defined types have been registered. + * All system types have already been registered by PKIX_PL_Initialize. + */ + + if (objType >= PKIX_NUMTYPES) { /* i.e. if this is a user-defined type */ +#ifdef PKIX_USER_OBJECT_TYPE + PKIX_Boolean typeRegistered; + PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n"); + PR_Lock(classTableLock); + pkixErrorResult = pkix_pl_PrimHashTable_Lookup + (classTable, + (void *)&objType, + objType, + NULL, + (void **)&ctEntry, + plContext); + PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n"); + PR_Unlock(classTableLock); + if (pkixErrorResult){ + PKIX_ERROR_FATAL(PKIX_COULDNOTLOOKUPINHASHTABLE); + } + + typeRegistered = (ctEntry != NULL); + + if (!typeRegistered) { + PKIX_ERROR_FATAL(PKIX_UNKNOWNTYPEARGUMENT); + } +#else + PORT_Assert (0); + pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE; + pkixErrorClass = PKIX_FATAL_ERROR; + goto cleanup; +#endif /* PKIX_USER_OBJECT_TYPE */ + } else { + ctEntry = &systemClasses[objType]; + } + + PORT_Assert(size == ctEntry->typeObjectSize); + + /* Allocate space for the object header and the requested size */ +#ifdef PKIX_OBJECT_LEAK_TEST + PKIX_CHECK(PKIX_PL_Calloc + (1, + ((PKIX_UInt32)sizeof (PKIX_PL_Object))+size, + (void **)&object, + plContext), + PKIX_MALLOCFAILED); +#else + PKIX_CHECK(PKIX_PL_Malloc + (((PKIX_UInt32)sizeof (PKIX_PL_Object))+size, + (void **)&object, + plContext), + PKIX_MALLOCFAILED); +#endif /* PKIX_OBJECT_LEAK_TEST */ + + /* Initialize all object fields */ + object->magicHeader = PKIX_MAGIC_HEADER; + object->type = objType; + object->references = 1; /* Default to a single reference */ + object->stringRep = NULL; + object->hashcode = 0; + object->hashcodeCached = 0; + + /* Cannot use PKIX_PL_Mutex because it depends on Object */ + /* Using NSPR Locks instead */ + PKIX_OBJECT_DEBUG("\tCalling PR_NewLock).\n"); + object->lock = PR_NewLock(); + if (object->lock == NULL) { + PKIX_ERROR_ALLOC_ERROR(); + } + + PKIX_OBJECT_DEBUG("\tShifting object pointer).\n"); + + + /* Return a pointer to the user data. Need to offset by object size */ + *pObject = object + 1; + object = NULL; + + /* Atomically increment object counter */ + PR_ATOMIC_INCREMENT((PRInt32*)&ctEntry->objCounter); + +cleanup: + + PKIX_FREE(object); + + PKIX_RETURN(OBJECT); +} + +/* + * FUNCTION: PKIX_PL_Object_IsTypeRegistered (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_Object_IsTypeRegistered( + PKIX_UInt32 objType, + PKIX_Boolean *pBool, + void *plContext) +{ +#ifdef PKIX_USER_OBJECT_TYPE + pkix_ClassTable_Entry *ctEntry = NULL; +#endif + + PKIX_ENTER(OBJECT, "PKIX_PL_Object_IsTypeRegistered"); + PKIX_NULLCHECK_ONE(pBool); + + /* first, we handle the system types */ + if (objType < PKIX_NUMTYPES) { + *pBool = PKIX_TRUE; + goto cleanup; + } + +#ifndef PKIX_USER_OBJECT_TYPE + PORT_Assert (0); + pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE; + pkixErrorClass = PKIX_FATAL_ERROR; +#else + PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n"); + PR_Lock(classTableLock); + pkixErrorResult = pkix_pl_PrimHashTable_Lookup + (classTable, + (void *)&objType, + objType, + NULL, + (void **)&ctEntry, + plContext); + PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n"); + PR_Unlock(classTableLock); + + if (pkixErrorResult){ + PKIX_ERROR_FATAL(PKIX_COULDNOTLOOKUPINHASHTABLE); + } + + *pBool = (ctEntry != NULL); +#endif /* PKIX_USER_OBJECT_TYPE */ + +cleanup: + + PKIX_RETURN(OBJECT); +} + +#ifdef PKIX_USER_OBJECT_TYPE +/* + * FUNCTION: PKIX_PL_Object_RegisterType (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_Object_RegisterType( + PKIX_UInt32 objType, + char *description, + PKIX_PL_DestructorCallback destructor, + PKIX_PL_EqualsCallback equalsFunction, + PKIX_PL_HashcodeCallback hashcodeFunction, + PKIX_PL_ToStringCallback toStringFunction, + PKIX_PL_ComparatorCallback comparator, + PKIX_PL_DuplicateCallback duplicateFunction, + void *plContext) +{ + pkix_ClassTable_Entry *ctEntry = NULL; + pkix_pl_Integer *key = NULL; + + PKIX_ENTER(OBJECT, "PKIX_PL_Object_RegisterType"); + + /* + * System types are registered on startup by PKIX_PL_Initialize. + * These can not be overwritten. + */ + + if (objType < PKIX_NUMTYPES) { /* if this is a system type */ + PKIX_ERROR(PKIX_CANTREREGISTERSYSTEMTYPE); + } + + PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n"); + PR_Lock(classTableLock); + PKIX_CHECK(pkix_pl_PrimHashTable_Lookup + (classTable, + (void *)&objType, + objType, + NULL, + (void **)&ctEntry, + plContext), + PKIX_PRIMHASHTABLELOOKUPFAILED); + + /* If the type is already registered, throw an error */ + if (ctEntry) { + PKIX_ERROR(PKIX_TYPEALREADYREGISTERED); + } + + PKIX_CHECK(PKIX_PL_Malloc + (((PKIX_UInt32)sizeof (pkix_ClassTable_Entry)), + (void **)&ctEntry, + plContext), + PKIX_MALLOCFAILED); + + /* Set Default Values if none specified */ + + if (description == NULL){ + description = "Object"; + } + + if (equalsFunction == NULL) { + equalsFunction = pkix_pl_Object_Equals_Default; + } + + if (toStringFunction == NULL) { + toStringFunction = pkix_pl_Object_ToString_Default; + } + + if (hashcodeFunction == NULL) { + hashcodeFunction = pkix_pl_Object_Hashcode_Default; + } + + ctEntry->destructor = destructor; + ctEntry->equalsFunction = equalsFunction; + ctEntry->toStringFunction = toStringFunction; + ctEntry->hashcodeFunction = hashcodeFunction; + ctEntry->comparator = comparator; + ctEntry->duplicateFunction = duplicateFunction; + ctEntry->description = description; + + PKIX_CHECK(PKIX_PL_Malloc + (((PKIX_UInt32)sizeof (pkix_pl_Integer)), + (void **)&key, + plContext), + PKIX_COULDNOTMALLOCNEWKEY); + + key->ht_int = objType; + + PKIX_CHECK(pkix_pl_PrimHashTable_Add + (classTable, + (void *)key, + (void *)ctEntry, + objType, + NULL, + plContext), + PKIX_PRIMHASHTABLEADDFAILED); + +cleanup: + PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n"); + PR_Unlock(classTableLock); + + PKIX_RETURN(OBJECT); +} +#endif /* PKIX_USER_OBJECT_TYPE */ + +/* + * FUNCTION: PKIX_PL_Object_IncRef (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_Object_IncRef( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_Object *objectHeader = NULL; + PKIX_PL_NssContext *context = NULL; + PKIX_Int32 refCount = 0; + + PKIX_ENTER(OBJECT, "PKIX_PL_Object_IncRef"); + PKIX_NULLCHECK_ONE(object); + + if (plContext){ + /* + * PKIX_PL_NssContext is not a complete PKIX Type, it doesn't + * have a header therefore we cannot verify its type before + * casting. + */ + context = (PKIX_PL_NssContext *) plContext; + if (context->arena != NULL) { + goto cleanup; + } + } + + if (object == (PKIX_PL_Object*)PKIX_ALLOC_ERROR()) { + goto cleanup; + } + + /* Shift pointer from user data to object header */ + PKIX_CHECK(pkix_pl_Object_GetHeader(object, &objectHeader, plContext), + PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT); + + /* This object should never have zero references */ + refCount = PR_ATOMIC_INCREMENT(&objectHeader->references); + + if (refCount <= 1) { + PKIX_THROW(FATAL, PKIX_OBJECTWITHNONPOSITIVEREFERENCES); + } + +cleanup: + + PKIX_RETURN(OBJECT); +} + +/* + * FUNCTION: PKIX_PL_Object_DecRef (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_Object_DecRef( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_Int32 refCount = 0; + PKIX_PL_Object *objectHeader = NULL; + PKIX_PL_NssContext *context = NULL; + + PKIX_ENTER(OBJECT, "PKIX_PL_Object_DecRef"); + PKIX_NULLCHECK_ONE(object); + + if (plContext){ + /* + * PKIX_PL_NssContext is not a complete PKIX Type, it doesn't + * have a header therefore we cannot verify its type before + * casting. + */ + context = (PKIX_PL_NssContext *) plContext; + if (context->arena != NULL) { + goto cleanup; + } + } + + if (object == (PKIX_PL_Object*)PKIX_ALLOC_ERROR()) { + goto cleanup; + } + + /* Shift pointer from user data to object header */ + PKIX_CHECK(pkix_pl_Object_GetHeader(object, &objectHeader, plContext), + PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT); + + refCount = PR_ATOMIC_DECREMENT(&objectHeader->references); + + if (refCount == 0) { + PKIX_PL_DestructorCallback destructor = NULL; + pkix_ClassTable_Entry *ctEntry = NULL; + PKIX_UInt32 objType = objectHeader->type; + + /* first, special handling for system types */ + if (objType >= PKIX_NUMTYPES){ +#ifdef PKIX_USER_OBJECT_TYPE + PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n"); + PR_Lock(classTableLock); + pkixErrorResult = pkix_pl_PrimHashTable_Lookup + (classTable, + (void *)&objType, + objType, + NULL, + (void **)&ctEntry, + plContext); + PKIX_OBJECT_DEBUG + ("\tCalling PR_Unlock).\n"); + PR_Unlock(classTableLock); + if (pkixErrorResult){ + PKIX_ERROR_FATAL + (PKIX_ERRORINGETTINGDESTRUCTOR); + } + + if (ctEntry != NULL){ + destructor = ctEntry->destructor; + } +#else + PORT_Assert (0); + pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE; + pkixErrorClass = PKIX_FATAL_ERROR; + goto cleanup; +#endif /* PKIX_USER_OBJECT_TYPE */ + } else { + ctEntry = &systemClasses[objType]; + destructor = ctEntry->destructor; + } + + if (destructor != NULL){ + /* Call destructor on user data if necessary */ + pkixErrorResult = destructor(object, plContext); + if (pkixErrorResult) { + pkixErrorClass = PKIX_FATAL_ERROR; + PKIX_DoAddError(stdVarsPtr, pkixErrorResult, plContext); + pkixErrorResult = NULL; + } + } + + /* Atomically decrement object counter */ + PR_ATOMIC_DECREMENT((PRInt32*)&ctEntry->objCounter); + + /* pkix_pl_Object_Destroy assumes the lock is held */ + /* It will call unlock and destroy the object */ + pkixErrorResult = pkix_pl_Object_Destroy(object, plContext); + goto cleanup; + } + + if (refCount < 0) { + PKIX_ERROR_ALLOC_ERROR(); + } + +cleanup: + + PKIX_RETURN(OBJECT); +} + + + +/* + * FUNCTION: PKIX_PL_Object_Equals (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_Object_Equals( + PKIX_PL_Object *firstObject, + PKIX_PL_Object *secondObject, + PKIX_Boolean *pResult, + void *plContext) +{ + PKIX_PL_Object *firstObjectHeader = NULL; + PKIX_PL_Object *secondObjectHeader = NULL; + PKIX_PL_EqualsCallback func = NULL; + pkix_ClassTable_Entry entry; + PKIX_UInt32 objType; + + PKIX_ENTER(OBJECT, "PKIX_PL_Object_Equals"); + PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); + + PKIX_CHECK(pkix_pl_Object_GetHeader + (firstObject, &firstObjectHeader, plContext), + PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT); + + PKIX_CHECK(pkix_pl_Object_GetHeader + (secondObject, &secondObjectHeader, plContext), + PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT); + + /* if hashcodes are cached but not equal, objects can't be equal */ + if (firstObjectHeader->hashcodeCached && + secondObjectHeader->hashcodeCached){ + if (firstObjectHeader->hashcode != + secondObjectHeader->hashcode){ + *pResult = PKIX_FALSE; + goto cleanup; + } + } + + objType = firstObjectHeader->type; + + if (objType >= PKIX_NUMTYPES) { +#ifdef PKIX_USER_OBJECT_TYPE + pkix_ClassTable_Entry *ctEntry = NULL; + PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n"); + PR_Lock(classTableLock); + pkixErrorResult = pkix_pl_PrimHashTable_Lookup + (classTable, + (void *)&firstObjectHeader->type, + firstObjectHeader->type, + NULL, + (void **)&ctEntry, + plContext); + PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n"); + PR_Unlock(classTableLock); + + if (pkixErrorResult){ + PKIX_ERROR_FATAL(PKIX_ERRORGETTINGCLASSTABLEENTRY); + } + + if ((ctEntry == NULL) || (ctEntry->equalsFunction == NULL)) { + PKIX_ERROR_FATAL(PKIX_UNDEFINEDCALLBACK); + } else { + func = ctEntry->equalsFunction; + } +#else + PORT_Assert (0); + pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE; + pkixErrorClass = PKIX_FATAL_ERROR; + goto cleanup; +#endif /* PKIX_USER_OBJECT_TYPE */ + } else { + entry = systemClasses[objType]; + func = entry.equalsFunction; + if (func == NULL){ + func = pkix_pl_Object_Equals_Default; + } + } + + PKIX_CHECK(func(firstObject, secondObject, pResult, plContext), + PKIX_OBJECTSPECIFICFUNCTIONFAILED); + +cleanup: + + PKIX_RETURN(OBJECT); +} + +/* + * FUNCTION: PKIX_PL_Object_Duplicate (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_Object_Duplicate( + PKIX_PL_Object *firstObject, + PKIX_PL_Object **pNewObject, + void *plContext) +{ + PKIX_PL_Object *firstObjectHeader = NULL; + PKIX_PL_DuplicateCallback func = NULL; + pkix_ClassTable_Entry entry; + PKIX_UInt32 objType; + + PKIX_ENTER(OBJECT, "PKIX_PL_Object_Duplicate"); + PKIX_NULLCHECK_TWO(firstObject, pNewObject); + + PKIX_CHECK(pkix_pl_Object_GetHeader + (firstObject, &firstObjectHeader, plContext), + PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT); + + objType = firstObjectHeader->type; + + if (objType >= PKIX_NUMTYPES) { +#ifdef PKIX_USER_OBJECT_TYPE + pkix_ClassTable_Entry *ctEntry = NULL; + + PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n"); + PR_Lock(classTableLock); + pkixErrorResult = pkix_pl_PrimHashTable_Lookup + (classTable, + (void *)&objType, + objType, + NULL, + (void **)&ctEntry, + plContext); + PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n"); + PR_Unlock(classTableLock); + + if (pkixErrorResult){ + PKIX_ERROR_FATAL(PKIX_ERRORGETTINGCLASSTABLEENTRY); + } + + if ((ctEntry == NULL) || (ctEntry->duplicateFunction == NULL)) { + PKIX_ERROR_FATAL(PKIX_UNDEFINEDCALLBACK); + } else { + func = ctEntry->duplicateFunction; + } +#else + PORT_Assert (0); + pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE; + pkixErrorClass = PKIX_FATAL_ERROR; + goto cleanup; +#endif /* PKIX_USER_OBJECT_TYPE */ + } else { + entry = systemClasses[objType]; + func = entry.duplicateFunction; + if (!func){ + PKIX_ERROR_FATAL(PKIX_UNDEFINEDDUPLICATEFUNCTION); + } + } + + PKIX_CHECK(func(firstObject, pNewObject, plContext), + PKIX_OBJECTSPECIFICFUNCTIONFAILED); + +cleanup: + + PKIX_RETURN(OBJECT); +} + +/* + * FUNCTION: PKIX_PL_Object_Hashcode (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_Object_Hashcode( + PKIX_PL_Object *object, + PKIX_UInt32 *pValue, + void *plContext) +{ + PKIX_PL_Object *objectHeader = NULL; + PKIX_PL_HashcodeCallback func = NULL; + pkix_ClassTable_Entry entry; + PKIX_UInt32 objectHash; + + PKIX_ENTER(OBJECT, "PKIX_PL_Object_Hashcode"); + PKIX_NULLCHECK_TWO(object, pValue); + + /* Shift pointer from user data to object header */ + PKIX_CHECK(pkix_pl_Object_GetHeader(object, &objectHeader, plContext), + PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT); + + /* if we don't have a cached copy from before, we create one */ + if (!objectHeader->hashcodeCached){ + + PKIX_UInt32 objType = objectHeader->type; + + /* first, special handling for system types */ + if (objType >= PKIX_NUMTYPES){ +#ifdef PKIX_USER_OBJECT_TYPE + pkix_ClassTable_Entry *ctEntry = NULL; + + PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n"); + PR_Lock(classTableLock); + pkixErrorResult = pkix_pl_PrimHashTable_Lookup + (classTable, + (void *)&objType, + objType, + NULL, + (void **)&ctEntry, + plContext); + PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n"); + PR_Unlock(classTableLock); + + if (pkixErrorResult){ + PKIX_ERROR_FATAL + (PKIX_ERRORGETTINGCLASSTABLEENTRY); + } + + if ((ctEntry == NULL) || + (ctEntry->hashcodeFunction == NULL)) { + PKIX_ERROR_FATAL(PKIX_UNDEFINEDCALLBACK); + } + + func = ctEntry->hashcodeFunction; +#else + PORT_Assert (0); + pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE; + pkixErrorClass = PKIX_FATAL_ERROR; + goto cleanup; +#endif /* PKIX_USER_OBJECT_TYPE */ + } else { + entry = systemClasses[objType]; + func = entry.hashcodeFunction; + if (func == NULL){ + func = pkix_pl_Object_Hashcode_Default; + } + } + + PKIX_CHECK(func(object, &objectHash, plContext), + PKIX_OBJECTSPECIFICFUNCTIONFAILED); + + if (!objectHeader->hashcodeCached){ + + PKIX_CHECK(pkix_LockObject(object, plContext), + PKIX_ERRORLOCKINGOBJECT); + + if (!objectHeader->hashcodeCached){ + /* save cached copy in case we need it again */ + objectHeader->hashcode = objectHash; + objectHeader->hashcodeCached = PKIX_TRUE; + } + + PKIX_CHECK(pkix_UnlockObject(object, plContext), + PKIX_ERRORUNLOCKINGOBJECT); + } + } + + *pValue = objectHeader->hashcode; + +cleanup: + + PKIX_RETURN(OBJECT); +} + +/* + * FUNCTION: PKIX_PL_Object_ToString (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_Object_ToString( + PKIX_PL_Object *object, + PKIX_PL_String **pString, + void *plContext) +{ + PKIX_PL_Object *objectHeader = NULL; + PKIX_PL_ToStringCallback func = NULL; + pkix_ClassTable_Entry entry; + PKIX_PL_String *objectString = NULL; + + PKIX_ENTER(OBJECT, "PKIX_PL_Object_ToString"); + PKIX_NULLCHECK_TWO(object, pString); + + /* Shift pointer from user data to object header */ + PKIX_CHECK(pkix_pl_Object_GetHeader(object, &objectHeader, plContext), + PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT); + + /* if we don't have a cached copy from before, we create one */ + if (!objectHeader->stringRep){ + + PKIX_UInt32 objType = objectHeader->type; + + if (objType >= PKIX_NUMTYPES){ +#ifdef PKIX_USER_OBJECT_TYPE + pkix_ClassTable_Entry *ctEntry = NULL; + + PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n"); + PR_Lock(classTableLock); + pkixErrorResult = pkix_pl_PrimHashTable_Lookup + (classTable, + (void *)&objType, + objType, + NULL, + (void **)&ctEntry, + plContext); + PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n"); + PR_Unlock(classTableLock); + if (pkixErrorResult){ + PKIX_ERROR_FATAL + (PKIX_ERRORGETTINGCLASSTABLEENTRY); + } + + if ((ctEntry == NULL) || + (ctEntry->toStringFunction == NULL)) { + PKIX_ERROR_FATAL(PKIX_UNDEFINEDCALLBACK); + } + + func = ctEntry->toStringFunction; +#else + PORT_Assert (0); + pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE; + pkixErrorClass = PKIX_FATAL_ERROR; + goto cleanup; +#endif /* PKIX_USER_OBJECT_TYPE */ + } else { + entry = systemClasses[objType]; + func = entry.toStringFunction; + if (func == NULL){ + func = pkix_pl_Object_ToString_Default; + } + } + + PKIX_CHECK(func(object, &objectString, plContext), + PKIX_OBJECTSPECIFICFUNCTIONFAILED); + + if (!objectHeader->stringRep){ + + PKIX_CHECK(pkix_LockObject(object, plContext), + PKIX_ERRORLOCKINGOBJECT); + + if (!objectHeader->stringRep){ + /* save a cached copy */ + objectHeader->stringRep = objectString; + objectString = NULL; + } + + PKIX_CHECK(pkix_UnlockObject(object, plContext), + PKIX_ERRORUNLOCKINGOBJECT); + } + } + + + *pString = objectHeader->stringRep; + objectHeader->stringRep = NULL; + +cleanup: + if (objectHeader) { + PKIX_DECREF(objectHeader->stringRep); + } + PKIX_DECREF(objectString); + + PKIX_RETURN(OBJECT); +} + +/* + * FUNCTION: PKIX_PL_Object_InvalidateCache (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_Object_InvalidateCache( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_PL_Object *objectHeader = NULL; + + PKIX_ENTER(OBJECT, "PKIX_PL_Object_InvalidateCache"); + PKIX_NULLCHECK_ONE(object); + + /* Shift pointer from user data to object header */ + PKIX_CHECK(pkix_pl_Object_GetHeader(object, &objectHeader, plContext), + PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT); + + PKIX_CHECK(pkix_LockObject(object, plContext), + PKIX_ERRORLOCKINGOBJECT); + + /* invalidate hashcode */ + objectHeader->hashcode = 0; + objectHeader->hashcodeCached = PKIX_FALSE; + + PKIX_DECREF(objectHeader->stringRep); + + PKIX_CHECK(pkix_UnlockObject(object, plContext), + PKIX_ERRORUNLOCKINGOBJECT); + +cleanup: + + PKIX_RETURN(OBJECT); +} + +/* + * FUNCTION: PKIX_PL_Object_Compare (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_Object_Compare( + PKIX_PL_Object *firstObject, + PKIX_PL_Object *secondObject, + PKIX_Int32 *pResult, + void *plContext) +{ + PKIX_PL_Object *firstObjectHeader = NULL; + PKIX_PL_Object *secondObjectHeader = NULL; + PKIX_PL_ComparatorCallback func = NULL; + pkix_ClassTable_Entry entry; + PKIX_UInt32 objType; + + PKIX_ENTER(OBJECT, "PKIX_PL_Object_Compare"); + PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); + + /* Shift pointer from user data to object header */ + PKIX_CHECK(pkix_pl_Object_GetHeader + (firstObject, &firstObjectHeader, plContext), + PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT); + + /* Shift pointer from user data to object header */ + PKIX_CHECK(pkix_pl_Object_GetHeader + (secondObject, &secondObjectHeader, plContext), + PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT); + + objType = firstObjectHeader->type; + + if (objType >= PKIX_NUMTYPES){ +#ifdef PKIX_USER_OBJECT_TYPE + pkix_ClassTable_Entry *ctEntry = NULL; + + PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n"); + PR_Lock(classTableLock); + pkixErrorResult = pkix_pl_PrimHashTable_Lookup + (classTable, + (void *)&objType, + objType, + NULL, + (void **)&ctEntry, + plContext); + PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n"); + PR_Unlock(classTableLock); + if (pkixErrorResult){ + PKIX_ERROR_FATAL(PKIX_ERRORGETTINGCLASSTABLEENTRY); + } + + if ((ctEntry == NULL) || (ctEntry->comparator == NULL)) { + PKIX_ERROR_FATAL(PKIX_UNDEFINEDCOMPARATOR); + } + + func = ctEntry->comparator; +#else + PORT_Assert (0); + pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE; + pkixErrorClass = PKIX_FATAL_ERROR; + goto cleanup; +#endif /* PKIX_USER_OBJECT_TYPE */ + } else { + /* special handling for system types */ + entry = systemClasses[objType]; + func = entry.comparator; + if (!func){ + PKIX_ERROR(PKIX_UNDEFINEDCOMPARATOR); + } + } + + PKIX_CHECK(func(firstObject, secondObject, pResult, plContext), + PKIX_OBJECTSPECIFICFUNCTIONFAILED); + +cleanup: + + PKIX_RETURN(OBJECT); +} + +/* + * FUNCTION: PKIX_PL_Object_Lock (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_Object_Lock( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_ENTER(OBJECT, "PKIX_PL_Object_Lock"); + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_LockObject(object, plContext), + PKIX_LOCKOBJECTFAILED); + +cleanup: + + PKIX_RETURN(OBJECT); +} + +/* + * FUNCTION: PKIX_PL_Object_Unlock (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_Object_Unlock( + PKIX_PL_Object *object, + void *plContext) +{ + PKIX_ENTER(OBJECT, "PKIX_PL_Object_Unlock"); + PKIX_NULLCHECK_ONE(object); + + PKIX_CHECK(pkix_UnlockObject(object, plContext), + PKIX_UNLOCKOBJECTFAILED); + +cleanup: + + PKIX_RETURN(OBJECT); +} + + +/* + * FUNCTION: PKIX_PL_Object_GetType (see comments in pkix_pl_system.h) + */ +PKIX_Error * +PKIX_PL_Object_GetType( + PKIX_PL_Object *object, + PKIX_UInt32 *pType, + void *plContext) +{ + PKIX_PL_Object *objectHeader = NULL; + + PKIX_ENTER(OBJECT, "PKIX_PL_Object_GetType"); + PKIX_NULLCHECK_TWO(object, pType); + + /* Shift pointer from user data to object header */ + PKIX_CHECK(pkix_pl_Object_GetHeader(object, &objectHeader, plContext), + PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT); + + *pType = objectHeader->type; + +cleanup: + + PKIX_RETURN(OBJECT); +} |