michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: /* michael@0: * pkix_error.c michael@0: * michael@0: * Error Object Functions michael@0: * michael@0: */ michael@0: michael@0: #include "pkix_error.h" michael@0: michael@0: #undef PKIX_ERRORENTRY michael@0: michael@0: #define PKIX_ERRORENTRY(name,desc,nsserr) #desc michael@0: michael@0: #if defined PKIX_ERROR_DESCRIPTION michael@0: michael@0: const char * const PKIX_ErrorText[] = michael@0: { michael@0: #include "pkix_errorstrings.h" michael@0: }; michael@0: michael@0: #else michael@0: michael@0: #include "prprf.h" michael@0: michael@0: #endif /* PKIX_ERROR_DESCRIPTION */ michael@0: michael@0: extern const PKIX_Int32 PKIX_PLErrorIndex[]; michael@0: michael@0: /* --Private-Functions-------------------------------------------- */ michael@0: michael@0: /* michael@0: * FUNCTION: pkix_Error_Equals michael@0: * (see comments for PKIX_PL_EqualsCallback in pkix_pl_system.h) michael@0: */ michael@0: static PKIX_Error * michael@0: pkix_Error_Equals( michael@0: PKIX_PL_Object *firstObject, michael@0: PKIX_PL_Object *secondObject, michael@0: PKIX_Boolean *pResult, michael@0: void *plContext) michael@0: { michael@0: PKIX_Error *firstError = NULL; michael@0: PKIX_Error *secondError = NULL; michael@0: PKIX_Error *firstCause = NULL; michael@0: PKIX_Error *secondCause = NULL; michael@0: PKIX_PL_Object *firstInfo = NULL; michael@0: PKIX_PL_Object *secondInfo = NULL; michael@0: PKIX_ERRORCLASS firstClass, secondClass; michael@0: PKIX_UInt32 secondType; michael@0: PKIX_Boolean boolResult, unequalFlag; michael@0: michael@0: PKIX_ENTER(ERROR, "pkix_Error_Equals"); michael@0: PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); michael@0: michael@0: unequalFlag = PKIX_FALSE; michael@0: michael@0: /* First just compare pointer values to save time */ michael@0: if (firstObject == secondObject) { michael@0: *pResult = PKIX_TRUE; michael@0: goto cleanup; michael@0: } else { michael@0: /* Result will only be set to true if all tests pass */ michael@0: *pResult = PKIX_FALSE; michael@0: } michael@0: michael@0: PKIX_CHECK(pkix_CheckType(firstObject, PKIX_ERROR_TYPE, plContext), michael@0: PKIX_FIRSTOBJECTNOTANERROROBJECT); michael@0: michael@0: PKIX_CHECK(PKIX_PL_Object_GetType michael@0: (secondObject, &secondType, plContext), michael@0: PKIX_ERRORGETTINGSECONDOBJECTTYPE); michael@0: michael@0: /* If types differ, then return false. Result is already set */ michael@0: if (secondType != PKIX_ERROR_TYPE) goto cleanup; michael@0: michael@0: /* It is safe to cast to PKIX_Error */ michael@0: firstError = (PKIX_Error *) firstObject; michael@0: secondError = (PKIX_Error *) secondObject; michael@0: michael@0: /* Compare error codes */ michael@0: firstClass = firstError->errClass; michael@0: secondClass = secondError->errClass; michael@0: michael@0: /* If codes differ, return false. Result is already set */ michael@0: if (firstClass != secondClass) goto cleanup; michael@0: michael@0: /* Compare causes */ michael@0: firstCause = firstError->cause; michael@0: secondCause = secondError->cause; michael@0: michael@0: /* Ensure that either both or none of the causes are NULL */ michael@0: if (((firstCause != NULL) && (secondCause == NULL))|| michael@0: ((firstCause == NULL) && (secondCause != NULL))) michael@0: unequalFlag = PKIX_TRUE; michael@0: michael@0: if ((firstCause != NULL) && (secondCause != NULL)) { michael@0: PKIX_CHECK(PKIX_PL_Object_Equals michael@0: ((PKIX_PL_Object*)firstCause, michael@0: (PKIX_PL_Object*)secondCause, michael@0: &boolResult, michael@0: plContext), michael@0: PKIX_ERRORINRECURSIVEEQUALSCALL); michael@0: michael@0: /* Set the unequalFlag so that we return after dec refing */ michael@0: if (boolResult == 0) unequalFlag = PKIX_TRUE; michael@0: } michael@0: michael@0: /* If the cause errors are not equal, return null */ michael@0: if (unequalFlag) goto cleanup; michael@0: michael@0: /* Compare info fields */ michael@0: firstInfo = firstError->info; michael@0: secondInfo = secondError->info; michael@0: michael@0: if (firstInfo != secondInfo) goto cleanup; michael@0: michael@0: /* Ensure that either both or none of the infos are NULL */ michael@0: if (((firstInfo != NULL) && (secondInfo == NULL))|| michael@0: ((firstInfo == NULL) && (secondInfo != NULL))) michael@0: unequalFlag = PKIX_TRUE; michael@0: michael@0: if ((firstInfo != NULL) && (secondInfo != NULL)) { michael@0: michael@0: PKIX_CHECK(PKIX_PL_Object_Equals michael@0: ((PKIX_PL_Object*)firstInfo, michael@0: (PKIX_PL_Object*)secondInfo, michael@0: &boolResult, michael@0: plContext), michael@0: PKIX_ERRORINRECURSIVEEQUALSCALL); michael@0: michael@0: /* Set the unequalFlag so that we return after dec refing */ michael@0: if (boolResult == 0) unequalFlag = PKIX_TRUE; michael@0: } michael@0: michael@0: /* If the infos are not equal, return null */ michael@0: if (unequalFlag) goto cleanup; michael@0: michael@0: michael@0: /* Compare descs */ michael@0: if (firstError->errCode != secondError->errCode) { michael@0: unequalFlag = PKIX_TRUE; michael@0: } michael@0: michael@0: if (firstError->plErr != secondError->plErr) { michael@0: unequalFlag = PKIX_TRUE; michael@0: } michael@0: michael@0: /* If the unequalFlag was set, return false */ michael@0: if (unequalFlag) goto cleanup; michael@0: michael@0: /* Errors are equal in all fields at this point */ michael@0: *pResult = PKIX_TRUE; michael@0: michael@0: cleanup: michael@0: michael@0: PKIX_RETURN(ERROR); michael@0: } michael@0: michael@0: /* michael@0: * FUNCTION: pkix_Error_Destroy michael@0: * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) michael@0: */ michael@0: static PKIX_Error * michael@0: pkix_Error_Destroy( michael@0: PKIX_PL_Object *object, michael@0: void *plContext) michael@0: { michael@0: PKIX_Error *error = NULL; michael@0: michael@0: PKIX_ENTER(ERROR, "pkix_Error_Destroy"); michael@0: PKIX_NULLCHECK_ONE(object); michael@0: michael@0: PKIX_CHECK(pkix_CheckType(object, PKIX_ERROR_TYPE, plContext), michael@0: PKIX_OBJECTNOTANERROR); michael@0: michael@0: error = (PKIX_Error *)object; michael@0: michael@0: PKIX_DECREF(error->cause); michael@0: michael@0: PKIX_DECREF(error->info); michael@0: michael@0: cleanup: michael@0: michael@0: PKIX_RETURN(ERROR); michael@0: } michael@0: michael@0: michael@0: /* XXX This is not thread safe */ michael@0: static PKIX_UInt32 pkix_error_cause_depth = 1; michael@0: michael@0: /* michael@0: * FUNCTION: pkix_Error_ToString michael@0: * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h) michael@0: */ michael@0: static PKIX_Error * michael@0: pkix_Error_ToString( michael@0: PKIX_PL_Object *object, michael@0: PKIX_PL_String **pString, michael@0: void *plContext) michael@0: { michael@0: PKIX_Error *error = NULL; michael@0: PKIX_Error *cause = NULL; michael@0: PKIX_PL_String *desc = NULL; michael@0: PKIX_PL_String *formatString = NULL; michael@0: PKIX_PL_String *causeString = NULL; michael@0: PKIX_PL_String *optCauseString = NULL; michael@0: PKIX_PL_String *errorNameString = NULL; michael@0: char *format = NULL; michael@0: PKIX_ERRORCLASS errClass; michael@0: michael@0: PKIX_ENTER(ERROR, "pkix_Error_ToString"); michael@0: PKIX_NULLCHECK_TWO(object, pString); michael@0: michael@0: PKIX_CHECK(pkix_CheckType(object, PKIX_ERROR_TYPE, plContext), michael@0: PKIX_OBJECTNOTANERROR); michael@0: michael@0: error = (PKIX_Error *)object; michael@0: michael@0: /* Get this error's errClass, description and the string of its cause */ michael@0: errClass = error->errClass; michael@0: michael@0: /* Get the description string */ michael@0: PKIX_Error_GetDescription(error, &desc, plContext); michael@0: michael@0: /* Get the cause */ michael@0: cause = error->cause; michael@0: michael@0: /* Get the causes's description string */ michael@0: if (cause != NULL) { michael@0: pkix_error_cause_depth++; michael@0: michael@0: /* Get the cause string */ michael@0: PKIX_CHECK(PKIX_PL_Object_ToString michael@0: ((PKIX_PL_Object*)cause, &causeString, plContext), michael@0: PKIX_ERRORGETTINGCAUSESTRING); michael@0: michael@0: format = "\n*** Cause (%d): %s"; michael@0: michael@0: PKIX_CHECK(PKIX_PL_String_Create michael@0: (PKIX_ESCASCII, michael@0: format, michael@0: 0, michael@0: &formatString, michael@0: plContext), michael@0: PKIX_STRINGCREATEFAILED); michael@0: michael@0: /* Create the optional Cause String */ michael@0: PKIX_CHECK(PKIX_PL_Sprintf michael@0: (&optCauseString, michael@0: plContext, michael@0: formatString, michael@0: pkix_error_cause_depth, michael@0: causeString), michael@0: PKIX_SPRINTFFAILED); michael@0: michael@0: PKIX_DECREF(formatString); michael@0: michael@0: pkix_error_cause_depth--; michael@0: } michael@0: michael@0: /* Create the Format String */ michael@0: if (optCauseString != NULL) { michael@0: format = "*** %s Error- %s%s"; michael@0: } else { michael@0: format = "*** %s Error- %s"; michael@0: } michael@0: michael@0: /* Ensure that error errClass is known, otherwise default to Object */ michael@0: if (errClass >= PKIX_NUMERRORCLASSES) { michael@0: errClass = 0; michael@0: } michael@0: michael@0: PKIX_CHECK(PKIX_PL_String_Create michael@0: (PKIX_ESCASCII, michael@0: (void *)PKIX_ERRORCLASSNAMES[errClass], michael@0: 0, michael@0: &errorNameString, michael@0: plContext), michael@0: PKIX_STRINGCREATEFAILED); michael@0: michael@0: PKIX_CHECK(PKIX_PL_String_Create michael@0: (PKIX_ESCASCII, michael@0: format, michael@0: 0, michael@0: &formatString, michael@0: plContext), michael@0: PKIX_STRINGCREATEFAILED); michael@0: michael@0: /* Create the output String */ michael@0: PKIX_CHECK(PKIX_PL_Sprintf michael@0: (pString, michael@0: plContext, michael@0: formatString, michael@0: errorNameString, michael@0: desc, michael@0: optCauseString), michael@0: PKIX_SPRINTFFAILED); michael@0: michael@0: cleanup: michael@0: michael@0: PKIX_DECREF(desc); michael@0: PKIX_DECREF(causeString); michael@0: PKIX_DECREF(formatString); michael@0: PKIX_DECREF(optCauseString); michael@0: PKIX_DECREF(errorNameString); michael@0: michael@0: PKIX_RETURN(ERROR); michael@0: } michael@0: michael@0: /* michael@0: * FUNCTION: pkix_Error_Hashcode michael@0: * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) michael@0: */ michael@0: static PKIX_Error * michael@0: pkix_Error_Hashcode( michael@0: PKIX_PL_Object *object, michael@0: PKIX_UInt32 *pResult, michael@0: void *plContext) michael@0: { michael@0: PKIX_ENTER(ERROR, "pkix_Error_Hashcode"); michael@0: PKIX_NULLCHECK_TWO(object, pResult); michael@0: michael@0: /* XXX Unimplemented */ michael@0: /* XXX Need to make hashcodes equal when two errors are equal */ michael@0: *pResult = (PKIX_UInt32)object; michael@0: michael@0: PKIX_RETURN(ERROR); michael@0: } michael@0: michael@0: /* --Initializers------------------------------------------------- */ michael@0: michael@0: /* michael@0: * PKIX_ERRORCLASSNAMES is an array of strings, with each string holding a michael@0: * descriptive name for an error errClass. This is used by the default michael@0: * PKIX_PL_Error_ToString function. michael@0: * michael@0: * Note: PKIX_ERRORCLASSES is defined in pkixt.h as a list of error types. michael@0: * (More precisely, as a list of invocations of ERRMACRO(type).) The michael@0: * macro is expanded in pkixt.h to define error numbers, and here to michael@0: * provide corresponding strings. For example, since the fifth ERRMACRO michael@0: * entry is MUTEX, then PKIX_MUTEX_ERROR is defined in pkixt.h as 4, and michael@0: * PKIX_ERRORCLASSNAMES[4] is initialized here with the value "MUTEX". michael@0: */ michael@0: #undef ERRMACRO michael@0: #define ERRMACRO(type) #type michael@0: michael@0: const char * michael@0: PKIX_ERRORCLASSNAMES[PKIX_NUMERRORCLASSES] = michael@0: { michael@0: PKIX_ERRORCLASSES michael@0: }; michael@0: michael@0: /* michael@0: * FUNCTION: pkix_Error_RegisterSelf michael@0: * DESCRIPTION: michael@0: * Registers PKIX_ERROR_TYPE and its related functions with systemClasses[] michael@0: * THREAD SAFETY: michael@0: * Not Thread Safe - for performance and complexity reasons michael@0: * michael@0: * Since this function is only called by PKIX_PL_Initialize, which should michael@0: * only be called once, it is acceptable that this function is not michael@0: * thread-safe. michael@0: */ michael@0: PKIX_Error * michael@0: pkix_Error_RegisterSelf(void *plContext) michael@0: { michael@0: extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; michael@0: pkix_ClassTable_Entry entry; michael@0: michael@0: PKIX_ENTER(ERROR, "pkix_Error_RegisterSelf"); michael@0: michael@0: entry.description = "Error"; michael@0: entry.objCounter = 0; michael@0: entry.typeObjectSize = sizeof(PKIX_Error); michael@0: entry.destructor = pkix_Error_Destroy; michael@0: entry.equalsFunction = pkix_Error_Equals; michael@0: entry.hashcodeFunction = pkix_Error_Hashcode; michael@0: entry.toStringFunction = pkix_Error_ToString; michael@0: entry.comparator = NULL; michael@0: entry.duplicateFunction = pkix_duplicateImmutable; michael@0: michael@0: systemClasses[PKIX_ERROR_TYPE] = entry; michael@0: michael@0: PKIX_RETURN(ERROR); michael@0: } michael@0: michael@0: /* --Public-Functions--------------------------------------------- */ michael@0: michael@0: /* michael@0: * FUNCTION: PKIX_Error_Create (see comments in pkix_util.h) michael@0: */ michael@0: PKIX_Error * michael@0: PKIX_Error_Create( michael@0: PKIX_ERRORCLASS errClass, michael@0: PKIX_Error *cause, michael@0: PKIX_PL_Object *info, michael@0: PKIX_ERRORCODE errCode, michael@0: PKIX_Error **pError, michael@0: void *plContext) michael@0: { michael@0: PKIX_Error *tempCause = NULL; michael@0: PKIX_Error *error = NULL; michael@0: michael@0: PKIX_ENTER(ERROR, "PKIX_Error_Create"); michael@0: michael@0: PKIX_NULLCHECK_ONE(pError); michael@0: michael@0: /* michael@0: * when called here, if PKIX_PL_Object_Alloc returns an error, michael@0: * it must be a PKIX_ALLOC_ERROR michael@0: */ michael@0: pkixErrorResult = PKIX_PL_Object_Alloc michael@0: (PKIX_ERROR_TYPE, michael@0: ((PKIX_UInt32)(sizeof (PKIX_Error))), michael@0: (PKIX_PL_Object **)&error, michael@0: plContext); michael@0: michael@0: if (pkixErrorResult) return (pkixErrorResult); michael@0: michael@0: error->errClass = errClass; michael@0: michael@0: /* Ensure we don't have a loop. Follow causes until NULL */ michael@0: for (tempCause = cause; michael@0: tempCause != NULL; michael@0: tempCause = tempCause->cause) { michael@0: /* If we detect a loop, throw a new error */ michael@0: if (tempCause == error) { michael@0: PKIX_ERROR(PKIX_LOOPOFERRORCAUSEDETECTED); michael@0: } michael@0: } michael@0: michael@0: PKIX_INCREF(cause); michael@0: error->cause = cause; michael@0: michael@0: PKIX_INCREF(info); michael@0: error->info = info; michael@0: michael@0: error->errCode = errCode; michael@0: michael@0: error->plErr = PKIX_PLErrorIndex[error->errCode]; michael@0: michael@0: *pError = error; michael@0: error = NULL; michael@0: michael@0: cleanup: michael@0: /* PKIX-XXX Fix for leak during error creation */ michael@0: PKIX_DECREF(error); michael@0: michael@0: PKIX_RETURN(ERROR); michael@0: } michael@0: michael@0: /* michael@0: * FUNCTION: PKIX_Error_GetErrorClass (see comments in pkix_util.h) michael@0: */ michael@0: PKIX_Error * michael@0: PKIX_Error_GetErrorClass( michael@0: PKIX_Error *error, michael@0: PKIX_ERRORCLASS *pClass, michael@0: void *plContext) michael@0: { michael@0: PKIX_ENTER(ERROR, "PKIX_Error_GetErrorClass"); michael@0: PKIX_NULLCHECK_TWO(error, pClass); michael@0: michael@0: *pClass = error->errClass; michael@0: michael@0: PKIX_RETURN(ERROR); michael@0: } michael@0: michael@0: /* michael@0: * FUNCTION: PKIX_Error_GetErrorCode (see comments in pkix_util.h) michael@0: */ michael@0: PKIX_Error * michael@0: PKIX_Error_GetErrorCode( michael@0: PKIX_Error *error, michael@0: PKIX_ERRORCODE *pCode, michael@0: void *plContext) michael@0: { michael@0: PKIX_ENTER(ERROR, "PKIX_Error_GetErrorCode"); michael@0: PKIX_NULLCHECK_TWO(error, pCode); michael@0: michael@0: *pCode = error->errCode; michael@0: michael@0: PKIX_RETURN(ERROR); michael@0: } michael@0: michael@0: /* michael@0: * FUNCTION: PKIX_Error_GetCause (see comments in pkix_util.h) michael@0: */ michael@0: PKIX_Error * michael@0: PKIX_Error_GetCause( michael@0: PKIX_Error *error, michael@0: PKIX_Error **pCause, michael@0: void *plContext) michael@0: { michael@0: PKIX_ENTER(ERROR, "PKIX_Error_GetCause"); michael@0: PKIX_NULLCHECK_TWO(error, pCause); michael@0: michael@0: if (error->cause != PKIX_ALLOC_ERROR()){ michael@0: PKIX_INCREF(error->cause); michael@0: } michael@0: michael@0: *pCause = error->cause; michael@0: michael@0: cleanup: michael@0: PKIX_RETURN(ERROR); michael@0: } michael@0: michael@0: /* michael@0: * FUNCTION: PKIX_Error_GetSupplementaryInfo (see comments in pkix_util.h) michael@0: */ michael@0: PKIX_Error * michael@0: PKIX_Error_GetSupplementaryInfo( michael@0: PKIX_Error *error, michael@0: PKIX_PL_Object **pInfo, michael@0: void *plContext) michael@0: { michael@0: PKIX_ENTER(ERROR, "PKIX_Error_GetSupplementaryInfo"); michael@0: PKIX_NULLCHECK_TWO(error, pInfo); michael@0: michael@0: PKIX_INCREF(error->info); michael@0: michael@0: *pInfo = error->info; michael@0: michael@0: cleanup: michael@0: PKIX_RETURN(ERROR); michael@0: } michael@0: michael@0: /* michael@0: * FUNCTION: PKIX_Error_GetDescription (see comments in pkix_util.h) michael@0: */ michael@0: PKIX_Error * michael@0: PKIX_Error_GetDescription( michael@0: PKIX_Error *error, michael@0: PKIX_PL_String **pDesc, michael@0: void *plContext) michael@0: { michael@0: PKIX_PL_String *descString = NULL; michael@0: #ifndef PKIX_ERROR_DESCRIPTION michael@0: char errorStr[32]; michael@0: #endif michael@0: michael@0: PKIX_ENTER(ERROR, "PKIX_Error_GetDescription"); michael@0: PKIX_NULLCHECK_TWO(error, pDesc); michael@0: michael@0: #ifndef PKIX_ERROR_DESCRIPTION michael@0: PR_snprintf(errorStr, 32, "Error code: %d", error->errCode); michael@0: #endif michael@0: michael@0: PKIX_PL_String_Create(PKIX_ESCASCII, michael@0: #if defined PKIX_ERROR_DESCRIPTION michael@0: (void *)PKIX_ErrorText[error->errCode], michael@0: #else michael@0: errorStr, michael@0: #endif michael@0: 0, michael@0: &descString, michael@0: plContext); michael@0: michael@0: *pDesc = descString; michael@0: michael@0: PKIX_RETURN(ERROR); michael@0: }