| /* 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_logger.c |
| * |
| * Logger Object Functions |
| * |
| */ |
| |
| #include "pkix_logger.h" |
| #ifndef PKIX_ERROR_DESCRIPTION |
| #include "prprf.h" |
| #endif |
| |
| /* Global variable to keep PKIX_Logger List */ |
| PKIX_List *pkixLoggers = NULL; |
| |
| /* |
| * Once the Logger has been set, for any logging related operations, we have |
| * to go through the List to find a match, and if found, issue the |
| * corresponding callback. The overhead to check for DEBUG and TRACE in each |
| * PKIX function entering and exiting is very expensive (400X), and redundant |
| * if they are not the interest of the Logger. Therefore, the PKIX_Logger List |
| * pkixLoggers is separated into two lists based on its Loggers' trace level. |
| * |
| * Whenever the pkixLoggers List is updated by PKIX_Logger_AddLogger() or |
| * PKIX_Logger_SetLoggers(), we destroy and reconstruct pkixLoggersErrors |
| * and pkixLoggersDebugTrace Logger Lists. The ERROR, FATAL_ERROR and |
| * WARNING goes to pkixLoggersErrors and the DEBUG and TRACE goes to |
| * pkixLoggersDebugTrace. |
| * |
| * Currently we provide five logging levels and the default setting are by: |
| * |
| * PKIX_FATAL_ERROR() macro invokes pkix_Logger_Check of FATAL_ERROR level |
| * PKIX_ERROR() macro invokes pkix_Logger_Check of ERROR level |
| * WARNING is not invoked as default |
| * PKIX_DEBUG() macro invokes pkix_Logger_Check of DEBUG level. This needs |
| * compilation -DPKIX_<component>DEBUG flag to turn on |
| * PKIX_ENTER() and PKIX_RETURN() macros invoke pkix_Logger_Check of TRACE |
| * level. TRACE provides duplicate information of DEBUG, but needs no |
| * recompilation and cannot choose component. To allow application |
| * to use DEBUG level, TRACE is put as last. |
| * |
| */ |
| PKIX_List *pkixLoggersErrors = NULL; |
| PKIX_List *pkixLoggersDebugTrace = NULL; |
| |
| /* To ensure atomic update on pkixLoggers lists */ |
| PKIX_PL_MonitorLock *pkixLoggerLock = NULL; |
| |
| /* --Private-Functions-------------------------------------------- */ |
| |
| /* |
| * FUNCTION: pkix_Logger_CheckErrors |
| * DESCRIPTION: |
| * |
| * This function goes through each PKIX_Logger at "pkixLoggersList" and |
| * checks if "maxLevel" and "logComponent" satisfies what is specified in the |
| * PKIX_Logger. If satisfies, it invokes the callback in PKIX_Logger and |
| * passes a PKIX_PL_String that is the concatenation of "message" and |
| * "message2" to the application for processing. |
| * Since this call is inserted into a handful of PKIX macros, no macros are |
| * applied in this function, to avoid infinite recursion. |
| * If an error occurs, this call is aborted. |
| * |
| * PARAMETERS: |
| * "pkixLoggersList" |
| * A list of PKIX_Loggers to be examined for invoking callback. Must be |
| * non-NULL. |
| * "message" |
| * Address of "message" to be logged. Must be non-NULL. |
| * "message2" |
| * Address of "message2" to be concatenated and logged. May be NULL. |
| * "logComponent" |
| * A PKIX_UInt32 that indicates the component the message is from. |
| * "maxLevel" |
| * A PKIX_UInt32 that represents the level of severity of the message. |
| * "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 |
| */ |
| PKIX_Error * |
| pkix_Logger_Check( |
| PKIX_List *pkixLoggersList, |
| const char *message, |
| const char *message2, |
| PKIX_ERRORCLASS logComponent, |
| PKIX_UInt32 currentLevel, |
| void *plContext) |
| { |
| PKIX_Logger *logger = NULL; |
| PKIX_List *savedPkixLoggersErrors = NULL; |
| PKIX_List *savedPkixLoggersDebugTrace = NULL; |
| PKIX_PL_String *formatString = NULL; |
| PKIX_PL_String *messageString = NULL; |
| PKIX_PL_String *message2String = NULL; |
| PKIX_PL_String *msgString = NULL; |
| PKIX_Error *error = NULL; |
| PKIX_Boolean needLogging = PKIX_FALSE; |
| PKIX_UInt32 i, length; |
| |
| /* |
| * We cannot use any the PKIX_ macros here, since this function is |
| * called from some of these macros. It can create infinite recursion. |
| */ |
| |
| if ((pkixLoggersList == NULL) || (message == NULL)) { |
| return(NULL); |
| } |
| |
| /* |
| * Disable all subsequent loggings to avoid recursion. The result is |
| * if other thread is calling this function at the same time, there |
| * won't be any logging because the pkixLoggersErrors and |
| * pkixLoggersDebugTrace are set to null. |
| * It would be nice if we provide control per thread (e.g. make |
| * plContext threadable) then we can avoid the recursion by setting |
| * flag at plContext. Then other thread's logging won't be affected. |
| * |
| * Also we need to use a reentrant Lock. Although we avoid recursion |
| * for TRACE. When there is an ERROR occurs in subsequent call, this |
| * function will be called. |
| */ |
| |
| error = PKIX_PL_MonitorLock_Enter(pkixLoggerLock, plContext); |
| if (error) { return(NULL); } |
| |
| savedPkixLoggersDebugTrace = pkixLoggersDebugTrace; |
| pkixLoggersDebugTrace = NULL; |
| savedPkixLoggersErrors = pkixLoggersErrors; |
| pkixLoggersErrors = NULL; |
| |
| /* Convert message and message2 to String */ |
| error = PKIX_PL_String_Create |
| (PKIX_ESCASCII, message, 0, &messageString, plContext); |
| if (error) { goto cleanup; } |
| |
| if (message2) { |
| error = PKIX_PL_String_Create |
| (PKIX_ESCASCII, message2, 0, &message2String, plContext); |
| if (error) { goto cleanup; } |
| error = PKIX_PL_String_Create |
| (PKIX_ESCASCII, "%s %s", 0, &formatString, plContext); |
| if (error) { goto cleanup; } |
| |
| } else { |
| error = PKIX_PL_String_Create |
| (PKIX_ESCASCII, "%s", 0, &formatString, plContext); |
| if (error) { goto cleanup; } |
| |
| } |
| |
| error = PKIX_PL_Sprintf |
| (&msgString, |
| plContext, |
| formatString, |
| messageString, |
| message2String); |
| if (error) { goto cleanup; } |
| |
| /* Go through the Logger list */ |
| |
| error = PKIX_List_GetLength(pkixLoggersList, &length, plContext); |
| if (error) { goto cleanup; } |
| |
| for (i = 0; i < length; i++) { |
| |
| error = PKIX_List_GetItem |
| (pkixLoggersList, |
| i, |
| (PKIX_PL_Object **) &logger, |
| plContext); |
| if (error) { goto cleanup; } |
| |
| /* Intended logging level less or equal than the max */ |
| needLogging = (currentLevel <= logger->maxLevel); |
| |
| if (needLogging && (logger->callback)) { |
| |
| /* |
| * We separate Logger into two lists based on log level |
| * but log level is not modified. We need to check here to |
| * avoid logging the higher log level (lower value) twice. |
| */ |
| if (pkixLoggersList == pkixLoggersErrors) { |
| needLogging = needLogging && |
| (currentLevel <= PKIX_LOGGER_LEVEL_WARNING); |
| } else if (pkixLoggersList == pkixLoggersDebugTrace) { |
| needLogging = needLogging && |
| (currentLevel > PKIX_LOGGER_LEVEL_WARNING); |
| } |
| |
| if (needLogging) { |
| if (logComponent == logger->logComponent) { |
| needLogging = PKIX_TRUE; |
| } else { |
| needLogging = PKIX_FALSE; |
| } |
| } |
| |
| if (needLogging) { |
| error = logger->callback |
| (logger, |
| msgString, |
| currentLevel, |
| logComponent, |
| plContext); |
| if (error) { goto cleanup; } |
| } |
| } |
| |
| error = PKIX_PL_Object_DecRef |
| ((PKIX_PL_Object *)logger, plContext); |
| logger = NULL; |
| if (error) { goto cleanup; } |
| |
| } |
| |
| cleanup: |
| |
| if (formatString) { |
| error = PKIX_PL_Object_DecRef |
| ((PKIX_PL_Object *)formatString, plContext); |
| } |
| |
| if (messageString) { |
| error = PKIX_PL_Object_DecRef |
| ((PKIX_PL_Object *)messageString, plContext); |
| } |
| |
| if (message2String) { |
| error = PKIX_PL_Object_DecRef |
| ((PKIX_PL_Object *)message2String, plContext); |
| } |
| |
| if (msgString) { |
| error = PKIX_PL_Object_DecRef |
| ((PKIX_PL_Object *)msgString, plContext); |
| } |
| |
| if (logger) { |
| error = PKIX_PL_Object_DecRef |
| ((PKIX_PL_Object *)logger, plContext); |
| } |
| |
| if (pkixLoggersErrors == NULL && savedPkixLoggersErrors != NULL) { |
| pkixLoggersErrors = savedPkixLoggersErrors; |
| } |
| |
| if (pkixLoggersDebugTrace == NULL && |
| savedPkixLoggersDebugTrace != NULL) { |
| pkixLoggersDebugTrace = savedPkixLoggersDebugTrace; |
| } |
| |
| error = PKIX_PL_MonitorLock_Exit(pkixLoggerLock, plContext); |
| if (error) { return(NULL); } |
| |
| return(NULL); |
| } |
| |
| PKIX_Error * |
| pkix_Logger_CheckWithCode( |
| PKIX_List *pkixLoggersList, |
| PKIX_UInt32 errorCode, |
| const char *message2, |
| PKIX_ERRORCLASS logComponent, |
| PKIX_UInt32 currentLevel, |
| void *plContext) |
| { |
| char error[32]; |
| char *errorString = NULL; |
| |
| PKIX_ENTER(LOGGER, "pkix_Logger_CheckWithCode"); |
| #if defined PKIX_ERROR_DESCRIPTION |
| errorString = PKIX_ErrorText[errorCode]; |
| #else |
| PR_snprintf(error, 32, "Error code: %d", errorCode); |
| errorString = error; |
| #endif /* PKIX_ERROR_DESCRIPTION */ |
| |
| pkixErrorResult = pkix_Logger_Check(pkixLoggersList, errorString, |
| message2, logComponent, |
| currentLevel, plContext); |
| PKIX_RETURN(LOGGER); |
| } |
| |
| /* |
| * FUNCTION: pkix_Logger_Destroy |
| * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) |
| */ |
| static PKIX_Error * |
| pkix_Logger_Destroy( |
| PKIX_PL_Object *object, |
| void *plContext) |
| { |
| PKIX_Logger *logger = NULL; |
| |
| PKIX_ENTER(LOGGER, "pkix_Logger_Destroy"); |
| PKIX_NULLCHECK_ONE(object); |
| |
| /* Check that this object is a logger */ |
| PKIX_CHECK(pkix_CheckType(object, PKIX_LOGGER_TYPE, plContext), |
| PKIX_OBJECTNOTLOGGER); |
| |
| logger = (PKIX_Logger *)object; |
| |
| /* We have a valid logger. DecRef its item and recurse on next */ |
| |
| logger->callback = NULL; |
| PKIX_DECREF(logger->context); |
| logger->logComponent = (PKIX_ERRORCLASS)0; |
| |
| cleanup: |
| |
| PKIX_RETURN(LOGGER); |
| } |
| |
| /* |
| * FUNCTION: pkix_Logger_ToString |
| * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h) |
| */ |
| static PKIX_Error * |
| pkix_Logger_ToString( |
| PKIX_PL_Object *object, |
| PKIX_PL_String **pString, |
| void *plContext) |
| { |
| PKIX_Logger *logger = NULL; |
| char *asciiFormat = NULL; |
| PKIX_PL_String *formatString = NULL; |
| PKIX_PL_String *contextString = NULL; |
| PKIX_PL_String *componentString = NULL; |
| PKIX_PL_String *loggerString = NULL; |
| |
| PKIX_ENTER(LOGGER, "pkix_Logger_ToString_Helper"); |
| PKIX_NULLCHECK_TWO(object, pString); |
| |
| /* Check that this object is a logger */ |
| PKIX_CHECK(pkix_CheckType(object, PKIX_LOGGER_TYPE, plContext), |
| PKIX_OBJECTNOTLOGGER); |
| |
| logger = (PKIX_Logger *)object; |
| |
| asciiFormat = |
| "[\n" |
| "\tLogger: \n" |
| "\tContext: %s\n" |
| "\tMaximum Level: %d\n" |
| "\tComponent Name: %s\n" |
| "]\n"; |
| |
| PKIX_CHECK(PKIX_PL_String_Create |
| (PKIX_ESCASCII, |
| asciiFormat, |
| 0, |
| &formatString, |
| plContext), |
| PKIX_STRINGCREATEFAILED); |
| |
| PKIX_TOSTRING(logger->context, &contextString, plContext, |
| PKIX_OBJECTTOSTRINGFAILED); |
| |
| PKIX_CHECK(PKIX_PL_String_Create |
| (PKIX_ESCASCII, |
| (void *)PKIX_ERRORCLASSNAMES[logger->logComponent], |
| 0, |
| &componentString, |
| plContext), |
| PKIX_STRINGCREATEFAILED); |
| |
| PKIX_CHECK(PKIX_PL_Sprintf |
| (&loggerString, |
| plContext, |
| formatString, |
| contextString, |
| logger->maxLevel, |
| componentString), |
| PKIX_SPRINTFFAILED); |
| |
| *pString = loggerString; |
| |
| cleanup: |
| |
| PKIX_DECREF(formatString); |
| PKIX_DECREF(contextString); |
| PKIX_RETURN(LOGGER); |
| } |
| |
| /* |
| * FUNCTION: pkix_Logger_Equals |
| * (see comments for PKIX_PL_EqualsCallback in pkix_pl_system.h) |
| */ |
| static PKIX_Error * |
| pkix_Logger_Equals( |
| PKIX_PL_Object *first, |
| PKIX_PL_Object *second, |
| PKIX_Boolean *pResult, |
| void *plContext) |
| { |
| PKIX_UInt32 secondType; |
| PKIX_Boolean cmpResult; |
| PKIX_Logger *firstLogger = NULL; |
| PKIX_Logger *secondLogger = NULL; |
| |
| PKIX_ENTER(LOGGER, "pkix_Logger_Equals"); |
| PKIX_NULLCHECK_THREE(first, second, pResult); |
| |
| /* test that first is a Logger */ |
| PKIX_CHECK(pkix_CheckType(first, PKIX_LOGGER_TYPE, plContext), |
| PKIX_FIRSTOBJECTNOTLOGGER); |
| |
| /* |
| * Since we know first is a Logger, if both references are |
| * identical, they must be equal |
| */ |
| if (first == second){ |
| *pResult = PKIX_TRUE; |
| goto cleanup; |
| } |
| |
| /* |
| * If second isn't a Logger, we don't throw an error. |
| * We simply return a Boolean result of FALSE |
| */ |
| *pResult = PKIX_FALSE; |
| PKIX_CHECK(PKIX_PL_Object_GetType(second, &secondType, plContext), |
| PKIX_COULDNOTGETTYPEOFSECONDARGUMENT); |
| if (secondType != PKIX_LOGGER_TYPE) goto cleanup; |
| |
| firstLogger = (PKIX_Logger *)first; |
| secondLogger = (PKIX_Logger *)second; |
| |
| cmpResult = PKIX_FALSE; |
| |
| if (firstLogger->callback != secondLogger->callback) { |
| goto cleanup; |
| } |
| |
| if (firstLogger->logComponent != secondLogger->logComponent) { |
| goto cleanup; |
| } |
| |
| PKIX_EQUALS |
| (firstLogger->context, |
| secondLogger->context, |
| &cmpResult, |
| plContext, |
| PKIX_OBJECTEQUALSFAILED); |
| |
| if (cmpResult == PKIX_FALSE) { |
| goto cleanup; |
| } |
| |
| if (firstLogger->maxLevel != secondLogger->maxLevel) { |
| goto cleanup; |
| } |
| |
| *pResult = cmpResult; |
| |
| cleanup: |
| |
| PKIX_RETURN(LOGGER); |
| } |
| |
| /* |
| * FUNCTION: pkix_Logger_Hashcode |
| * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) |
| */ |
| static PKIX_Error * |
| pkix_Logger_Hashcode( |
| PKIX_PL_Object *object, |
| PKIX_UInt32 *pHashcode, |
| void *plContext) |
| { |
| PKIX_Logger *logger = NULL; |
| PKIX_UInt32 hash = 0; |
| PKIX_UInt32 tempHash = 0; |
| |
| PKIX_ENTER(LOGGER, "pkix_Logger_Hashcode"); |
| PKIX_NULLCHECK_TWO(object, pHashcode); |
| |
| PKIX_CHECK(pkix_CheckType(object, PKIX_LOGGER_TYPE, plContext), |
| PKIX_OBJECTNOTLOGGER); |
| |
| logger = (PKIX_Logger *)object; |
| |
| PKIX_HASHCODE(logger->context, &tempHash, plContext, |
| PKIX_OBJECTHASHCODEFAILED); |
| |
| hash = (((((PKIX_UInt32)((char *)logger->callback - (char *)NULL) + tempHash) << 7) + |
| logger->maxLevel) << 7) + (PKIX_UInt32)logger->logComponent; |
| |
| *pHashcode = hash; |
| |
| cleanup: |
| |
| PKIX_RETURN(LOGGER); |
| } |
| |
| |
| /* |
| * FUNCTION: pkix_Logger_Duplicate |
| * (see comments for PKIX_PL_DuplicateCallback in pkix_pl_system.h) |
| */ |
| static PKIX_Error * |
| pkix_Logger_Duplicate( |
| PKIX_PL_Object *object, |
| PKIX_PL_Object **pNewObject, |
| void *plContext) |
| { |
| PKIX_Logger *logger = NULL; |
| PKIX_Logger *dupLogger = NULL; |
| |
| PKIX_ENTER(LOGGER, "pkix_Logger_Duplicate"); |
| PKIX_NULLCHECK_TWO(object, pNewObject); |
| |
| PKIX_CHECK(pkix_CheckType |
| ((PKIX_PL_Object *)object, PKIX_LOGGER_TYPE, plContext), |
| PKIX_OBJECTNOTLOGGER); |
| |
| logger = (PKIX_Logger *) object; |
| |
| PKIX_CHECK(PKIX_PL_Object_Alloc |
| (PKIX_LOGGER_TYPE, |
| sizeof (PKIX_Logger), |
| (PKIX_PL_Object **)&dupLogger, |
| plContext), |
| PKIX_COULDNOTCREATELOGGEROBJECT); |
| |
| dupLogger->callback = logger->callback; |
| dupLogger->maxLevel = logger->maxLevel; |
| |
| PKIX_DUPLICATE |
| (logger->context, |
| &dupLogger->context, |
| plContext, |
| PKIX_OBJECTDUPLICATEFAILED); |
| |
| dupLogger->logComponent = logger->logComponent; |
| |
| *pNewObject = (PKIX_PL_Object *) dupLogger; |
| |
| cleanup: |
| |
| if (PKIX_ERROR_RECEIVED){ |
| PKIX_DECREF(dupLogger); |
| } |
| |
| PKIX_RETURN(LOGGER); |
| } |
| |
| /* |
| * FUNCTION: pkix_Logger_RegisterSelf |
| * DESCRIPTION: |
| * Registers PKIX_LOGGER_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_Error * |
| pkix_Logger_RegisterSelf(void *plContext) |
| { |
| extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; |
| pkix_ClassTable_Entry entry; |
| |
| PKIX_ENTER(LOGGER, "pkix_Logger_RegisterSelf"); |
| |
| entry.description = "Logger"; |
| entry.objCounter = 0; |
| entry.typeObjectSize = sizeof(PKIX_Logger); |
| entry.destructor = pkix_Logger_Destroy; |
| entry.equalsFunction = pkix_Logger_Equals; |
| entry.hashcodeFunction = pkix_Logger_Hashcode; |
| entry.toStringFunction = pkix_Logger_ToString; |
| entry.comparator = NULL; |
| entry.duplicateFunction = pkix_Logger_Duplicate; |
| |
| systemClasses[PKIX_LOGGER_TYPE] = entry; |
| |
| PKIX_RETURN(LOGGER); |
| } |
| |
| /* --Public-Logger-Functions--------------------------------------------- */ |
| |
| /* |
| * FUNCTION: PKIX_Logger_Create (see comments in pkix_util.h) |
| */ |
| PKIX_Error * |
| PKIX_Logger_Create( |
| PKIX_Logger_LogCallback callback, |
| PKIX_PL_Object *loggerContext, |
| PKIX_Logger **pLogger, |
| void *plContext) |
| { |
| PKIX_Logger *logger = NULL; |
| |
| PKIX_ENTER(LOGGER, "PKIX_Logger_Create"); |
| PKIX_NULLCHECK_ONE(pLogger); |
| |
| PKIX_CHECK(PKIX_PL_Object_Alloc |
| (PKIX_LOGGER_TYPE, |
| sizeof (PKIX_Logger), |
| (PKIX_PL_Object **)&logger, |
| plContext), |
| PKIX_COULDNOTCREATELOGGEROBJECT); |
| |
| logger->callback = callback; |
| logger->maxLevel = 0; |
| logger->logComponent = (PKIX_ERRORCLASS)0; |
| |
| PKIX_INCREF(loggerContext); |
| logger->context = loggerContext; |
| |
| *pLogger = logger; |
| logger = NULL; |
| |
| cleanup: |
| |
| PKIX_DECREF(logger); |
| |
| PKIX_RETURN(LOGGER); |
| } |
| |
| /* |
| * FUNCTION: PKIX_Logger_GetLogCallback (see comments in pkix_util.h) |
| */ |
| PKIX_Error * |
| PKIX_Logger_GetLogCallback( |
| PKIX_Logger *logger, |
| PKIX_Logger_LogCallback *pCallback, |
| void *plContext) |
| { |
| PKIX_ENTER(LOGGER, "PKIX_Logger_GetLogCallback"); |
| PKIX_NULLCHECK_TWO(logger, pCallback); |
| |
| *pCallback = logger->callback; |
| |
| PKIX_RETURN(LOGGER); |
| } |
| |
| /* |
| * FUNCTION: PKIX_Logger_GetLoggerContext (see comments in pkix_util.h) |
| */ |
| PKIX_Error * |
| PKIX_Logger_GetLoggerContext( |
| PKIX_Logger *logger, |
| PKIX_PL_Object **pLoggerContext, |
| void *plContext) |
| { |
| PKIX_ENTER(LOGGER, "PKIX_Logger_GetLoggerContex"); |
| PKIX_NULLCHECK_TWO(logger, pLoggerContext); |
| |
| PKIX_INCREF(logger->context); |
| *pLoggerContext = logger->context; |
| |
| cleanup: |
| PKIX_RETURN(LOGGER); |
| } |
| |
| /* |
| * FUNCTION: PKIX_Logger_GetMaxLoggingLevel (see comments in pkix_util.h) |
| */ |
| PKIX_Error * |
| PKIX_Logger_GetMaxLoggingLevel( |
| PKIX_Logger *logger, |
| PKIX_UInt32 *pLevel, |
| void *plContext) |
| { |
| PKIX_ENTER(LOGGER, "PKIX_Logger_GetMaxLoggingLevel"); |
| PKIX_NULLCHECK_TWO(logger, pLevel); |
| |
| *pLevel = logger->maxLevel; |
| |
| PKIX_RETURN(LOGGER); |
| } |
| |
| /* |
| * FUNCTION: PKIX_Logger_SetMaxLoggingLevel (see comments in pkix_util.h) |
| */ |
| PKIX_Error * |
| PKIX_Logger_SetMaxLoggingLevel( |
| PKIX_Logger *logger, |
| PKIX_UInt32 level, |
| void *plContext) |
| { |
| PKIX_ENTER(LOGGER, "PKIX_Logger_SetMaxLoggingLevel"); |
| PKIX_NULLCHECK_ONE(logger); |
| |
| if (level > PKIX_LOGGER_LEVEL_MAX) { |
| PKIX_ERROR(PKIX_LOGGINGLEVELEXCEEDSMAXIMUM); |
| } else { |
| logger->maxLevel = level; |
| } |
| |
| cleanup: |
| |
| PKIX_RETURN(LOGGER); |
| } |
| |
| /* |
| * FUNCTION: PKIX_Logger_GetLoggingComponent (see comments in pkix_util.h) |
| */ |
| PKIX_Error * |
| PKIX_Logger_GetLoggingComponent( |
| PKIX_Logger *logger, |
| PKIX_ERRORCLASS *pComponent, |
| void *plContext) |
| { |
| PKIX_ENTER(LOGGER, "PKIX_Logger_GetLoggingComponent"); |
| PKIX_NULLCHECK_TWO(logger, pComponent); |
| |
| *pComponent = logger->logComponent; |
| |
| PKIX_RETURN(LOGGER); |
| } |
| |
| /* |
| * FUNCTION: PKIX_Logger_SetLoggingComponent (see comments in pkix_util.h) |
| */ |
| PKIX_Error * |
| PKIX_Logger_SetLoggingComponent( |
| PKIX_Logger *logger, |
| PKIX_ERRORCLASS component, |
| void *plContext) |
| { |
| PKIX_ENTER(LOGGER, "PKIX_Logger_SetLoggingComponent"); |
| PKIX_NULLCHECK_ONE(logger); |
| |
| logger->logComponent = component; |
| |
| PKIX_RETURN(LOGGER); |
| } |
| |
| |
| /* |
| * Following PKIX_GetLoggers(), PKIX_SetLoggers() and PKIX_AddLogger() are |
| * documented as not thread-safe. However they are thread-safe now. We need |
| * the lock when accessing the logger lists. |
| */ |
| |
| /* |
| * FUNCTION: PKIX_Logger_GetLoggers (see comments in pkix_util.h) |
| */ |
| PKIX_Error * |
| PKIX_GetLoggers( |
| PKIX_List **pLoggers, /* list of PKIX_Logger */ |
| void *plContext) |
| { |
| PKIX_List *list = NULL; |
| PKIX_List *savedPkixLoggersDebugTrace = NULL; |
| PKIX_List *savedPkixLoggersErrors = NULL; |
| PKIX_Logger *logger = NULL; |
| PKIX_Logger *dupLogger = NULL; |
| PKIX_UInt32 i, length; |
| PKIX_Boolean locked = PKIX_FALSE; |
| |
| PKIX_ENTER(LOGGER, "PKIX_Logger_GetLoggers"); |
| PKIX_NULLCHECK_ONE(pLoggers); |
| |
| PKIX_CHECK(PKIX_PL_MonitorLock_Enter(pkixLoggerLock, plContext), |
| PKIX_MONITORLOCKENTERFAILED); |
| locked = PKIX_TRUE; |
| |
| /* |
| * Temporarily disable DEBUG/TRACE Logging to avoid possible |
| * deadlock: |
| * When the Logger List is being accessed, e.g. by PKIX_ENTER or |
| * PKIX_DECREF, pkix_Logger_Check may check whether logging |
| * is requested, creating a deadlock situation. |
| */ |
| savedPkixLoggersDebugTrace = pkixLoggersDebugTrace; |
| pkixLoggersDebugTrace = NULL; |
| savedPkixLoggersErrors = pkixLoggersErrors; |
| pkixLoggersErrors = NULL; |
| |
| if (pkixLoggers == NULL) { |
| length = 0; |
| } else { |
| PKIX_CHECK(PKIX_List_GetLength |
| (pkixLoggers, &length, plContext), |
| PKIX_LISTGETLENGTHFAILED); |
| } |
| |
| /* Create a list and copy the pkixLoggers item to the list */ |
| PKIX_CHECK(PKIX_List_Create(&list, plContext), |
| PKIX_LISTCREATEFAILED); |
| |
| for (i = 0; i < length; i++) { |
| |
| PKIX_CHECK(PKIX_List_GetItem |
| (pkixLoggers, |
| i, |
| (PKIX_PL_Object **) &logger, |
| plContext), |
| PKIX_LISTGETITEMFAILED); |
| |
| PKIX_CHECK(pkix_Logger_Duplicate |
| ((PKIX_PL_Object *)logger, |
| (PKIX_PL_Object **)&dupLogger, |
| plContext), |
| PKIX_LOGGERDUPLICATEFAILED); |
| |
| PKIX_CHECK(PKIX_List_AppendItem |
| (list, |
| (PKIX_PL_Object *) dupLogger, |
| plContext), |
| PKIX_LISTAPPENDITEMFAILED); |
| |
| PKIX_DECREF(logger); |
| PKIX_DECREF(dupLogger); |
| } |
| |
| /* Set the list to be immutable */ |
| PKIX_CHECK(PKIX_List_SetImmutable(list, plContext), |
| PKIX_LISTSETIMMUTABLEFAILED); |
| |
| *pLoggers = list; |
| |
| cleanup: |
| |
| PKIX_DECREF(logger); |
| |
| /* Restore logging capability */ |
| pkixLoggersDebugTrace = savedPkixLoggersDebugTrace; |
| pkixLoggersErrors = savedPkixLoggersErrors; |
| |
| if (locked) { |
| PKIX_CHECK(PKIX_PL_MonitorLock_Exit(pkixLoggerLock, plContext), |
| PKIX_MONITORLOCKEXITFAILED); |
| } |
| |
| PKIX_RETURN(LOGGER); |
| } |
| |
| /* |
| * FUNCTION: PKIX_Logger_SetLoggers (see comments in pkix_util.h) |
| */ |
| PKIX_Error * |
| PKIX_SetLoggers( |
| PKIX_List *loggers, /* list of PKIX_Logger */ |
| void *plContext) |
| { |
| PKIX_List *list = NULL; |
| PKIX_List *savedPkixLoggersErrors = NULL; |
| PKIX_List *savedPkixLoggersDebugTrace = NULL; |
| PKIX_Logger *logger = NULL; |
| PKIX_Logger *dupLogger = NULL; |
| PKIX_Boolean locked = PKIX_FALSE; |
| PKIX_UInt32 i, length; |
| |
| PKIX_ENTER(LOGGER, "PKIX_SetLoggers"); |
| |
| PKIX_CHECK(PKIX_PL_MonitorLock_Enter(pkixLoggerLock, plContext), |
| PKIX_MONITORLOCKENTERFAILED); |
| locked = PKIX_TRUE; |
| |
| /* Disable tracing, etc. to avoid recursion and deadlock */ |
| savedPkixLoggersDebugTrace = pkixLoggersDebugTrace; |
| pkixLoggersDebugTrace = NULL; |
| savedPkixLoggersErrors = pkixLoggersErrors; |
| pkixLoggersErrors = NULL; |
| |
| /* discard any prior loggers */ |
| PKIX_DECREF(pkixLoggers); |
| PKIX_DECREF(savedPkixLoggersErrors); |
| PKIX_DECREF(savedPkixLoggersDebugTrace); |
| |
| if (loggers != NULL) { |
| |
| PKIX_CHECK(PKIX_List_Create(&list, plContext), |
| PKIX_LISTCREATEFAILED); |
| |
| PKIX_CHECK(PKIX_List_GetLength(loggers, &length, plContext), |
| PKIX_LISTGETLENGTHFAILED); |
| |
| for (i = 0; i < length; i++) { |
| |
| PKIX_CHECK(PKIX_List_GetItem |
| (loggers, |
| i, |
| (PKIX_PL_Object **) &logger, |
| plContext), |
| PKIX_LISTGETITEMFAILED); |
| |
| PKIX_CHECK(pkix_Logger_Duplicate |
| ((PKIX_PL_Object *)logger, |
| (PKIX_PL_Object **)&dupLogger, |
| plContext), |
| PKIX_LOGGERDUPLICATEFAILED); |
| |
| PKIX_CHECK(PKIX_List_AppendItem |
| (list, |
| (PKIX_PL_Object *) dupLogger, |
| plContext), |
| PKIX_LISTAPPENDITEMFAILED); |
| |
| /* Make two lists */ |
| |
| /* Put in pkixLoggersErrors in any case*/ |
| |
| if (savedPkixLoggersErrors == NULL) { |
| |
| PKIX_CHECK(PKIX_List_Create |
| (&savedPkixLoggersErrors, |
| plContext), |
| PKIX_LISTCREATEFAILED); |
| } |
| |
| PKIX_CHECK(PKIX_List_AppendItem |
| (savedPkixLoggersErrors, |
| (PKIX_PL_Object *) dupLogger, |
| plContext), |
| PKIX_LISTAPPENDITEMFAILED); |
| |
| if (logger->maxLevel > PKIX_LOGGER_LEVEL_WARNING) { |
| |
| /* Put in pkixLoggersDebugTrace */ |
| |
| if (savedPkixLoggersDebugTrace == NULL) { |
| |
| PKIX_CHECK(PKIX_List_Create |
| (&savedPkixLoggersDebugTrace, |
| plContext), |
| PKIX_LISTCREATEFAILED); |
| } |
| |
| PKIX_CHECK(PKIX_List_AppendItem |
| (savedPkixLoggersDebugTrace, |
| (PKIX_PL_Object *) dupLogger, |
| plContext), |
| PKIX_LISTAPPENDITEMFAILED); |
| } |
| PKIX_DECREF(logger); |
| PKIX_DECREF(dupLogger); |
| |
| } |
| |
| pkixLoggers = list; |
| } |
| |
| cleanup: |
| |
| if (PKIX_ERROR_RECEIVED){ |
| PKIX_DECREF(list); |
| PKIX_DECREF(savedPkixLoggersErrors); |
| PKIX_DECREF(savedPkixLoggersDebugTrace); |
| pkixLoggers = NULL; |
| } |
| |
| PKIX_DECREF(logger); |
| |
| /* Reenable logging capability with new lists */ |
| pkixLoggersErrors = savedPkixLoggersErrors; |
| pkixLoggersDebugTrace = savedPkixLoggersDebugTrace; |
| |
| if (locked) { |
| PKIX_CHECK(PKIX_PL_MonitorLock_Exit(pkixLoggerLock, plContext), |
| PKIX_MONITORLOCKEXITFAILED); |
| } |
| |
| PKIX_RETURN(LOGGER); |
| } |
| |
| /* |
| * FUNCTION: PKIX_Logger_AddLogger (see comments in pkix_util.h) |
| */ |
| PKIX_Error * |
| PKIX_AddLogger( |
| PKIX_Logger *logger, |
| void *plContext) |
| { |
| PKIX_Logger *dupLogger = NULL; |
| PKIX_Logger *addLogger = NULL; |
| PKIX_List *savedPkixLoggersErrors = NULL; |
| PKIX_List *savedPkixLoggersDebugTrace = NULL; |
| PKIX_Boolean locked = PKIX_FALSE; |
| PKIX_UInt32 i, length; |
| |
| PKIX_ENTER(LOGGER, "PKIX_Logger_AddLogger"); |
| PKIX_NULLCHECK_ONE(logger); |
| |
| PKIX_CHECK(PKIX_PL_MonitorLock_Enter(pkixLoggerLock, plContext), |
| PKIX_MONITORLOCKENTERFAILED); |
| locked = PKIX_TRUE; |
| |
| savedPkixLoggersDebugTrace = pkixLoggersDebugTrace; |
| pkixLoggersDebugTrace = NULL; |
| savedPkixLoggersErrors = pkixLoggersErrors; |
| pkixLoggersErrors = NULL; |
| |
| PKIX_DECREF(savedPkixLoggersErrors); |
| PKIX_DECREF(savedPkixLoggersDebugTrace); |
| |
| if (pkixLoggers == NULL) { |
| |
| PKIX_CHECK(PKIX_List_Create(&pkixLoggers, plContext), |
| PKIX_LISTCREATEFAILED); |
| } |
| |
| PKIX_CHECK(pkix_Logger_Duplicate |
| ((PKIX_PL_Object *)logger, |
| (PKIX_PL_Object **)&dupLogger, |
| plContext), |
| PKIX_LOGGERDUPLICATEFAILED); |
| |
| PKIX_CHECK(PKIX_List_AppendItem |
| (pkixLoggers, |
| (PKIX_PL_Object *) dupLogger, |
| plContext), |
| PKIX_LISTAPPENDITEMFAILED); |
| |
| PKIX_CHECK(PKIX_List_GetLength(pkixLoggers, &length, plContext), |
| PKIX_LISTGETLENGTHFAILED); |
| |
| /* Reconstruct pkixLoggersErrors and pkixLoggersDebugTrace */ |
| for (i = 0; i < length; i++) { |
| |
| PKIX_CHECK(PKIX_List_GetItem |
| (pkixLoggers, |
| i, |
| (PKIX_PL_Object **) &addLogger, |
| plContext), |
| PKIX_LISTGETITEMFAILED); |
| |
| |
| /* Put in pkixLoggersErrors */ |
| |
| if (savedPkixLoggersErrors == NULL) { |
| |
| PKIX_CHECK(PKIX_List_Create |
| (&savedPkixLoggersErrors, |
| plContext), |
| PKIX_LISTCREATEFAILED); |
| } |
| |
| PKIX_CHECK(PKIX_List_AppendItem |
| (savedPkixLoggersErrors, |
| (PKIX_PL_Object *) addLogger, |
| plContext), |
| PKIX_LISTAPPENDITEMFAILED); |
| |
| if (addLogger->maxLevel > PKIX_LOGGER_LEVEL_WARNING) { |
| |
| /* Put in pkixLoggersDebugTrace */ |
| |
| if (savedPkixLoggersDebugTrace == NULL) { |
| |
| PKIX_CHECK(PKIX_List_Create |
| (&savedPkixLoggersDebugTrace, |
| plContext), |
| PKIX_LISTCREATEFAILED); |
| } |
| |
| PKIX_CHECK(PKIX_List_AppendItem |
| (savedPkixLoggersDebugTrace, |
| (PKIX_PL_Object *) addLogger, |
| plContext), |
| PKIX_LISTAPPENDITEMFAILED); |
| } |
| |
| PKIX_DECREF(addLogger); |
| |
| } |
| |
| cleanup: |
| |
| PKIX_DECREF(dupLogger); |
| PKIX_DECREF(addLogger); |
| |
| /* Restore logging capability */ |
| pkixLoggersErrors = savedPkixLoggersErrors; |
| pkixLoggersDebugTrace = savedPkixLoggersDebugTrace; |
| |
| if (locked) { |
| PKIX_CHECK(PKIX_PL_MonitorLock_Exit(pkixLoggerLock, plContext), |
| PKIX_MONITORLOCKEXITFAILED); |
| } |
| |
| PKIX_RETURN(LOGGER); |
| } |