tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

pkix_logger.c (34076B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 /*
      5 * pkix_logger.c
      6 *
      7 * Logger Object Functions
      8 *
      9 */
     10 
     11 #include "pkix_logger.h"
     12 #ifndef PKIX_ERROR_DESCRIPTION
     13 #include "prprf.h"
     14 #endif
     15 
     16 /* Global variable to keep PKIX_Logger List */
     17 PKIX_List *pkixLoggers = NULL;
     18 
     19 /*
     20 * Once the Logger has been set, for any logging related operations, we have
     21 * to go through the List to find a match, and if found, issue the
     22 * corresponding callback. The overhead to check for DEBUG and TRACE in each
     23 * PKIX function entering and exiting is very expensive (400X), and redundant
     24 * if they are not the interest of the Logger. Therefore, the PKIX_Logger List
     25 * pkixLoggers is separated into two lists based on its Loggers' trace level.
     26 *
     27 * Whenever the pkixLoggers List is updated by PKIX_Logger_AddLogger() or
     28 * PKIX_Logger_SetLoggers(), we destroy and reconstruct pkixLoggersErrors
     29 * and pkixLoggersDebugTrace Logger Lists. The ERROR, FATAL_ERROR and
     30 * WARNING goes to pkixLoggersErrors and the DEBUG and TRACE goes to
     31 * pkixLoggersDebugTrace.
     32 *
     33 * Currently we provide five logging levels and the default setting are by:
     34 *
     35 *     PKIX_FATAL_ERROR() macro invokes pkix_Logger_Check of FATAL_ERROR level
     36 *     PKIX_ERROR() macro invokes pkix_Logger_Check of ERROR level
     37 *     WARNING is not invoked as default
     38 *     PKIX_DEBUG() macro invokes pkix_Logger_Check of DEBUG level. This needs
     39 *         compilation -DPKIX_<component>DEBUG flag to turn on 
     40 *     PKIX_ENTER() and PKIX_RETURN() macros invoke pkix_Logger_Check of TRACE
     41 *         level. TRACE provides duplicate information of DEBUG, but needs no
     42 *         recompilation and cannot choose component. To allow application
     43 *         to use DEBUG level, TRACE is put as last.
     44 *
     45 */
     46 PKIX_List *pkixLoggersErrors = NULL;
     47 PKIX_List *pkixLoggersDebugTrace = NULL;
     48 
     49 /* To ensure atomic update on pkixLoggers lists */
     50 PKIX_PL_MonitorLock *pkixLoggerLock = NULL;
     51 
     52 /* --Private-Functions-------------------------------------------- */
     53 
     54 /*
     55 * FUNCTION: pkix_Logger_CheckErrors
     56 * DESCRIPTION:
     57 *
     58 *  This function goes through each PKIX_Logger at "pkixLoggersList" and
     59 *  checks if "maxLevel" and "logComponent" satisfies what is specified in the
     60 *  PKIX_Logger. If satisfies, it invokes the callback in PKIX_Logger and
     61 *  passes a PKIX_PL_String that is the concatenation of "message" and 
     62 *  "message2" to the application for processing. 
     63 *  Since this call is inserted into a handful of PKIX macros, no macros are
     64 *  applied in this function, to avoid infinite recursion.
     65 *  If an error occurs, this call is aborted.
     66 *
     67 * PARAMETERS:
     68 *  "pkixLoggersList"
     69 *      A list of PKIX_Loggers to be examined for invoking callback. Must be
     70 *      non-NULL.
     71 *  "message"
     72 *      Address of "message" to be logged. Must be non-NULL.
     73 *  "message2"
     74 *      Address of "message2" to be concatenated and logged. May be NULL.
     75 *  "logComponent"
     76 *      A PKIX_UInt32 that indicates the component the message is from.
     77 *  "maxLevel"
     78 *      A PKIX_UInt32 that represents the level of severity of the message.
     79 *  "plContext"
     80 *      Platform-specific context pointer.
     81 * THREAD SAFETY:
     82 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
     83 * RETURNS:
     84 *  Returns NULL if the function succeeds
     85 *  Returns a Fatal Error if the function fails in an unrecoverable way
     86 */
     87 PKIX_Error *
     88 pkix_Logger_Check(
     89        PKIX_List *pkixLoggersList,
     90        const char *message,
     91        const char *message2,
     92        PKIX_ERRORCLASS logComponent,
     93        PKIX_UInt32 currentLevel,
     94        void *plContext)
     95 {
     96        PKIX_Logger *logger = NULL;
     97        PKIX_List *savedPkixLoggersErrors = NULL;
     98        PKIX_List *savedPkixLoggersDebugTrace = NULL;
     99        PKIX_PL_String *formatString = NULL;
    100        PKIX_PL_String *messageString = NULL;
    101        PKIX_PL_String *message2String = NULL;
    102        PKIX_PL_String *msgString = NULL;
    103        PKIX_Error *error = NULL;
    104        PKIX_Boolean needLogging = PKIX_FALSE;
    105        PKIX_UInt32 i, length;
    106 
    107        /*
    108         * We cannot use any the PKIX_ macros here, since this function is
    109         * called from some of these macros. It can create infinite recursion.
    110         */
    111 
    112        if ((pkixLoggersList == NULL) || (message == NULL)) {
    113                return(NULL);
    114        }
    115 
    116        /*
    117         * Disable all subsequent loggings to avoid recursion. The result is
    118         * if other thread is calling this function at the same time, there
    119         * won't be any logging because the pkixLoggersErrors and
    120         * pkixLoggersDebugTrace are set to null.
    121         * It would be nice if we provide control per thread (e.g. make
    122         * plContext threadable) then we can avoid the recursion by setting
    123         * flag at plContext. Then other thread's logging won't be affected.
    124         *
    125         * Also we need to use a reentrant Lock. Although we avoid recursion
    126         * for TRACE. When there is an ERROR occurs in subsequent call, this
    127         * function will be called.
    128         */
    129 
    130        error = PKIX_PL_MonitorLock_Enter(pkixLoggerLock, plContext);
    131        if (error) { return(NULL); }
    132 
    133        savedPkixLoggersDebugTrace = pkixLoggersDebugTrace;
    134        pkixLoggersDebugTrace = NULL;
    135        savedPkixLoggersErrors = pkixLoggersErrors;
    136        pkixLoggersErrors = NULL;
    137 
    138        /* Convert message and message2 to String */
    139        error = PKIX_PL_String_Create
    140                    (PKIX_ESCASCII, message, 0, &messageString, plContext);
    141        if (error) { goto cleanup; }
    142 
    143        if (message2) {
    144                error = PKIX_PL_String_Create
    145                    (PKIX_ESCASCII, message2, 0, &message2String, plContext);
    146                if (error) { goto cleanup; }
    147                error = PKIX_PL_String_Create
    148                    (PKIX_ESCASCII, "%s %s", 0, &formatString, plContext);
    149                if (error) { goto cleanup; }
    150 
    151        } else {
    152                error = PKIX_PL_String_Create
    153                    (PKIX_ESCASCII, "%s", 0, &formatString, plContext);
    154                if (error) { goto cleanup; }
    155 
    156        }
    157 
    158        error = PKIX_PL_Sprintf
    159                    (&msgString,
    160                    plContext,
    161                    formatString,
    162                    messageString,
    163                    message2String);
    164        if (error) { goto cleanup; }
    165 
    166        /* Go through the Logger list */
    167 
    168        error = PKIX_List_GetLength(pkixLoggersList, &length, plContext);
    169        if (error) { goto cleanup; }
    170 
    171        for (i = 0; i < length; i++) {
    172 
    173                error = PKIX_List_GetItem
    174                    (pkixLoggersList,
    175                    i,
    176                    (PKIX_PL_Object **) &logger,
    177                    plContext);
    178                if (error) { goto cleanup; }
    179 
    180                /* Intended logging level less or equal than the max */
    181                needLogging = (currentLevel <= logger->maxLevel);
    182 
    183                if (needLogging && (logger->callback)) {
    184 
    185                    /*
    186                     * We separate Logger into two lists based on log level
    187                     * but log level is not modified. We need to check here to
    188                     * avoid logging the higher log level (lower value) twice.
    189                     */
    190                    if (pkixLoggersList == pkixLoggersErrors) {
    191                            needLogging = needLogging && 
    192                                (currentLevel <= PKIX_LOGGER_LEVEL_WARNING);
    193                    } else if (pkixLoggersList == pkixLoggersDebugTrace) {
    194                            needLogging = needLogging && 
    195                                (currentLevel > PKIX_LOGGER_LEVEL_WARNING);
    196                    }
    197                
    198                    if (needLogging) {
    199                        if (logComponent == logger->logComponent) {
    200                            needLogging = PKIX_TRUE;
    201                        } else {
    202                            needLogging = PKIX_FALSE;
    203                        }
    204                    }
    205 
    206                    if (needLogging) {
    207                        error = logger->callback
    208                                (logger,
    209                                msgString,
    210                                currentLevel,
    211                                logComponent,
    212                                plContext);
    213                        if (error) { goto cleanup; }
    214                    }
    215                }
    216 
    217                error = PKIX_PL_Object_DecRef
    218                        ((PKIX_PL_Object *)logger, plContext);
    219                logger = NULL;
    220                if (error) { goto cleanup; }
    221 
    222        }
    223 
    224 cleanup:
    225 
    226        if (formatString) {
    227                error = PKIX_PL_Object_DecRef
    228                        ((PKIX_PL_Object *)formatString, plContext);
    229        }
    230 
    231        if (messageString) {
    232                error = PKIX_PL_Object_DecRef
    233                         ((PKIX_PL_Object *)messageString, plContext);
    234        }
    235 
    236        if (message2String) {
    237                error = PKIX_PL_Object_DecRef
    238                        ((PKIX_PL_Object *)message2String, plContext);
    239        }
    240 
    241        if (msgString) {
    242                error = PKIX_PL_Object_DecRef
    243                        ((PKIX_PL_Object *)msgString, plContext);
    244        }
    245 
    246        if (logger) {
    247                error = PKIX_PL_Object_DecRef
    248                        ((PKIX_PL_Object *)logger, plContext);
    249        }
    250 
    251        if (pkixLoggersErrors == NULL && savedPkixLoggersErrors != NULL) {
    252                pkixLoggersErrors = savedPkixLoggersErrors;
    253        } 
    254 
    255        if (pkixLoggersDebugTrace == NULL && 
    256           savedPkixLoggersDebugTrace != NULL) {
    257                pkixLoggersDebugTrace = savedPkixLoggersDebugTrace;
    258        }
    259 
    260        error = PKIX_PL_MonitorLock_Exit(pkixLoggerLock, plContext);
    261        if (error) { return(NULL); }
    262 
    263        return(NULL);
    264 }
    265 
    266 PKIX_Error *
    267 pkix_Logger_CheckWithCode(
    268        PKIX_List *pkixLoggersList,
    269        PKIX_UInt32 errorCode,
    270        const char *message2,
    271        PKIX_ERRORCLASS logComponent,
    272        PKIX_UInt32 currentLevel,
    273        void *plContext)
    274 {
    275    char error[32];
    276    char *errorString = NULL;
    277 
    278    PKIX_ENTER(LOGGER, "pkix_Logger_CheckWithCode");
    279 #if defined PKIX_ERROR_DESCRIPTION
    280    errorString = PKIX_ErrorText[errorCode];
    281 #else
    282    PR_snprintf(error, 32, "Error code: %d", errorCode);
    283    errorString = error;
    284 #endif /* PKIX_ERROR_DESCRIPTION */
    285 
    286    pkixErrorResult = pkix_Logger_Check(pkixLoggersList, errorString,
    287                                        message2, logComponent,
    288                                        currentLevel, plContext);
    289    PKIX_RETURN(LOGGER);
    290 }
    291 
    292 /*
    293 * FUNCTION: pkix_Logger_Destroy
    294 * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
    295 */
    296 static PKIX_Error *
    297 pkix_Logger_Destroy(
    298        PKIX_PL_Object *object,
    299        void *plContext)
    300 {
    301        PKIX_Logger *logger = NULL;
    302 
    303        PKIX_ENTER(LOGGER, "pkix_Logger_Destroy");
    304        PKIX_NULLCHECK_ONE(object);
    305 
    306        /* Check that this object is a logger */
    307        PKIX_CHECK(pkix_CheckType(object, PKIX_LOGGER_TYPE, plContext),
    308                    PKIX_OBJECTNOTLOGGER);
    309 
    310        logger = (PKIX_Logger *)object;
    311 
    312        /* We have a valid logger. DecRef its item and recurse on next */
    313 
    314        logger->callback = NULL;
    315        PKIX_DECREF(logger->context);
    316        logger->logComponent = (PKIX_ERRORCLASS)0;
    317 
    318 cleanup:
    319 
    320        PKIX_RETURN(LOGGER);
    321 }
    322 
    323 /*
    324 * FUNCTION: pkix_Logger_ToString
    325 * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h)
    326 */
    327 static PKIX_Error *
    328 pkix_Logger_ToString(
    329        PKIX_PL_Object *object,
    330        PKIX_PL_String **pString,
    331        void *plContext)
    332 {
    333        PKIX_Logger *logger = NULL;
    334        char *asciiFormat = NULL;
    335        PKIX_PL_String *formatString = NULL;
    336        PKIX_PL_String *contextString = NULL;
    337        PKIX_PL_String *componentString = NULL;
    338        PKIX_PL_String *loggerString = NULL;
    339 
    340        PKIX_ENTER(LOGGER, "pkix_Logger_ToString_Helper");
    341        PKIX_NULLCHECK_TWO(object, pString);
    342 
    343        /* Check that this object is a logger */
    344        PKIX_CHECK(pkix_CheckType(object, PKIX_LOGGER_TYPE, plContext),
    345                    PKIX_OBJECTNOTLOGGER);
    346 
    347        logger = (PKIX_Logger *)object;
    348 
    349        asciiFormat =
    350                "[\n"
    351                "\tLogger: \n"
    352                "\tContext:          %s\n"
    353                "\tMaximum Level:    %d\n"
    354                "\tComponent Name:   %s\n"
    355                "]\n";
    356 
    357        PKIX_CHECK(PKIX_PL_String_Create
    358                    (PKIX_ESCASCII,
    359                    asciiFormat,
    360                    0,
    361                    &formatString,
    362                    plContext),
    363                    PKIX_STRINGCREATEFAILED);
    364 
    365        PKIX_TOSTRING(logger->context, &contextString, plContext,
    366                PKIX_OBJECTTOSTRINGFAILED);
    367 
    368        PKIX_CHECK(PKIX_PL_String_Create
    369                (PKIX_ESCASCII,
    370                (void *)PKIX_ERRORCLASSNAMES[logger->logComponent],
    371                0,
    372                &componentString,
    373                plContext),
    374                PKIX_STRINGCREATEFAILED);
    375 
    376        PKIX_CHECK(PKIX_PL_Sprintf
    377                (&loggerString,
    378                plContext,
    379                formatString,
    380                contextString,
    381                logger->maxLevel,
    382                componentString),
    383                PKIX_SPRINTFFAILED);
    384 
    385        *pString = loggerString;
    386 
    387 cleanup:
    388 
    389        PKIX_DECREF(formatString);
    390        PKIX_DECREF(contextString);
    391        PKIX_RETURN(LOGGER);
    392 }
    393 
    394 /*
    395 * FUNCTION: pkix_Logger_Equals
    396 * (see comments for PKIX_PL_EqualsCallback in pkix_pl_system.h)
    397 */
    398 static PKIX_Error *
    399 pkix_Logger_Equals(
    400        PKIX_PL_Object *first,
    401        PKIX_PL_Object *second,
    402        PKIX_Boolean *pResult,
    403        void *plContext)
    404 {
    405        PKIX_UInt32 secondType;
    406        PKIX_Boolean cmpResult;
    407        PKIX_Logger *firstLogger = NULL;
    408        PKIX_Logger *secondLogger = NULL;
    409 
    410        PKIX_ENTER(LOGGER, "pkix_Logger_Equals");
    411        PKIX_NULLCHECK_THREE(first, second, pResult);
    412 
    413        /* test that first is a Logger */
    414        PKIX_CHECK(pkix_CheckType(first, PKIX_LOGGER_TYPE, plContext),
    415                PKIX_FIRSTOBJECTNOTLOGGER);
    416 
    417        /*
    418         * Since we know first is a Logger, if both references are
    419         * identical, they must be equal
    420         */
    421        if (first == second){
    422                *pResult = PKIX_TRUE;
    423                goto cleanup;
    424        }
    425 
    426        /*
    427         * If second isn't a Logger, we don't throw an error.
    428         * We simply return a Boolean result of FALSE
    429         */
    430        *pResult = PKIX_FALSE;
    431        PKIX_CHECK(PKIX_PL_Object_GetType(second, &secondType, plContext),
    432                    PKIX_COULDNOTGETTYPEOFSECONDARGUMENT);
    433        if (secondType != PKIX_LOGGER_TYPE) goto cleanup;
    434 
    435        firstLogger = (PKIX_Logger *)first;
    436        secondLogger = (PKIX_Logger *)second;
    437 
    438        cmpResult = PKIX_FALSE;
    439 
    440        if (firstLogger->callback != secondLogger->callback) {
    441                goto cleanup;
    442        }
    443 
    444        if (firstLogger->logComponent != secondLogger->logComponent) {
    445                goto cleanup;
    446        }
    447 
    448        PKIX_EQUALS  
    449                (firstLogger->context,
    450                secondLogger->context,
    451                &cmpResult,
    452                plContext,
    453                PKIX_OBJECTEQUALSFAILED);
    454 
    455        if (cmpResult == PKIX_FALSE) {
    456                goto cleanup;
    457        }
    458 
    459        if (firstLogger->maxLevel != secondLogger->maxLevel) {
    460                goto cleanup;
    461        }
    462 
    463        *pResult = cmpResult;
    464 
    465 cleanup:
    466 
    467        PKIX_RETURN(LOGGER);
    468 }
    469 
    470 /*
    471 * FUNCTION: pkix_Logger_Hashcode
    472 * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h)
    473 */
    474 static PKIX_Error *
    475 pkix_Logger_Hashcode(
    476        PKIX_PL_Object *object,
    477        PKIX_UInt32 *pHashcode,
    478        void *plContext)
    479 {
    480        PKIX_Logger *logger = NULL;
    481        PKIX_UInt32 hash = 0;
    482        PKIX_UInt32 tempHash = 0;
    483 
    484        PKIX_ENTER(LOGGER, "pkix_Logger_Hashcode");
    485        PKIX_NULLCHECK_TWO(object, pHashcode);
    486 
    487        PKIX_CHECK(pkix_CheckType(object, PKIX_LOGGER_TYPE, plContext),
    488                    PKIX_OBJECTNOTLOGGER);
    489 
    490        logger = (PKIX_Logger *)object;
    491 
    492        PKIX_HASHCODE(logger->context, &tempHash, plContext,
    493                PKIX_OBJECTHASHCODEFAILED);
    494 
    495        hash = (((((PKIX_UInt32)((char *)logger->callback - (char *)NULL) + tempHash) << 7) +
    496                logger->maxLevel) << 7) + (PKIX_UInt32)logger->logComponent;
    497 
    498        *pHashcode = hash;
    499 
    500 cleanup:
    501 
    502        PKIX_RETURN(LOGGER);
    503 }
    504 
    505 
    506 /*
    507 * FUNCTION: pkix_Logger_Duplicate
    508 * (see comments for PKIX_PL_DuplicateCallback in pkix_pl_system.h)
    509 */
    510 static PKIX_Error *
    511 pkix_Logger_Duplicate(
    512        PKIX_PL_Object *object,
    513        PKIX_PL_Object **pNewObject,
    514        void *plContext)
    515 {
    516        PKIX_Logger *logger = NULL;
    517        PKIX_Logger *dupLogger = NULL;
    518 
    519        PKIX_ENTER(LOGGER, "pkix_Logger_Duplicate");
    520        PKIX_NULLCHECK_TWO(object, pNewObject);
    521 
    522        PKIX_CHECK(pkix_CheckType
    523                    ((PKIX_PL_Object *)object, PKIX_LOGGER_TYPE, plContext),
    524                    PKIX_OBJECTNOTLOGGER);
    525 
    526        logger = (PKIX_Logger *) object;
    527 
    528        PKIX_CHECK(PKIX_PL_Object_Alloc
    529                    (PKIX_LOGGER_TYPE,
    530                    sizeof (PKIX_Logger),
    531                    (PKIX_PL_Object **)&dupLogger,
    532                    plContext),
    533                    PKIX_COULDNOTCREATELOGGEROBJECT);
    534 
    535        dupLogger->callback = logger->callback;
    536        dupLogger->maxLevel = logger->maxLevel;
    537        
    538        PKIX_DUPLICATE
    539                    (logger->context,
    540                    &dupLogger->context,
    541                    plContext,
    542                    PKIX_OBJECTDUPLICATEFAILED);
    543 
    544        dupLogger->logComponent = logger->logComponent;
    545 
    546        *pNewObject = (PKIX_PL_Object *) dupLogger;
    547 
    548 cleanup:
    549 
    550        if (PKIX_ERROR_RECEIVED){
    551                PKIX_DECREF(dupLogger);
    552        }
    553 
    554        PKIX_RETURN(LOGGER);
    555 }
    556 
    557 /*
    558 * FUNCTION: pkix_Logger_RegisterSelf
    559 * DESCRIPTION:
    560 *  Registers PKIX_LOGGER_TYPE and its related functions with systemClasses[]
    561 * THREAD SAFETY:
    562 *  Not Thread Safe - for performance and complexity reasons
    563 *
    564 *  Since this function is only called by PKIX_PL_Initialize, which should
    565 *  only be called once, it is acceptable that this function is not
    566 *  thread-safe.
    567 */
    568 PKIX_Error *
    569 pkix_Logger_RegisterSelf(void *plContext)
    570 {
    571        extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
    572        pkix_ClassTable_Entry entry;
    573 
    574        PKIX_ENTER(LOGGER, "pkix_Logger_RegisterSelf");
    575 
    576        entry.description = "Logger";
    577        entry.objCounter = 0;
    578        entry.typeObjectSize = sizeof(PKIX_Logger);
    579        entry.destructor = pkix_Logger_Destroy;
    580        entry.equalsFunction = pkix_Logger_Equals;
    581        entry.hashcodeFunction = pkix_Logger_Hashcode;
    582        entry.toStringFunction = pkix_Logger_ToString;
    583        entry.comparator = NULL;
    584        entry.duplicateFunction = pkix_Logger_Duplicate;
    585 
    586        systemClasses[PKIX_LOGGER_TYPE] = entry;
    587 
    588        PKIX_RETURN(LOGGER);
    589 }
    590 
    591 /* --Public-Logger-Functions--------------------------------------------- */
    592 
    593 /*
    594 * FUNCTION: PKIX_Logger_Create (see comments in pkix_util.h)
    595 */
    596 PKIX_Error *
    597 PKIX_Logger_Create(
    598        PKIX_Logger_LogCallback callback,
    599        PKIX_PL_Object *loggerContext,
    600        PKIX_Logger **pLogger,
    601        void *plContext)
    602 {
    603        PKIX_Logger *logger = NULL;
    604 
    605        PKIX_ENTER(LOGGER, "PKIX_Logger_Create");
    606        PKIX_NULLCHECK_ONE(pLogger);
    607 
    608        PKIX_CHECK(PKIX_PL_Object_Alloc
    609                    (PKIX_LOGGER_TYPE,
    610                    sizeof (PKIX_Logger),
    611                    (PKIX_PL_Object **)&logger,
    612                    plContext),
    613                    PKIX_COULDNOTCREATELOGGEROBJECT);
    614 
    615        logger->callback = callback;
    616        logger->maxLevel = 0;
    617        logger->logComponent = (PKIX_ERRORCLASS)0;
    618 
    619        PKIX_INCREF(loggerContext);
    620        logger->context = loggerContext;
    621 
    622        *pLogger = logger;
    623        logger = NULL;
    624 
    625 cleanup:
    626 
    627        PKIX_DECREF(logger);
    628 
    629        PKIX_RETURN(LOGGER);
    630 }
    631 
    632 /*
    633 * FUNCTION: PKIX_Logger_GetLogCallback (see comments in pkix_util.h)
    634 */
    635 PKIX_Error *
    636 PKIX_Logger_GetLogCallback(
    637        PKIX_Logger *logger,
    638        PKIX_Logger_LogCallback *pCallback,
    639        void *plContext)
    640 {
    641        PKIX_ENTER(LOGGER, "PKIX_Logger_GetLogCallback");
    642        PKIX_NULLCHECK_TWO(logger, pCallback);
    643 
    644        *pCallback = logger->callback;
    645 
    646        PKIX_RETURN(LOGGER);
    647 }
    648 
    649 /*
    650 * FUNCTION: PKIX_Logger_GetLoggerContext (see comments in pkix_util.h)
    651 */
    652 PKIX_Error *
    653 PKIX_Logger_GetLoggerContext(
    654        PKIX_Logger *logger,
    655        PKIX_PL_Object **pLoggerContext,
    656        void *plContext)
    657 {
    658        PKIX_ENTER(LOGGER, "PKIX_Logger_GetLoggerContex");
    659        PKIX_NULLCHECK_TWO(logger, pLoggerContext);
    660 
    661        PKIX_INCREF(logger->context);
    662        *pLoggerContext = logger->context;
    663 
    664 cleanup:
    665        PKIX_RETURN(LOGGER);
    666 }
    667 
    668 /*
    669 * FUNCTION: PKIX_Logger_GetMaxLoggingLevel (see comments in pkix_util.h)
    670 */
    671 PKIX_Error *
    672 PKIX_Logger_GetMaxLoggingLevel(
    673        PKIX_Logger *logger,
    674        PKIX_UInt32 *pLevel,
    675        void *plContext)
    676 {
    677        PKIX_ENTER(LOGGER, "PKIX_Logger_GetMaxLoggingLevel");
    678        PKIX_NULLCHECK_TWO(logger, pLevel);
    679 
    680        *pLevel = logger->maxLevel;
    681 
    682        PKIX_RETURN(LOGGER);
    683 }
    684 
    685 /*
    686 * FUNCTION: PKIX_Logger_SetMaxLoggingLevel (see comments in pkix_util.h)
    687 */
    688 PKIX_Error *
    689 PKIX_Logger_SetMaxLoggingLevel(
    690        PKIX_Logger *logger,
    691        PKIX_UInt32 level,
    692        void *plContext)
    693 {
    694        PKIX_ENTER(LOGGER, "PKIX_Logger_SetMaxLoggingLevel");
    695        PKIX_NULLCHECK_ONE(logger);
    696 
    697        if (level > PKIX_LOGGER_LEVEL_MAX) {
    698                PKIX_ERROR(PKIX_LOGGINGLEVELEXCEEDSMAXIMUM);
    699        } else {
    700                logger->maxLevel = level;
    701        }
    702 
    703 cleanup:
    704 
    705        PKIX_RETURN(LOGGER);
    706 }
    707 
    708 /*
    709 * FUNCTION: PKIX_Logger_GetLoggingComponent (see comments in pkix_util.h)
    710 */
    711 PKIX_Error *
    712 PKIX_Logger_GetLoggingComponent(
    713        PKIX_Logger *logger,
    714        PKIX_ERRORCLASS *pComponent,
    715        void *plContext)
    716 {
    717        PKIX_ENTER(LOGGER, "PKIX_Logger_GetLoggingComponent");
    718        PKIX_NULLCHECK_TWO(logger, pComponent);
    719 
    720        *pComponent = logger->logComponent;
    721 
    722        PKIX_RETURN(LOGGER);
    723 }
    724 
    725 /*
    726 * FUNCTION: PKIX_Logger_SetLoggingComponent (see comments in pkix_util.h)
    727 */
    728 PKIX_Error *
    729 PKIX_Logger_SetLoggingComponent(
    730        PKIX_Logger *logger,
    731        PKIX_ERRORCLASS component,
    732        void *plContext)
    733 {
    734        PKIX_ENTER(LOGGER, "PKIX_Logger_SetLoggingComponent");
    735        PKIX_NULLCHECK_ONE(logger);
    736 
    737        logger->logComponent = component;
    738 
    739        PKIX_RETURN(LOGGER);
    740 }
    741 
    742 
    743 /*
    744 * Following PKIX_GetLoggers(), PKIX_SetLoggers() and PKIX_AddLogger() are
    745 * documented as not thread-safe. However they are thread-safe now. We need
    746 * the lock when accessing the logger lists.
    747 */
    748 
    749 /*
    750 * FUNCTION: PKIX_Logger_GetLoggers (see comments in pkix_util.h)
    751 */
    752 PKIX_Error *
    753 PKIX_GetLoggers(
    754        PKIX_List **pLoggers,  /* list of PKIX_Logger */
    755        void *plContext)
    756 {
    757        PKIX_List *list = NULL;
    758        PKIX_List *savedPkixLoggersDebugTrace = NULL;
    759        PKIX_List *savedPkixLoggersErrors = NULL;
    760        PKIX_Logger *logger = NULL;
    761        PKIX_Logger *dupLogger = NULL;
    762        PKIX_UInt32 i, length;
    763        PKIX_Boolean locked = PKIX_FALSE;
    764 
    765        PKIX_ENTER(LOGGER, "PKIX_Logger_GetLoggers");
    766        PKIX_NULLCHECK_ONE(pLoggers);
    767 
    768        PKIX_CHECK(PKIX_PL_MonitorLock_Enter(pkixLoggerLock, plContext),
    769                PKIX_MONITORLOCKENTERFAILED);
    770        locked = PKIX_TRUE;
    771 
    772        /*
    773         * Temporarily disable DEBUG/TRACE Logging to avoid possible
    774         * deadlock:
    775         * When the Logger List is being accessed, e.g. by PKIX_ENTER or
    776         * PKIX_DECREF, pkix_Logger_Check may check whether logging
    777         * is requested, creating a deadlock situation.
    778         */
    779        savedPkixLoggersDebugTrace = pkixLoggersDebugTrace;
    780        pkixLoggersDebugTrace = NULL;
    781        savedPkixLoggersErrors = pkixLoggersErrors;
    782        pkixLoggersErrors = NULL;
    783 
    784        if (pkixLoggers == NULL) {
    785                length = 0;
    786        } else {
    787                PKIX_CHECK(PKIX_List_GetLength
    788                    (pkixLoggers, &length, plContext),
    789                    PKIX_LISTGETLENGTHFAILED);
    790        }
    791 
    792        /* Create a list and copy the pkixLoggers item to the list */
    793        PKIX_CHECK(PKIX_List_Create(&list, plContext),
    794                    PKIX_LISTCREATEFAILED);
    795 
    796        for (i = 0; i < length; i++) {
    797 
    798            PKIX_CHECK(PKIX_List_GetItem
    799                        (pkixLoggers,
    800                        i,
    801                        (PKIX_PL_Object **) &logger,
    802                        plContext),
    803                        PKIX_LISTGETITEMFAILED);
    804 
    805            PKIX_CHECK(pkix_Logger_Duplicate
    806                        ((PKIX_PL_Object *)logger,
    807                        (PKIX_PL_Object **)&dupLogger,
    808                        plContext),
    809                        PKIX_LOGGERDUPLICATEFAILED);
    810 
    811            PKIX_CHECK(PKIX_List_AppendItem
    812                        (list,
    813                        (PKIX_PL_Object *) dupLogger,
    814                        plContext),
    815                        PKIX_LISTAPPENDITEMFAILED);
    816 
    817            PKIX_DECREF(logger);
    818            PKIX_DECREF(dupLogger);
    819        }
    820 
    821        /* Set the list to be immutable */
    822        PKIX_CHECK(PKIX_List_SetImmutable(list, plContext),
    823                        PKIX_LISTSETIMMUTABLEFAILED);
    824 
    825        *pLoggers = list;
    826 
    827 cleanup:
    828 
    829        PKIX_DECREF(logger);
    830 
    831        /* Restore logging capability */
    832        pkixLoggersDebugTrace = savedPkixLoggersDebugTrace;
    833        pkixLoggersErrors = savedPkixLoggersErrors;
    834 
    835        if (locked) {
    836                PKIX_CHECK(PKIX_PL_MonitorLock_Exit(pkixLoggerLock, plContext),
    837                        PKIX_MONITORLOCKEXITFAILED);
    838        }
    839 
    840        PKIX_RETURN(LOGGER);
    841 }
    842 
    843 /*
    844 * FUNCTION: PKIX_Logger_SetLoggers (see comments in pkix_util.h)
    845 */
    846 PKIX_Error *
    847 PKIX_SetLoggers(
    848        PKIX_List *loggers,  /* list of PKIX_Logger */
    849        void *plContext)
    850 {
    851        PKIX_List *list = NULL;
    852        PKIX_List *savedPkixLoggersErrors = NULL;
    853        PKIX_List *savedPkixLoggersDebugTrace = NULL;
    854        PKIX_Logger *logger = NULL;
    855        PKIX_Logger *dupLogger = NULL;
    856        PKIX_Boolean locked = PKIX_FALSE;
    857        PKIX_UInt32 i, length;
    858 
    859        PKIX_ENTER(LOGGER, "PKIX_SetLoggers");
    860 
    861        PKIX_CHECK(PKIX_PL_MonitorLock_Enter(pkixLoggerLock, plContext),
    862                PKIX_MONITORLOCKENTERFAILED);
    863        locked = PKIX_TRUE;
    864 
    865        /* Disable tracing, etc. to avoid recursion and deadlock */
    866        savedPkixLoggersDebugTrace = pkixLoggersDebugTrace;
    867        pkixLoggersDebugTrace = NULL;
    868        savedPkixLoggersErrors = pkixLoggersErrors;
    869        pkixLoggersErrors = NULL;
    870 
    871        /* discard any prior loggers */
    872        PKIX_DECREF(pkixLoggers);
    873        PKIX_DECREF(savedPkixLoggersErrors);
    874        PKIX_DECREF(savedPkixLoggersDebugTrace);
    875 
    876        if (loggers != NULL) {
    877 
    878                PKIX_CHECK(PKIX_List_Create(&list, plContext),
    879                    PKIX_LISTCREATEFAILED);
    880 
    881                PKIX_CHECK(PKIX_List_GetLength(loggers, &length, plContext),
    882                    PKIX_LISTGETLENGTHFAILED);
    883 
    884                for (i = 0; i < length; i++) {
    885 
    886                    PKIX_CHECK(PKIX_List_GetItem
    887                        (loggers,
    888                        i,
    889                        (PKIX_PL_Object **) &logger,
    890                        plContext),
    891                        PKIX_LISTGETITEMFAILED);
    892 
    893                    PKIX_CHECK(pkix_Logger_Duplicate
    894                        ((PKIX_PL_Object *)logger,
    895                        (PKIX_PL_Object **)&dupLogger,
    896                        plContext),
    897                        PKIX_LOGGERDUPLICATEFAILED);
    898 
    899                    PKIX_CHECK(PKIX_List_AppendItem
    900                        (list,
    901                        (PKIX_PL_Object *) dupLogger,
    902                        plContext),
    903                        PKIX_LISTAPPENDITEMFAILED);
    904 
    905                    /* Make two lists */
    906 
    907                    /* Put in pkixLoggersErrors in any case*/
    908 
    909                    if (savedPkixLoggersErrors == NULL) {
    910 
    911                        PKIX_CHECK(PKIX_List_Create
    912                                (&savedPkixLoggersErrors,
    913                                plContext),
    914                                PKIX_LISTCREATEFAILED);
    915                    }
    916        
    917                    PKIX_CHECK(PKIX_List_AppendItem
    918                            (savedPkixLoggersErrors,
    919                            (PKIX_PL_Object *) dupLogger,
    920                            plContext),
    921                            PKIX_LISTAPPENDITEMFAILED);
    922 
    923                    if (logger->maxLevel > PKIX_LOGGER_LEVEL_WARNING) {
    924 
    925                        /* Put in pkixLoggersDebugTrace */
    926 
    927                        if (savedPkixLoggersDebugTrace == NULL) {
    928 
    929                            PKIX_CHECK(PKIX_List_Create
    930                                    (&savedPkixLoggersDebugTrace,
    931                                    plContext),
    932                                    PKIX_LISTCREATEFAILED);
    933                        }
    934        
    935                        PKIX_CHECK(PKIX_List_AppendItem
    936                                (savedPkixLoggersDebugTrace,
    937                                (PKIX_PL_Object *) dupLogger,
    938                                plContext),
    939                                PKIX_LISTAPPENDITEMFAILED);
    940                    }
    941                    PKIX_DECREF(logger);
    942                    PKIX_DECREF(dupLogger);
    943 
    944                }
    945 
    946                pkixLoggers = list;
    947        }
    948 
    949 cleanup:
    950 
    951        if (PKIX_ERROR_RECEIVED){
    952                PKIX_DECREF(list);
    953                PKIX_DECREF(savedPkixLoggersErrors);
    954                PKIX_DECREF(savedPkixLoggersDebugTrace);
    955                pkixLoggers = NULL;
    956        }
    957 
    958        PKIX_DECREF(logger);
    959 
    960        /* Reenable logging capability with new lists */
    961        pkixLoggersErrors = savedPkixLoggersErrors;
    962        pkixLoggersDebugTrace = savedPkixLoggersDebugTrace;
    963 
    964        if (locked) {
    965                PKIX_CHECK(PKIX_PL_MonitorLock_Exit(pkixLoggerLock, plContext),
    966                        PKIX_MONITORLOCKEXITFAILED);
    967        }
    968 
    969        PKIX_RETURN(LOGGER);
    970 }
    971 
    972 /*
    973 * FUNCTION: PKIX_Logger_AddLogger (see comments in pkix_util.h)
    974 */
    975 PKIX_Error *
    976 PKIX_AddLogger(
    977        PKIX_Logger *logger,
    978        void *plContext)
    979 {
    980        PKIX_Logger *dupLogger = NULL;
    981        PKIX_Logger *addLogger = NULL;
    982        PKIX_List *savedPkixLoggersErrors = NULL;
    983        PKIX_List *savedPkixLoggersDebugTrace = NULL;
    984        PKIX_Boolean locked = PKIX_FALSE;
    985        PKIX_UInt32 i, length;
    986 
    987        PKIX_ENTER(LOGGER, "PKIX_Logger_AddLogger");
    988        PKIX_NULLCHECK_ONE(logger);
    989 
    990        PKIX_CHECK(PKIX_PL_MonitorLock_Enter(pkixLoggerLock, plContext),
    991                PKIX_MONITORLOCKENTERFAILED);
    992        locked = PKIX_TRUE;
    993 
    994        savedPkixLoggersDebugTrace = pkixLoggersDebugTrace;
    995        pkixLoggersDebugTrace = NULL;
    996        savedPkixLoggersErrors = pkixLoggersErrors;
    997        pkixLoggersErrors = NULL;
    998 
    999        PKIX_DECREF(savedPkixLoggersErrors);
   1000        PKIX_DECREF(savedPkixLoggersDebugTrace);
   1001 
   1002        if (pkixLoggers == NULL) {
   1003 
   1004            PKIX_CHECK(PKIX_List_Create(&pkixLoggers, plContext),
   1005                    PKIX_LISTCREATEFAILED);
   1006        }
   1007 
   1008        PKIX_CHECK(pkix_Logger_Duplicate
   1009                    ((PKIX_PL_Object *)logger,
   1010                    (PKIX_PL_Object **)&dupLogger,
   1011                    plContext),
   1012                    PKIX_LOGGERDUPLICATEFAILED);
   1013 
   1014        PKIX_CHECK(PKIX_List_AppendItem
   1015                    (pkixLoggers,
   1016                    (PKIX_PL_Object *) dupLogger,
   1017                    plContext),
   1018                    PKIX_LISTAPPENDITEMFAILED);
   1019 
   1020        PKIX_CHECK(PKIX_List_GetLength(pkixLoggers, &length, plContext),
   1021                    PKIX_LISTGETLENGTHFAILED);
   1022 
   1023        /* Reconstruct pkixLoggersErrors and pkixLoggersDebugTrace */
   1024        for (i = 0; i < length; i++) {
   1025 
   1026                PKIX_CHECK(PKIX_List_GetItem
   1027                        (pkixLoggers,
   1028                        i,
   1029                        (PKIX_PL_Object **) &addLogger,
   1030                        plContext),
   1031                        PKIX_LISTGETITEMFAILED);
   1032 
   1033 
   1034                /* Put in pkixLoggersErrors */
   1035 
   1036                if (savedPkixLoggersErrors == NULL) {
   1037 
   1038                        PKIX_CHECK(PKIX_List_Create
   1039                                    (&savedPkixLoggersErrors,
   1040                                    plContext),
   1041                                    PKIX_LISTCREATEFAILED);
   1042                }
   1043        
   1044                PKIX_CHECK(PKIX_List_AppendItem
   1045                        (savedPkixLoggersErrors,
   1046                        (PKIX_PL_Object *) addLogger,
   1047                        plContext),
   1048                        PKIX_LISTAPPENDITEMFAILED);
   1049                            
   1050                if (addLogger->maxLevel > PKIX_LOGGER_LEVEL_WARNING) {
   1051 
   1052                        /* Put in pkixLoggersDebugTrace */
   1053 
   1054                        if (savedPkixLoggersDebugTrace == NULL) {
   1055 
   1056                            PKIX_CHECK(PKIX_List_Create
   1057                                    (&savedPkixLoggersDebugTrace,
   1058                                    plContext),
   1059                                    PKIX_LISTCREATEFAILED);
   1060                        }
   1061 
   1062                        PKIX_CHECK(PKIX_List_AppendItem
   1063                                (savedPkixLoggersDebugTrace,
   1064                                (PKIX_PL_Object *) addLogger,
   1065                                plContext),
   1066                                PKIX_LISTAPPENDITEMFAILED);
   1067                }
   1068 
   1069                PKIX_DECREF(addLogger);
   1070 
   1071        }
   1072 
   1073 cleanup:
   1074 
   1075        PKIX_DECREF(dupLogger);
   1076        PKIX_DECREF(addLogger);
   1077 
   1078        /* Restore logging capability */
   1079        pkixLoggersErrors = savedPkixLoggersErrors;
   1080        pkixLoggersDebugTrace = savedPkixLoggersDebugTrace;
   1081 
   1082        if (locked) {
   1083                PKIX_CHECK(PKIX_PL_MonitorLock_Exit(pkixLoggerLock, plContext),
   1084                        PKIX_MONITORLOCKEXITFAILED);
   1085        }
   1086 
   1087       PKIX_RETURN(LOGGER);
   1088 }