PageRenderTime 83ms CodeModel.GetById 7ms app.highlight 69ms RepoModel.GetById 1ms app.codeStats 1ms

/security/nss/lib/libpkix/pkix/util/pkix_logger.c

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