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