michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: /* michael@0: * libpkixBuildThreads.c michael@0: * michael@0: * libpkix Builder Performance Evaluation application (multi-threaded) michael@0: * michael@0: */ michael@0: michael@0: #include michael@0: #include michael@0: michael@0: #include "secutil.h" michael@0: michael@0: #include "nspr.h" michael@0: #include "prtypes.h" michael@0: #include "prtime.h" michael@0: #include "prlong.h" michael@0: michael@0: #include "pk11func.h" michael@0: #include "secasn1.h" michael@0: #include "cert.h" michael@0: #include "cryptohi.h" michael@0: #include "secoid.h" michael@0: #include "certdb.h" michael@0: #include "nss.h" michael@0: michael@0: #include "pkix.h" michael@0: #include "pkix_tools.h" michael@0: #include "pkix_pl_cert.h" michael@0: michael@0: #include "testutil.h" michael@0: #include "testutil_nss.h" michael@0: michael@0: static void *plContext = NULL; michael@0: michael@0: #undef pkixTempResult michael@0: #define PERF_DECREF(obj) \ michael@0: { \ michael@0: PKIX_Error *pkixTempResult = NULL; \ michael@0: if (obj){ \ michael@0: pkixTempResult = PKIX_PL_Object_DecRef \ michael@0: ((PKIX_PL_Object *)(obj), plContext); \ michael@0: obj = NULL; \ michael@0: } \ michael@0: } michael@0: michael@0: static void finish(char* message, int code); michael@0: michael@0: typedef struct ThreadDataStr tData; michael@0: michael@0: struct ThreadDataStr { michael@0: CERTCertificate* anchor; michael@0: char* eecertName; michael@0: PRIntervalTime duration; michael@0: CERTCertDBHandle *handle; michael@0: PRUint32 iterations; michael@0: }; michael@0: michael@0: #define PKIX_LOGGER_ON 1 michael@0: michael@0: #ifdef PKIX_LOGGER_ON michael@0: michael@0: char *logLevels[] = { michael@0: "None", michael@0: "Fatal Error", michael@0: "Error", michael@0: "Warning", michael@0: "Debug", michael@0: "Trace" michael@0: }; michael@0: michael@0: static PKIX_Error *loggerCallback( michael@0: PKIX_Logger *logger, michael@0: PKIX_PL_String *message, michael@0: PKIX_UInt32 logLevel, michael@0: PKIX_ERRORCLASS logComponent, michael@0: void *plContext) michael@0: { michael@0: char *msg = NULL; michael@0: static int callCount = 0; michael@0: michael@0: msg = PKIX_String2ASCII(message, plContext); michael@0: printf("Logging %s (%s): %s\n", michael@0: logLevels[logLevel], michael@0: PKIX_ERRORCLASSNAMES[logComponent], michael@0: msg); michael@0: PR_Free((void *)msg); michael@0: michael@0: return(NULL); michael@0: } michael@0: michael@0: #endif /* PKIX_LOGGER_ON */ michael@0: michael@0: static void ThreadEntry(void* data) michael@0: { michael@0: tData* tdata = (tData*) data; michael@0: PRIntervalTime duration = tdata->duration; michael@0: PRIntervalTime start = PR_IntervalNow(); michael@0: michael@0: PKIX_List *anchors = NULL; michael@0: PKIX_ProcessingParams *procParams = NULL; michael@0: PKIX_BuildResult *buildResult = NULL; michael@0: CERTCertificate* nsseecert; michael@0: PKIX_PL_Cert *eeCert = NULL; michael@0: PKIX_CertStore *certStore = NULL; michael@0: PKIX_List *certStores = NULL; michael@0: PKIX_ComCertSelParams *certSelParams = NULL; michael@0: PKIX_CertSelector *certSelector = NULL; michael@0: PKIX_PL_Date *nowDate = NULL; michael@0: void *state = NULL; /* only relevant with non-blocking I/O */ michael@0: void *nbioContext = NULL; /* only relevant with non-blocking I/O */ michael@0: michael@0: PR_ASSERT(duration); michael@0: if (!duration){ michael@0: return; michael@0: } michael@0: michael@0: do { michael@0: michael@0: /* libpkix code */ michael@0: michael@0: /* keep more update time, testing cache */ michael@0: PKIX_PL_Date_Create_UTCTime(NULL, &nowDate, plContext); michael@0: michael@0: /* CertUsage is 0x10 and no NSS arena */ michael@0: /* We haven't determined how we obtain the value of wincx */ michael@0: michael@0: nsseecert = CERT_FindCertByNicknameOrEmailAddr(tdata->handle, michael@0: tdata->eecertName); michael@0: if (!nsseecert) finish("Unable to find eecert.\n", 1); michael@0: michael@0: pkix_pl_Cert_CreateWithNSSCert michael@0: (nsseecert, &eeCert, plContext); michael@0: michael@0: PKIX_List_Create(&anchors, plContext); michael@0: michael@0: /* michael@0: * This code is retired. michael@0: * pkix_pl_Cert_CreateWithNSSCert michael@0: * (tdata->anchor, &anchorCert, NULL); michael@0: * PKIX_TrustAnchor_CreateWithCert(anchorCert, &anchor, NULL); michael@0: * PKIX_List_AppendItem(anchors, (PKIX_PL_Object *)anchor, NULL); michael@0: */ michael@0: michael@0: PKIX_ProcessingParams_Create(anchors, &procParams, plContext); michael@0: michael@0: PKIX_ProcessingParams_SetRevocationEnabled michael@0: (procParams, PKIX_TRUE, plContext); michael@0: michael@0: PKIX_ProcessingParams_SetDate michael@0: (procParams, nowDate, plContext); michael@0: michael@0: /* create CertSelector with target certificate in params */ michael@0: michael@0: PKIX_ComCertSelParams_Create(&certSelParams, plContext); michael@0: michael@0: PKIX_ComCertSelParams_SetCertificate michael@0: (certSelParams, eeCert, plContext); michael@0: michael@0: PKIX_CertSelector_Create michael@0: (NULL, NULL, &certSelector, plContext); michael@0: michael@0: PKIX_CertSelector_SetCommonCertSelectorParams michael@0: (certSelector, certSelParams, plContext); michael@0: michael@0: PKIX_ProcessingParams_SetTargetCertConstraints michael@0: (procParams, certSelector, plContext); michael@0: michael@0: PKIX_PL_Pk11CertStore_Create(&certStore, plContext); michael@0: michael@0: PKIX_List_Create(&certStores, plContext); michael@0: PKIX_List_AppendItem michael@0: (certStores, (PKIX_PL_Object *)certStore, plContext); michael@0: PKIX_ProcessingParams_SetCertStores michael@0: (procParams, certStores, plContext); michael@0: michael@0: PKIX_BuildChain michael@0: (procParams, michael@0: &nbioContext, michael@0: &state, michael@0: &buildResult, michael@0: NULL, michael@0: plContext); michael@0: michael@0: /* michael@0: * As long as we use only CertStores with blocking I/O, we michael@0: * know we must be done at this point. michael@0: */ michael@0: michael@0: if (!buildResult){ michael@0: (void) fprintf(stderr, "libpkix BuildChain failed.\n"); michael@0: PORT_Assert(0); michael@0: return; michael@0: } michael@0: michael@0: tdata->iterations ++; michael@0: michael@0: PERF_DECREF(nowDate); michael@0: PERF_DECREF(anchors); michael@0: PERF_DECREF(procParams); michael@0: PERF_DECREF(buildResult); michael@0: PERF_DECREF(certStore); michael@0: PERF_DECREF(certStores); michael@0: PERF_DECREF(certSelParams); michael@0: PERF_DECREF(certSelector); michael@0: PERF_DECREF(eeCert); michael@0: michael@0: } while ((PR_IntervalNow() - start) < duration); michael@0: michael@0: michael@0: } michael@0: michael@0: static void michael@0: Test( michael@0: CERTCertificate* anchor, michael@0: char* eecertName, michael@0: PRIntervalTime duration, michael@0: CERTCertDBHandle *handle, michael@0: PRUint32 threads) michael@0: { michael@0: tData data; michael@0: tData** alldata; michael@0: PRIntervalTime starttime, endtime, elapsed; michael@0: PRUint32 msecs; michael@0: float total = 0; michael@0: PRThread** pthreads = NULL; michael@0: PRUint32 i = 0; michael@0: michael@0: data.duration = duration; michael@0: data.anchor = anchor; michael@0: data.eecertName = eecertName; michael@0: data.handle = handle; michael@0: michael@0: data.iterations = 0; michael@0: michael@0: starttime = PR_IntervalNow(); michael@0: pthreads = (PRThread**)PR_Malloc(threads*sizeof (PRThread*)); michael@0: alldata = (tData**)PR_Malloc(threads*sizeof (tData*)); michael@0: for (i = 0; i < threads; i++){ michael@0: alldata[i] = (tData*)PR_Malloc(sizeof (tData)); michael@0: *alldata[i] = data; michael@0: pthreads[i] = michael@0: PR_CreateThread(PR_USER_THREAD, michael@0: ThreadEntry, michael@0: (void*) alldata[i], michael@0: PR_PRIORITY_NORMAL, michael@0: PR_GLOBAL_THREAD, michael@0: PR_JOINABLE_THREAD, michael@0: 0); michael@0: } michael@0: michael@0: for (i = 0; i < threads; i++) { michael@0: tData* args = alldata[i]; michael@0: PR_JoinThread(pthreads[i]); michael@0: total += args->iterations; michael@0: PR_Free((void*)args); michael@0: } michael@0: michael@0: PR_Free((void*) pthreads); michael@0: PR_Free((void*) alldata); michael@0: endtime = PR_IntervalNow(); michael@0: michael@0: endtime = PR_IntervalNow(); michael@0: elapsed = endtime - starttime; michael@0: msecs = PR_IntervalToMilliseconds(elapsed); michael@0: total /= msecs; michael@0: total *= 1000; michael@0: (void) fprintf(stdout, "%f operations per second.\n", total); michael@0: } michael@0: michael@0: michael@0: static void finish(char* message, int code) michael@0: { michael@0: (void) printf(message); michael@0: exit(code); michael@0: } michael@0: michael@0: static void usage(char* progname) michael@0: { michael@0: (void) printf("Usage : %s <-d certStoreDirectory> " michael@0: " \n\n", progname); michael@0: finish("", 0); michael@0: } michael@0: michael@0: int michael@0: libpkix_buildthreads(int argc, char** argv) michael@0: { michael@0: CERTCertDBHandle *handle = NULL; michael@0: CERTCertificate* eecert = NULL; michael@0: PRIntervalTime duration = PR_SecondsToInterval(1); michael@0: PRUint32 threads = 1; michael@0: PKIX_UInt32 actualMinorVersion; michael@0: PKIX_UInt32 j = 0; michael@0: PKIX_Logger *logger = NULL; michael@0: void *wincx = NULL; michael@0: michael@0: /* if (argc != 5) -- when TrustAnchor used to be on command line */ michael@0: if (argc != 4) michael@0: { michael@0: usage(argv[0]); michael@0: } michael@0: if (atoi(argv[1]) > 0) michael@0: { michael@0: duration = PR_SecondsToInterval(atoi(argv[1])); michael@0: } michael@0: if (atoi(argv[2]) > 0) michael@0: { michael@0: threads = atoi(argv[2]); michael@0: } michael@0: michael@0: PKIX_PL_NssContext_Create(certificateUsageEmailSigner, PKIX_FALSE, michael@0: NULL, &plContext); michael@0: michael@0: handle = CERT_GetDefaultCertDB(); michael@0: PR_ASSERT(handle); michael@0: michael@0: #ifdef PKIX_LOGGER_ON michael@0: michael@0: /* set logger to log trace and up */ michael@0: PKIX_SetLoggers(NULL, plContext); michael@0: PKIX_Logger_Create(loggerCallback, NULL, &logger, plContext); michael@0: PKIX_Logger_SetMaxLoggingLevel michael@0: (logger, PKIX_LOGGER_LEVEL_WARNING, plContext); michael@0: PKIX_AddLogger(logger, plContext); michael@0: michael@0: #endif /* PKIX_LOGGER_ON */ michael@0: michael@0: /* michael@0: * This code is retired michael@0: * anchor = CERT_FindCertByNicknameOrEmailAddr(handle, argv[3]); michael@0: * if (!anchor) finish("Unable to find anchor.\n", 1); michael@0: * michael@0: * eecert = CERT_FindCertByNicknameOrEmailAddr(handle, argv[4]); michael@0: michael@0: * if (!eecert) finish("Unable to find eecert.\n", 1); michael@0: * michael@0: * Test(anchor, eecert, duration, threads); michael@0: */ michael@0: michael@0: Test(NULL, argv[3], duration, handle, threads); michael@0: michael@0: PERF_DECREF(logger); michael@0: michael@0: PKIX_Shutdown(plContext); michael@0: michael@0: return (0); michael@0: }