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