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 * libpkixBuildThreads.c
6 *
7 * libpkix Builder Performance Evaluation application (multi-threaded)
8 *
9 */
10
11 #include <stdio.h>
12 #include <string.h>
13
14 #include "secutil.h"
15
16 #include "nspr.h"
17 #include "prtypes.h"
18 #include "prtime.h"
19 #include "prlong.h"
20
21 #include "pk11func.h"
22 #include "secasn1.h"
23 #include "cert.h"
24 #include "cryptohi.h"
25 #include "secoid.h"
26 #include "certdb.h"
27 #include "nss.h"
28
29 #include "pkix.h"
30 #include "pkix_tools.h"
31 #include "pkix_pl_cert.h"
32
33 #include "testutil.h"
34 #include "testutil_nss.h"
35
36 static void *plContext = NULL;
37
38 #undef pkixTempResult
39 #define PERF_DECREF(obj) \
40 { \
41 PKIX_Error *pkixTempResult = NULL; \
42 if (obj) { \
43 pkixTempResult = PKIX_PL_Object_DecRef((PKIX_PL_Object *)(obj), plContext); \
44 obj = NULL; \
45 } \
46 }
47
48 static void finish(char *message, int code);
49
50 typedef struct ThreadDataStr tData;
51
52 struct ThreadDataStr {
53 CERTCertificate *anchor;
54 char *eecertName;
55 PRIntervalTime duration;
56 CERTCertDBHandle *handle;
57 PRUint32 iterations;
58 };
59
60 #define PKIX_LOGGER_ON 1
61
62 #ifdef PKIX_LOGGER_ON
63
64 char *logLevels[] = {
65 "None",
66 "Fatal Error",
67 "Error",
68 "Warning",
69 "Debug",
70 "Trace"
71 };
72
73 static PKIX_Error *
loggerCallback(PKIX_Logger * logger,PKIX_PL_String * message,PKIX_UInt32 logLevel,PKIX_ERRORCLASS logComponent,void * plContext)74 loggerCallback(
75 PKIX_Logger *logger,
76 PKIX_PL_String *message,
77 PKIX_UInt32 logLevel,
78 PKIX_ERRORCLASS logComponent,
79 void *plContext)
80 {
81 char *msg = NULL;
82 static int callCount = 0;
83
84 msg = PKIX_String2ASCII(message, plContext);
85 printf("Logging %s (%s): %s\n",
86 logLevels[logLevel],
87 PKIX_ERRORCLASSNAMES[logComponent],
88 msg);
89 PR_Free((void *)msg);
90
91 return (NULL);
92 }
93
94 #endif /* PKIX_LOGGER_ON */
95
96 static void
ThreadEntry(void * data)97 ThreadEntry(void *data)
98 {
99 tData *tdata = (tData *)data;
100 PRIntervalTime duration = tdata->duration;
101 PRIntervalTime start = PR_IntervalNow();
102
103 PKIX_List *anchors = NULL;
104 PKIX_ProcessingParams *procParams = NULL;
105 PKIX_BuildResult *buildResult = NULL;
106 CERTCertificate *nsseecert;
107 PKIX_PL_Cert *eeCert = NULL;
108 PKIX_CertStore *certStore = NULL;
109 PKIX_List *certStores = NULL;
110 PKIX_ComCertSelParams *certSelParams = NULL;
111 PKIX_CertSelector *certSelector = NULL;
112 PKIX_PL_Date *nowDate = NULL;
113 void *state = NULL; /* only relevant with non-blocking I/O */
114 void *nbioContext = NULL; /* only relevant with non-blocking I/O */
115
116 PR_ASSERT(duration);
117 if (!duration) {
118 return;
119 }
120
121 do {
122
123 /* libpkix code */
124
125 /* keep more update time, testing cache */
126 PKIX_PL_Date_Create_UTCTime(NULL, &nowDate, plContext);
127
128 /* CertUsage is 0x10 and no NSS arena */
129 /* We haven't determined how we obtain the value of wincx */
130
131 nsseecert = CERT_FindCertByNicknameOrEmailAddr(tdata->handle,
132 tdata->eecertName);
133 if (!nsseecert)
134 finish("Unable to find eecert.\n", 1);
135
136 pkix_pl_Cert_CreateWithNSSCert(nsseecert, &eeCert, plContext);
137
138 PKIX_List_Create(&anchors, plContext);
139
140 /*
141 * This code is retired.
142 * pkix_pl_Cert_CreateWithNSSCert
143 * (tdata->anchor, &anchorCert, NULL);
144 * PKIX_TrustAnchor_CreateWithCert(anchorCert, &anchor, NULL);
145 * PKIX_List_AppendItem(anchors, (PKIX_PL_Object *)anchor, NULL);
146 */
147
148 PKIX_ProcessingParams_Create(anchors, &procParams, plContext);
149
150 PKIX_ProcessingParams_SetRevocationEnabled(procParams, PKIX_TRUE, plContext);
151
152 PKIX_ProcessingParams_SetDate(procParams, nowDate, plContext);
153
154 /* create CertSelector with target certificate in params */
155
156 PKIX_ComCertSelParams_Create(&certSelParams, plContext);
157
158 PKIX_ComCertSelParams_SetCertificate(certSelParams, eeCert, plContext);
159
160 PKIX_CertSelector_Create(NULL, NULL, &certSelector, plContext);
161
162 PKIX_CertSelector_SetCommonCertSelectorParams(certSelector, certSelParams, plContext);
163
164 PKIX_ProcessingParams_SetTargetCertConstraints(procParams, certSelector, plContext);
165
166 PKIX_PL_Pk11CertStore_Create(&certStore, plContext);
167
168 PKIX_List_Create(&certStores, plContext);
169 PKIX_List_AppendItem(certStores, (PKIX_PL_Object *)certStore, plContext);
170 PKIX_ProcessingParams_SetCertStores(procParams, certStores, plContext);
171
172 PKIX_BuildChain(procParams,
173 &nbioContext,
174 &state,
175 &buildResult,
176 NULL,
177 plContext);
178
179 /*
180 * As long as we use only CertStores with blocking I/O, we
181 * know we must be done at this point.
182 */
183
184 if (!buildResult) {
185 (void)fprintf(stderr, "libpkix BuildChain failed.\n");
186 PORT_Assert(0);
187 return;
188 }
189
190 tdata->iterations++;
191
192 PERF_DECREF(nowDate);
193 PERF_DECREF(anchors);
194 PERF_DECREF(procParams);
195 PERF_DECREF(buildResult);
196 PERF_DECREF(certStore);
197 PERF_DECREF(certStores);
198 PERF_DECREF(certSelParams);
199 PERF_DECREF(certSelector);
200 PERF_DECREF(eeCert);
201
202 } while ((PR_IntervalNow() - start) < duration);
203 }
204
205 static void
Test(CERTCertificate * anchor,char * eecertName,PRIntervalTime duration,CERTCertDBHandle * handle,PRUint32 threads)206 Test(
207 CERTCertificate *anchor,
208 char *eecertName,
209 PRIntervalTime duration,
210 CERTCertDBHandle *handle,
211 PRUint32 threads)
212 {
213 tData data;
214 tData **alldata;
215 PRIntervalTime starttime, endtime, elapsed;
216 PRUint32 msecs;
217 float total = 0;
218 PRThread **pthreads = NULL;
219 PRUint32 i = 0;
220
221 data.duration = duration;
222 data.anchor = anchor;
223 data.eecertName = eecertName;
224 data.handle = handle;
225
226 data.iterations = 0;
227
228 starttime = PR_IntervalNow();
229 pthreads = (PRThread **)PR_Malloc(threads * sizeof(PRThread *));
230 alldata = (tData **)PR_Malloc(threads * sizeof(tData *));
231 for (i = 0; i < threads; i++) {
232 alldata[i] = (tData *)PR_Malloc(sizeof(tData));
233 *alldata[i] = data;
234 pthreads[i] =
235 PR_CreateThread(PR_USER_THREAD,
236 ThreadEntry,
237 (void *)alldata[i],
238 PR_PRIORITY_NORMAL,
239 PR_GLOBAL_THREAD,
240 PR_JOINABLE_THREAD,
241 0);
242 }
243
244 for (i = 0; i < threads; i++) {
245 tData *args = alldata[i];
246 PR_JoinThread(pthreads[i]);
247 total += args->iterations;
248 PR_Free((void *)args);
249 }
250
251 PR_Free((void *)pthreads);
252 PR_Free((void *)alldata);
253 endtime = PR_IntervalNow();
254
255 endtime = PR_IntervalNow();
256 elapsed = endtime - starttime;
257 msecs = PR_IntervalToMilliseconds(elapsed);
258 total /= msecs;
259 total *= 1000;
260 (void)fprintf(stdout, "%f operations per second.\n", total);
261 }
262
263 static void
finish(char * message,int code)264 finish(char *message, int code)
265 {
266 (void)printf(message);
267 exit(code);
268 }
269
270 static void
usage(char * progname)271 usage(char *progname)
272 {
273 (void)printf("Usage : %s <-d certStoreDirectory> <duration> <threads> "
274 "<anchorNickname> <eecertNickname>\n\n",
275 progname);
276 finish("", 0);
277 }
278
279 int
libpkix_buildthreads(int argc,char ** argv)280 libpkix_buildthreads(int argc, char **argv)
281 {
282 CERTCertDBHandle *handle = NULL;
283 CERTCertificate *eecert = NULL;
284 PRIntervalTime duration = PR_SecondsToInterval(1);
285 PRUint32 threads = 1;
286 PKIX_UInt32 actualMinorVersion;
287 PKIX_UInt32 j = 0;
288 PKIX_Logger *logger = NULL;
289 void *wincx = NULL;
290
291 /* if (argc != 5) -- when TrustAnchor used to be on command line */
292 if (argc != 4) {
293 usage(argv[0]);
294 }
295 if (atoi(argv[1]) > 0) {
296 duration = PR_SecondsToInterval(atoi(argv[1]));
297 }
298 if (atoi(argv[2]) > 0) {
299 threads = atoi(argv[2]);
300 }
301
302 PKIX_PL_NssContext_Create(certificateUsageEmailSigner, PKIX_FALSE,
303 NULL, &plContext);
304
305 handle = CERT_GetDefaultCertDB();
306 PR_ASSERT(handle);
307
308 #ifdef PKIX_LOGGER_ON
309
310 /* set logger to log trace and up */
311 PKIX_SetLoggers(NULL, plContext);
312 PKIX_Logger_Create(loggerCallback, NULL, &logger, plContext);
313 PKIX_Logger_SetMaxLoggingLevel(logger, PKIX_LOGGER_LEVEL_WARNING, plContext);
314 PKIX_AddLogger(logger, plContext);
315
316 #endif /* PKIX_LOGGER_ON */
317
318 /*
319 * This code is retired
320 * anchor = CERT_FindCertByNicknameOrEmailAddr(handle, argv[3]);
321 * if (!anchor) finish("Unable to find anchor.\n", 1);
322 *
323 * eecert = CERT_FindCertByNicknameOrEmailAddr(handle, argv[4]);
324
325 * if (!eecert) finish("Unable to find eecert.\n", 1);
326 *
327 * Test(anchor, eecert, duration, threads);
328 */
329
330 Test(NULL, argv[3], duration, handle, threads);
331
332 PERF_DECREF(logger);
333
334 PKIX_Shutdown(plContext);
335
336 return (0);
337 }
338