7ab0aa5d619e252a183c5d23fa56bf3082c93a68
[platform/upstream/nss.git] / nss / cmd / strsclnt / strsclnt.c
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 #include <stdio.h>
5 #include <string.h>
6
7 #include "secutil.h"
8 #include "basicutil.h"
9
10 #if defined(XP_UNIX)
11 #include <unistd.h>
12 #endif
13 #include <stdlib.h>
14 #include <errno.h>
15 #include <fcntl.h>
16 #include <stdarg.h>
17
18 #include "plgetopt.h"
19
20 #include "nspr.h"
21 #include "prio.h"
22 #include "prnetdb.h"
23 #include "prerror.h"
24
25 #include "pk11func.h"
26 #include "secitem.h"
27 #include "sslproto.h"
28 #include "nss.h"
29 #include "ssl.h"
30
31 #ifndef PORT_Sprintf
32 #define PORT_Sprintf sprintf
33 #endif
34
35 #ifndef PORT_Strstr
36 #define PORT_Strstr strstr
37 #endif
38
39 #ifndef PORT_Malloc
40 #define PORT_Malloc PR_Malloc
41 #endif
42
43 #define RD_BUF_SIZE (60 * 1024)
44
45 /* Include these cipher suite arrays to re-use tstclnt's 
46  * cipher selection code.
47  */
48
49 int ssl2CipherSuites[] = {
50     SSL_EN_RC4_128_WITH_MD5,                    /* A */
51     SSL_EN_RC4_128_EXPORT40_WITH_MD5,           /* B */
52     SSL_EN_RC2_128_CBC_WITH_MD5,                /* C */
53     SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5,       /* D */
54     SSL_EN_DES_64_CBC_WITH_MD5,                 /* E */
55     SSL_EN_DES_192_EDE3_CBC_WITH_MD5,           /* F */
56     0
57 };
58
59 int ssl3CipherSuites[] = {
60     -1, /* SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA* a */
61     -1, /* SSL_FORTEZZA_DMS_WITH_RC4_128_SHA     * b */
62     SSL_RSA_WITH_RC4_128_MD5,                   /* c */
63     SSL_RSA_WITH_3DES_EDE_CBC_SHA,              /* d */
64     SSL_RSA_WITH_DES_CBC_SHA,                   /* e */
65     SSL_RSA_EXPORT_WITH_RC4_40_MD5,             /* f */
66     SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5,         /* g */
67     -1, /* SSL_FORTEZZA_DMS_WITH_NULL_SHA        * h */
68     SSL_RSA_WITH_NULL_MD5,                      /* i */
69     SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA,         /* j */
70     SSL_RSA_FIPS_WITH_DES_CBC_SHA,              /* k */
71     TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA,        /* l */
72     TLS_RSA_EXPORT1024_WITH_RC4_56_SHA,         /* m */
73     SSL_RSA_WITH_RC4_128_SHA,                   /* n */
74     TLS_DHE_DSS_WITH_RC4_128_SHA,               /* o */
75     SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA,          /* p */
76     SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA,          /* q */
77     SSL_DHE_RSA_WITH_DES_CBC_SHA,               /* r */
78     SSL_DHE_DSS_WITH_DES_CBC_SHA,               /* s */
79     TLS_DHE_DSS_WITH_AES_128_CBC_SHA,           /* t */
80     TLS_DHE_RSA_WITH_AES_128_CBC_SHA,           /* u */
81     TLS_RSA_WITH_AES_128_CBC_SHA,               /* v */
82     TLS_DHE_DSS_WITH_AES_256_CBC_SHA,           /* w */
83     TLS_DHE_RSA_WITH_AES_256_CBC_SHA,           /* x */
84     TLS_RSA_WITH_AES_256_CBC_SHA,               /* y */
85     SSL_RSA_WITH_NULL_SHA,                      /* z */
86     0
87 };
88
89 #define NO_FULLHS_PERCENTAGE -1
90
91 /* This global string is so that client main can see 
92  * which ciphers to use. 
93  */
94
95 static const char *cipherString;
96
97 static PRInt32 certsTested;
98 static int MakeCertOK;
99 static int NoReuse;
100 static int fullhs = NO_FULLHS_PERCENTAGE; /* percentage of full handshakes to
101                                           ** perform */
102 static PRInt32 globalconid = 0; /* atomically set */
103 static int total_connections;  /* total number of connections to perform */
104 static int total_connections_rounded_down_to_hundreds;
105 static int total_connections_modulo_100;
106
107 static PRBool NoDelay;
108 static PRBool QuitOnTimeout = PR_FALSE;
109 static PRBool ThrottleUp = PR_FALSE;
110
111 static PRLock    * threadLock; /* protects the global variables below */
112 static PRTime lastConnectFailure;
113 static PRTime lastConnectSuccess;
114 static PRTime lastThrottleUp;
115 static PRInt32 remaining_connections;  /* number of connections left */
116 static int active_threads = 8; /* number of threads currently trying to
117                                ** connect */
118 static PRInt32 numUsed;
119 /* end of variables protected by threadLock */
120
121 static SSL3Statistics * ssl3stats;
122
123 static int failed_already = 0;
124 static SSLVersionRange enabledVersions;
125 static PRBool enableSSL2      = PR_TRUE;
126 static PRBool bypassPKCS11    = PR_FALSE;
127 static PRBool disableLocking  = PR_FALSE;
128 static PRBool ignoreErrors    = PR_FALSE;
129 static PRBool enableSessionTickets = PR_FALSE;
130 static PRBool enableCompression    = PR_FALSE;
131 static PRBool enableFalseStart     = PR_FALSE;
132 static PRBool enableCertStatus     = PR_FALSE;
133
134 PRIntervalTime maxInterval    = PR_INTERVAL_NO_TIMEOUT;
135
136 char * progName;
137
138 secuPWData pwdata = { PW_NONE, 0 };
139
140 int     stopping;
141 int     verbose;
142 SECItem bigBuf;
143
144 #define PRINTF  if (verbose)  printf
145 #define FPRINTF if (verbose) fprintf
146
147 static void
148 Usage(const char *progName)
149 {
150     fprintf(stderr, 
151         "Usage: %s [-n nickname] [-p port] [-d dbdir] [-c connections]\n"
152         "          [-BDNovqs] [-f filename] [-N | -P percentage]\n"
153         "          [-w dbpasswd] [-C cipher(s)] [-t threads] [-W pwfile]\n"
154         "          [-V [min-version]:[max-version]] [-a sniHostName] hostname\n"
155         " where -v means verbose\n"
156         "       -o flag is interpreted as follows:\n"
157         "          1 -o   means override the result of server certificate validation.\n"
158         "          2 -o's mean skip server certificate validation altogether.\n"
159         "       -D means no TCP delays\n"
160         "       -q means quit when server gone (timeout rather than retry forever)\n"
161         "       -s means disable SSL socket locking\n"
162         "       -N means no session reuse\n"
163         "       -P means do a specified percentage of full handshakes (0-100)\n"
164         "       -V [min]:[max] restricts the set of enabled SSL/TLS protocols versions.\n"
165         "          All versions are enabled by default.\n"
166         "          Possible values for min/max: ssl2 ssl3 tls1.0 tls1.1 tls1.2\n"
167         "          Example: \"-V ssl3:\" enables SSL 3 and newer.\n"
168         "       -U means enable throttling up threads\n"
169         "       -B bypasses the PKCS11 layer for SSL encryption and MACing\n"
170         "       -T enable the cert_status extension (OCSP stapling)\n"
171         "       -u enable TLS Session Ticket extension\n"
172         "       -z enable compression\n"
173         "       -g enable false start\n",
174         progName);
175     exit(1);
176 }
177
178
179 static void
180 errWarn(char * funcString)
181 {
182     PRErrorCode  perr      = PR_GetError();
183     const char * errString = SECU_Strerror(perr);
184
185     fprintf(stderr, "strsclnt: %s returned error %d:\n%s\n",
186             funcString, perr, errString);
187 }
188
189 static void
190 errExit(char * funcString)
191 {
192     errWarn(funcString);
193     exit(1);
194 }
195
196 /**************************************************************************
197 ** 
198 ** Routines for disabling SSL ciphers.
199 **
200 **************************************************************************/
201
202 void
203 disableAllSSLCiphers(void)
204 {
205     const PRUint16 *cipherSuites = SSL_GetImplementedCiphers();
206     int             i            = SSL_GetNumImplementedCiphers();
207     SECStatus       rv;
208
209     /* disable all the SSL3 cipher suites */
210     while (--i >= 0) {
211         PRUint16 suite = cipherSuites[i];
212         rv = SSL_CipherPrefSetDefault(suite, PR_FALSE);
213         if (rv != SECSuccess) {
214             printf("SSL_CipherPrefSetDefault didn't like value 0x%04x (i = %d)\n",
215                    suite, i);
216             errWarn("SSL_CipherPrefSetDefault");
217             exit(2);
218         }
219     }
220 }
221
222 /* This invokes the "default" AuthCert handler in libssl.
223 ** The only reason to use this one is that it prints out info as it goes. 
224 */
225 static SECStatus
226 mySSLAuthCertificate(void *arg, PRFileDesc *fd, PRBool checkSig,
227                      PRBool isServer)
228 {
229     SECStatus rv;
230     CERTCertificate *    peerCert;
231     const SECItemArray *csa;
232
233     if (MakeCertOK>=2) {
234         return SECSuccess;
235     }
236     peerCert = SSL_PeerCertificate(fd);
237
238     PRINTF("strsclnt: Subject: %s\nstrsclnt: Issuer : %s\n", 
239            peerCert->subjectName, peerCert->issuerName); 
240     csa = SSL_PeerStapledOCSPResponses(fd);
241     if (csa) {
242         PRINTF("Received %d Cert Status items (OCSP stapled data)\n",
243                csa->len);
244     }
245     /* invoke the "default" AuthCert handler. */
246     rv = SSL_AuthCertificate(arg, fd, checkSig, isServer);
247
248     PR_ATOMIC_INCREMENT(&certsTested);
249     if (rv == SECSuccess) {
250         fputs("strsclnt: -- SSL: Server Certificate Validated.\n", stderr);
251     }
252     CERT_DestroyCertificate(peerCert);
253     /* error, if any, will be displayed by the Bad Cert Handler. */
254     return rv;  
255 }
256
257 static SECStatus
258 myBadCertHandler( void *arg, PRFileDesc *fd)
259 {
260     PRErrorCode err = PR_GetError();
261     if (!MakeCertOK)
262         fprintf(stderr, 
263             "strsclnt: -- SSL: Server Certificate Invalid, err %d.\n%s\n", 
264             err, SECU_Strerror(err));
265     return (MakeCertOK ? SECSuccess : SECFailure);
266 }
267
268 void 
269 printSecurityInfo(PRFileDesc *fd)
270 {
271     CERTCertificate * cert = NULL;
272     SSL3Statistics * ssl3stats = SSL_GetStatistics();
273     SECStatus result;
274     SSLChannelInfo    channel;
275     SSLCipherSuiteInfo suite;
276
277     static int only_once;
278
279     if (only_once && verbose < 2)
280         return;
281     only_once = 1;
282
283     result = SSL_GetChannelInfo(fd, &channel, sizeof channel);
284     if (result == SECSuccess && 
285         channel.length == sizeof channel && 
286         channel.cipherSuite) {
287         result = SSL_GetCipherSuiteInfo(channel.cipherSuite, 
288                                         &suite, sizeof suite);
289         if (result == SECSuccess) {
290             FPRINTF(stderr, 
291             "strsclnt: SSL version %d.%d using %d-bit %s with %d-bit %s MAC\n",
292                channel.protocolVersion >> 8, channel.protocolVersion & 0xff,
293                suite.effectiveKeyBits, suite.symCipherName, 
294                suite.macBits, suite.macAlgorithmName);
295             FPRINTF(stderr, 
296             "strsclnt: Server Auth: %d-bit %s, Key Exchange: %d-bit %s\n"
297             "          Compression: %s\n",
298                channel.authKeyBits, suite.authAlgorithmName,
299                channel.keaKeyBits,  suite.keaTypeName,
300                channel.compressionMethodName);
301         }
302     }
303
304     cert = SSL_LocalCertificate(fd);
305     if (!cert)
306         cert = SSL_PeerCertificate(fd);
307
308     if (verbose && cert) {
309         char * ip = CERT_NameToAscii(&cert->issuer);
310         char * sp = CERT_NameToAscii(&cert->subject);
311         if (sp) {
312             fprintf(stderr, "strsclnt: subject DN: %s\n", sp);
313             PORT_Free(sp);
314         }
315         if (ip) {
316             fprintf(stderr, "strsclnt: issuer  DN: %s\n", ip);
317             PORT_Free(ip);
318         }
319     }
320     if (cert) {
321         CERT_DestroyCertificate(cert);
322         cert = NULL;
323     }
324     fprintf(stderr,
325         "strsclnt: %ld cache hits; %ld cache misses, %ld cache not reusable\n"
326         "          %ld stateless resumes\n",
327         ssl3stats->hsh_sid_cache_hits, 
328         ssl3stats->hsh_sid_cache_misses,
329         ssl3stats->hsh_sid_cache_not_ok,
330         ssl3stats->hsh_sid_stateless_resumes);
331
332 }
333
334 /**************************************************************************
335 ** Begin thread management routines and data.
336 **************************************************************************/
337
338 #define MAX_THREADS 128
339
340 typedef int startFn(void *a, void *b, int c);
341
342
343 static PRInt32     numConnected;
344 static int         max_threads;    /* peak threads allowed */
345
346 typedef struct perThreadStr {
347     void *      a;
348     void *      b;
349     int         tid;
350     int         rv;
351     startFn  *  startFunc;
352     PRThread *  prThread;
353     PRBool      inUse;
354 } perThread;
355
356 perThread threads[MAX_THREADS];
357
358 void
359 thread_wrapper(void * arg)
360 {
361     perThread * slot = (perThread *)arg;
362     PRBool done = PR_FALSE;
363
364     do {
365         PRBool doop = PR_FALSE;
366         PRBool dosleep = PR_FALSE;
367         PRTime now = PR_Now();
368
369         PR_Lock(threadLock);
370         if (! (slot->tid < active_threads)) {
371             /* this thread isn't supposed to be running */
372             if (!ThrottleUp) {
373                 /* we'll never need this thread again, so abort it */
374                 done = PR_TRUE;
375             } else if (remaining_connections > 0) {
376                 /* we may still need this thread, so just sleep for 1s */
377                 dosleep = PR_TRUE;
378                 /* the conditions to trigger a throttle up are :
379                 ** 1. last PR_Connect failure must have happened more than
380                 **    10s ago
381                 ** 2. last throttling up must have happened more than 0.5s ago
382                 ** 3. there must be a more recent PR_Connect success than
383                 **    failure
384                 */
385                 if ( (now - lastConnectFailure > 10 * PR_USEC_PER_SEC) &&
386                     ( (!lastThrottleUp) || ( (now - lastThrottleUp) >=
387                                              (PR_USEC_PER_SEC/2)) ) &&
388                     (lastConnectSuccess > lastConnectFailure) ) {
389                     /* try throttling up by one thread */
390                     active_threads = PR_MIN(max_threads, active_threads+1);
391                     fprintf(stderr,"active_threads set up to %d\n",
392                             active_threads);
393                     lastThrottleUp = PR_MAX(now, lastThrottleUp);
394                 }
395             } else {
396                 /* no more connections left, we are done */
397                 done = PR_TRUE;
398             }
399         } else {
400             /* this thread should run */
401             if (--remaining_connections >= 0) { /* protected by threadLock */
402                 doop = PR_TRUE;
403             } else {
404                 done = PR_TRUE;
405             }
406         }
407         PR_Unlock(threadLock);
408         if (doop) {
409             slot->rv = (* slot->startFunc)(slot->a, slot->b, slot->tid);
410             PRINTF("strsclnt: Thread in slot %d returned %d\n", 
411                    slot->tid, slot->rv);
412         }
413         if (dosleep) {
414             PR_Sleep(PR_SecondsToInterval(1));
415         }
416     } while (!done && (!failed_already || ignoreErrors));
417 }
418
419 SECStatus
420 launch_thread(
421     startFn *   startFunc,
422     void *      a,
423     void *      b,
424     int         tid)
425 {
426     PRUint32 i;
427     perThread * slot;
428
429     PR_Lock(threadLock);
430
431     PORT_Assert(numUsed < MAX_THREADS);
432     if (! (numUsed < MAX_THREADS)) {
433         PR_Unlock(threadLock);
434         return SECFailure;
435     }
436
437     i = numUsed++;
438     slot = &threads[i];
439     slot->a = a;
440     slot->b = b;
441     slot->tid = tid;
442
443     slot->startFunc = startFunc;
444
445     slot->prThread      = PR_CreateThread(PR_USER_THREAD,
446                                       thread_wrapper, slot,
447                                       PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
448                                       PR_JOINABLE_THREAD, 0);
449     if (slot->prThread == NULL) {
450         PR_Unlock(threadLock);
451         printf("strsclnt: Failed to launch thread!\n");
452         return SECFailure;
453     } 
454
455     slot->inUse   = 1;
456     PR_Unlock(threadLock);
457     PRINTF("strsclnt: Launched thread in slot %d \n", i);
458
459     return SECSuccess;
460 }
461
462 /* join all the threads */
463 int 
464 reap_threads(void)
465 {
466     int         i;
467
468     for (i = 0; i < MAX_THREADS; ++i) {
469         if (threads[i].prThread) {
470             PR_JoinThread(threads[i].prThread);
471             threads[i].prThread = NULL;
472         }
473     }
474     return 0;
475 }
476
477 void
478 destroy_thread_data(void)
479 {
480     PORT_Memset(threads, 0, sizeof threads);
481
482     if (threadLock) {
483         PR_DestroyLock(threadLock);
484         threadLock = NULL;
485     }
486 }
487
488 void
489 init_thread_data(void)
490 {
491     threadLock = PR_NewLock();
492 }
493
494 /**************************************************************************
495 ** End   thread management routines.
496 **************************************************************************/
497
498 PRBool useModelSocket = PR_TRUE;
499
500 static const char stopCmd[] = { "GET /stop " };
501 static const char outHeader[] = {
502     "HTTP/1.0 200 OK\r\n"
503     "Server: Netscape-Enterprise/2.0a\r\n"
504     "Date: Tue, 26 Aug 1997 22:10:05 GMT\r\n"
505     "Content-type: text/plain\r\n"
506     "\r\n"
507 };
508
509 struct lockedVarsStr {
510     PRLock *    lock;
511     int         count;
512     int         waiters;
513     PRCondVar * condVar;
514 };
515
516 typedef struct lockedVarsStr lockedVars;
517
518 void 
519 lockedVars_Init( lockedVars * lv)
520 {
521     lv->count   = 0;
522     lv->waiters = 0;
523     lv->lock    = PR_NewLock();
524     lv->condVar = PR_NewCondVar(lv->lock);
525 }
526
527 void
528 lockedVars_Destroy( lockedVars * lv)
529 {
530     PR_DestroyCondVar(lv->condVar);
531     lv->condVar = NULL;
532
533     PR_DestroyLock(lv->lock);
534     lv->lock = NULL;
535 }
536
537 void
538 lockedVars_WaitForDone(lockedVars * lv)
539 {
540     PR_Lock(lv->lock);
541     while (lv->count > 0) {
542         PR_WaitCondVar(lv->condVar, PR_INTERVAL_NO_TIMEOUT);
543     }
544     PR_Unlock(lv->lock);
545 }
546
547 int     /* returns count */
548 lockedVars_AddToCount(lockedVars * lv, int addend)
549 {
550     int rv;
551
552     PR_Lock(lv->lock);
553     rv = lv->count += addend;
554     if (rv <= 0) {
555         PR_NotifyCondVar(lv->condVar);
556     }
557     PR_Unlock(lv->lock);
558     return rv;
559 }
560
561 int
562 do_writes(
563     void *       a,
564     void *       b,
565     int          c)
566 {
567     PRFileDesc *        ssl_sock        = (PRFileDesc *)a;
568     lockedVars *        lv              = (lockedVars *)b;
569     int                 sent            = 0;
570     int                 count           = 0;
571
572     while (sent < bigBuf.len) {
573
574         count = PR_Send(ssl_sock, bigBuf.data + sent, bigBuf.len - sent, 
575                         0, maxInterval);
576         if (count < 0) {
577             errWarn("PR_Send bigBuf");
578             break;
579         }
580         FPRINTF(stderr, "strsclnt: PR_Send wrote %d bytes from bigBuf\n", 
581                 count );
582         sent += count;
583     }
584     if (count >= 0) {   /* last write didn't fail. */
585         PR_Shutdown(ssl_sock, PR_SHUTDOWN_SEND);
586     }
587
588     /* notify the reader that we're done. */
589     lockedVars_AddToCount(lv, -1);
590     return (sent < bigBuf.len) ? SECFailure : SECSuccess;
591 }
592
593 int 
594 handle_fdx_connection( PRFileDesc * ssl_sock, int connection)
595 {
596     SECStatus          result;
597     int                firstTime = 1;
598     int                countRead = 0;
599     lockedVars         lv;
600     char               *buf;
601
602
603     lockedVars_Init(&lv);
604     lockedVars_AddToCount(&lv, 1);
605
606     /* Attempt to launch the writer thread. */
607     result = launch_thread(do_writes, ssl_sock, &lv, connection);
608
609     if (result != SECSuccess) 
610         goto cleanup;
611
612     buf = PR_Malloc(RD_BUF_SIZE);
613
614     if (buf) {
615         do {
616             /* do reads here. */
617             PRInt32 count;
618
619             count = PR_Recv(ssl_sock, buf, RD_BUF_SIZE, 0, maxInterval);
620             if (count < 0) {
621                 errWarn("PR_Recv");
622                 break;
623             }
624             countRead += count;
625             FPRINTF(stderr, 
626                     "strsclnt: connection %d read %d bytes (%d total).\n", 
627                     connection, count, countRead );
628             if (firstTime) {
629                 firstTime = 0;
630                 printSecurityInfo(ssl_sock);
631             }
632         } while (lockedVars_AddToCount(&lv, 0) > 0);
633         PR_Free(buf);
634         buf = 0;
635     }
636
637     /* Wait for writer to finish */
638     lockedVars_WaitForDone(&lv);
639     lockedVars_Destroy(&lv);
640
641     FPRINTF(stderr, 
642     "strsclnt: connection %d read %d bytes total. -----------------------\n", 
643             connection, countRead);
644
645 cleanup:
646     /* Caller closes the socket. */
647
648     return SECSuccess;
649 }
650
651 const char request[] = {"GET /abc HTTP/1.0\r\n\r\n" };
652
653 SECStatus
654 handle_connection( PRFileDesc *ssl_sock, int tid)
655 {
656     int     countRead = 0;
657     PRInt32 rv;
658     char    *buf;
659
660     buf = PR_Malloc(RD_BUF_SIZE);
661     if (!buf)
662         return SECFailure;
663
664     /* compose the http request here. */
665
666     rv = PR_Send(ssl_sock, request, strlen(request), 0, maxInterval);
667     if (rv <= 0) {
668         errWarn("PR_Send");
669         PR_Free(buf);
670         buf = 0;
671         failed_already = 1;
672         return SECFailure;
673     }
674     printSecurityInfo(ssl_sock);
675
676     /* read until EOF */
677     while (1) {
678         rv = PR_Recv(ssl_sock, buf, RD_BUF_SIZE, 0, maxInterval);
679         if (rv == 0) {
680             break;      /* EOF */
681         }
682         if (rv < 0) {
683             errWarn("PR_Recv");
684             failed_already = 1;
685             break;
686         }
687
688         countRead += rv;
689         FPRINTF(stderr,
690                 "strsclnt: connection on thread %d read %d bytes (%d total).\n",
691                 tid, rv, countRead );
692     }
693     PR_Free(buf);
694     buf = 0;
695
696     /* Caller closes the socket. */
697
698     FPRINTF(stderr, 
699     "strsclnt: connection on thread %d read %d bytes total. ---------\n", 
700             tid, countRead);
701
702     return SECSuccess;  /* success */
703 }
704
705 #define USE_SOCK_PEER_ID 1
706
707 #ifdef USE_SOCK_PEER_ID
708
709 PRInt32 lastFullHandshakePeerID;
710
711 void
712 myHandshakeCallback(PRFileDesc *socket, void *arg) 
713 {
714     PR_ATOMIC_SET(&lastFullHandshakePeerID, (PRInt32) arg);
715 }
716
717 #endif
718
719 /* one copy of this function is launched in a separate thread for each
720 ** connection to be made.
721 */
722 int
723 do_connects(
724     void *      a,
725     void *      b,
726     int         tid)
727 {
728     PRNetAddr  *        addr            = (PRNetAddr *)  a;
729     PRFileDesc *        model_sock      = (PRFileDesc *) b;
730     PRFileDesc *        ssl_sock        = 0;
731     PRFileDesc *        tcp_sock        = 0;
732     PRStatus            prStatus;
733     PRUint32            sleepInterval   = 50; /* milliseconds */
734     SECStatus           result;
735     int                 rv              = SECSuccess;
736     PRSocketOptionData  opt;
737
738 retry:
739
740     tcp_sock = PR_OpenTCPSocket(addr->raw.family);
741     if (tcp_sock == NULL) {
742         errExit("PR_OpenTCPSocket");
743     }
744
745     opt.option             = PR_SockOpt_Nonblocking;
746     opt.value.non_blocking = PR_FALSE;
747     prStatus = PR_SetSocketOption(tcp_sock, &opt);
748     if (prStatus != PR_SUCCESS) {
749         errWarn("PR_SetSocketOption(PR_SockOpt_Nonblocking, PR_FALSE)");
750         PR_Close(tcp_sock);
751         return SECSuccess;
752     } 
753
754     if (NoDelay) {
755         opt.option         = PR_SockOpt_NoDelay;
756         opt.value.no_delay = PR_TRUE;
757         prStatus = PR_SetSocketOption(tcp_sock, &opt);
758         if (prStatus != PR_SUCCESS) {
759             errWarn("PR_SetSocketOption(PR_SockOpt_NoDelay, PR_TRUE)");
760             PR_Close(tcp_sock);
761             return SECSuccess;
762         } 
763     }
764
765     prStatus = PR_Connect(tcp_sock, addr, PR_INTERVAL_NO_TIMEOUT);
766     if (prStatus != PR_SUCCESS) {
767         PRErrorCode err = PR_GetError(); /* save error code */
768         if (ThrottleUp) {
769             PRTime now = PR_Now();
770             PR_Lock(threadLock);
771             lastConnectFailure = PR_MAX(now, lastConnectFailure);
772             PR_Unlock(threadLock);
773         }
774         if ((err == PR_CONNECT_REFUSED_ERROR) || 
775             (err == PR_CONNECT_RESET_ERROR)      ) {
776             int connections = numConnected;
777
778             PR_Close(tcp_sock);
779             PR_Lock(threadLock);
780             if (connections > 2 && active_threads >= connections) {
781                 active_threads = connections - 1;
782                 fprintf(stderr,"active_threads set down to %d\n",
783                         active_threads);
784             }
785             PR_Unlock(threadLock);
786
787             if (QuitOnTimeout && sleepInterval > 40000) {
788                 fprintf(stderr,
789                     "strsclnt: Client timed out waiting for connection to server.\n");
790                 exit(1);
791             }
792             PR_Sleep(PR_MillisecondsToInterval(sleepInterval));
793             sleepInterval <<= 1;
794             goto retry;
795         }
796         errWarn("PR_Connect");
797         rv = SECFailure;
798         goto done;
799     } else {
800         if (ThrottleUp) {
801             PRTime now = PR_Now();
802             PR_Lock(threadLock);
803             lastConnectSuccess = PR_MAX(now, lastConnectSuccess);
804             PR_Unlock(threadLock);
805         }
806     }
807
808     ssl_sock = SSL_ImportFD(model_sock, tcp_sock);
809     /* XXX if this import fails, close tcp_sock and return. */
810     if (!ssl_sock) {
811         PR_Close(tcp_sock);
812         return SECSuccess;
813     }
814     if (fullhs != NO_FULLHS_PERCENTAGE) {
815 #ifdef USE_SOCK_PEER_ID
816         char sockPeerIDString[512];
817         static PRInt32 sockPeerID = 0; /* atomically incremented */
818         PRInt32 thisPeerID;
819 #endif
820         PRInt32 savid = PR_ATOMIC_INCREMENT(&globalconid);
821         PRInt32 conid = 1 + (savid - 1) % 100;
822         /* don't change peer ID on the very first handshake, which is always
823            a full, so the session gets stored into the client cache */
824         if ( (savid != 1) &&
825             ( ( (savid <= total_connections_rounded_down_to_hundreds) &&
826                 (conid <= fullhs) ) ||
827               (conid*100 <= total_connections_modulo_100*fullhs ) ) ) 
828 #ifdef USE_SOCK_PEER_ID
829         {
830             /* force a full handshake by changing the socket peer ID */
831             thisPeerID = PR_ATOMIC_INCREMENT(&sockPeerID);
832         } else {
833             /* reuse previous sockPeerID for restart handhsake */
834             thisPeerID = lastFullHandshakePeerID;
835         }
836         PR_snprintf(sockPeerIDString, sizeof(sockPeerIDString), "ID%d",
837                     thisPeerID);
838         SSL_SetSockPeerID(ssl_sock, sockPeerIDString);
839         SSL_HandshakeCallback(ssl_sock, myHandshakeCallback, (void*)thisPeerID);
840 #else
841             /* force a full handshake by setting the no cache option */
842             SSL_OptionSet(ssl_sock, SSL_NO_CACHE, 1);
843 #endif
844     }
845     rv = SSL_ResetHandshake(ssl_sock, /* asServer */ 0);
846     if (rv != SECSuccess) {
847         errWarn("SSL_ResetHandshake");
848         goto done;
849     }
850
851     PR_ATOMIC_INCREMENT(&numConnected);
852
853     if (bigBuf.data != NULL) {
854         result = handle_fdx_connection( ssl_sock, tid);
855     } else {
856         result = handle_connection( ssl_sock, tid);
857     }
858
859     PR_ATOMIC_DECREMENT(&numConnected);
860
861 done:
862     if (ssl_sock) {
863         PR_Close(ssl_sock);
864     } else if (tcp_sock) {
865         PR_Close(tcp_sock);
866     }
867     return SECSuccess;
868 }
869
870
871 typedef struct {
872     PRLock* lock;
873     char* nickname;
874     CERTCertificate* cert;
875     SECKEYPrivateKey* key;
876     void* wincx;
877 } cert_and_key;
878
879 PRBool FindCertAndKey(cert_and_key* Cert_And_Key)
880 {
881     if ( (NULL == Cert_And_Key->nickname) || (0 == strcmp(Cert_And_Key->nickname,"none"))) {
882         return PR_TRUE;
883     }
884     Cert_And_Key->cert = CERT_FindUserCertByUsage(CERT_GetDefaultCertDB(),
885                             Cert_And_Key->nickname, certUsageSSLClient,
886                             PR_FALSE, Cert_And_Key->wincx);
887     if (Cert_And_Key->cert) {
888         Cert_And_Key->key = PK11_FindKeyByAnyCert(Cert_And_Key->cert, Cert_And_Key->wincx);
889     }
890     if (Cert_And_Key->cert && Cert_And_Key->key) {
891         return PR_TRUE;
892     } else {
893         return PR_FALSE;
894     }
895 }
896
897 PRBool LoggedIn(CERTCertificate* cert, SECKEYPrivateKey* key)
898 {
899     if ( (cert->slot) && (key->pkcs11Slot) &&
900          (PR_TRUE == PK11_IsLoggedIn(cert->slot, NULL)) &&
901          (PR_TRUE == PK11_IsLoggedIn(key->pkcs11Slot, NULL)) ) {
902         return PR_TRUE;
903     }
904  
905     return PR_FALSE;
906 }
907
908 SECStatus 
909 StressClient_GetClientAuthData(void * arg,
910                       PRFileDesc * socket,
911                       struct CERTDistNamesStr * caNames,
912                       struct CERTCertificateStr ** pRetCert,
913                       struct SECKEYPrivateKeyStr **pRetKey)
914 {
915     cert_and_key* Cert_And_Key = (cert_and_key*) arg;
916
917     if (!pRetCert || !pRetKey) {
918         /* bad pointers, can't return a cert or key */
919         return SECFailure;
920     }
921
922     *pRetCert = NULL;
923     *pRetKey = NULL;
924
925     if (Cert_And_Key && Cert_And_Key->nickname) {
926         while (PR_TRUE) {
927             if (Cert_And_Key && Cert_And_Key->lock) {
928                 int timeout = 0;
929                 PR_Lock(Cert_And_Key->lock);
930
931                 if (Cert_And_Key->cert) {
932                     *pRetCert = CERT_DupCertificate(Cert_And_Key->cert);
933                 }
934
935                 if (Cert_And_Key->key) {
936                     *pRetKey = SECKEY_CopyPrivateKey(Cert_And_Key->key);
937                 }
938                 PR_Unlock(Cert_And_Key->lock);
939                 if (!*pRetCert || !*pRetKey) {
940                     /* one or both of them failed to copy. Either the source was NULL, or there was
941                     ** an out of memory condition. Free any allocated copy and fail */
942                     if (*pRetCert) {
943                         CERT_DestroyCertificate(*pRetCert);
944                         *pRetCert = NULL;
945                     }
946                     if (*pRetKey) {
947                         SECKEY_DestroyPrivateKey(*pRetKey);
948                         *pRetKey = NULL;
949                     }
950                     break;
951                 }
952                 /* now check if those objects are valid */
953                 if ( PR_FALSE == LoggedIn(*pRetCert, *pRetKey) ) {
954                     /* token is no longer logged in, it was removed */
955
956                     /* first, delete and clear our invalid local objects */
957                     CERT_DestroyCertificate(*pRetCert);
958                     SECKEY_DestroyPrivateKey(*pRetKey);
959                     *pRetCert = NULL;
960                     *pRetKey = NULL;
961
962                     PR_Lock(Cert_And_Key->lock);
963                     /* check if another thread already logged back in */
964                     if (PR_TRUE == LoggedIn(Cert_And_Key->cert, Cert_And_Key->key)) {
965                         /* yes : try again */
966                         PR_Unlock(Cert_And_Key->lock);
967                         continue;
968                     }
969                     /* this is the thread to retry */
970                     CERT_DestroyCertificate(Cert_And_Key->cert);
971                     SECKEY_DestroyPrivateKey(Cert_And_Key->key);
972                     Cert_And_Key->cert = NULL;
973                     Cert_And_Key->key = NULL;
974
975
976                     /* now look up the cert and key again */
977                     while (PR_FALSE == FindCertAndKey(Cert_And_Key) ) {
978                         PR_Sleep(PR_SecondsToInterval(1));
979                         timeout++;
980                         if (timeout>=60) {
981                             printf("\nToken pulled and not reinserted early enough : aborting.\n");
982                             exit(1);
983                         }
984                     }
985                     PR_Unlock(Cert_And_Key->lock);
986                     continue;
987                     /* try again to reduce code size */
988                 }
989                 return SECSuccess;
990             }
991         }
992         *pRetCert = NULL;
993         *pRetKey = NULL;
994         return SECFailure;
995     } else {
996         /* no cert configured, automatically find the right cert. */
997         CERTCertificate *  cert = NULL;
998         SECKEYPrivateKey * privkey = NULL;
999         CERTCertNicknames * names;
1000         int                 i;
1001         void *             proto_win = NULL;
1002         SECStatus          rv         = SECFailure;
1003
1004         if (Cert_And_Key) {
1005             proto_win = Cert_And_Key->wincx;
1006         }
1007
1008         names = CERT_GetCertNicknames(CERT_GetDefaultCertDB(),
1009                                       SEC_CERT_NICKNAMES_USER, proto_win);
1010         if (names != NULL) {
1011             for (i = 0; i < names->numnicknames; i++) {
1012                 cert = CERT_FindUserCertByUsage(CERT_GetDefaultCertDB(),
1013                             names->nicknames[i], certUsageSSLClient,
1014                             PR_FALSE, proto_win);       
1015                 if ( !cert )
1016                     continue;
1017                 /* Only check unexpired certs */
1018                 if (CERT_CheckCertValidTimes(cert, PR_Now(), PR_TRUE) != 
1019                                              secCertTimeValid ) {
1020                     CERT_DestroyCertificate(cert);
1021                     continue;
1022                 }
1023                 rv = NSS_CmpCertChainWCANames(cert, caNames);
1024                 if ( rv == SECSuccess ) {
1025                     privkey = PK11_FindKeyByAnyCert(cert, proto_win);
1026                     if ( privkey )
1027                         break;
1028                 }
1029                 rv = SECFailure;
1030                 CERT_DestroyCertificate(cert);
1031             }
1032             CERT_FreeNicknames(names);
1033         }
1034         if (rv == SECSuccess) {
1035             *pRetCert = cert;
1036             *pRetKey  = privkey;
1037         }
1038         return rv;
1039     }
1040 }
1041
1042 int 
1043 hexchar_to_int(int c) 
1044 {
1045     if (((c) >= '0') && ((c) <= '9'))
1046         return (c) - '0'; 
1047     if (((c) >= 'a') && ((c) <= 'f'))
1048         return (c) - 'a' + 10;
1049     if (((c) >= 'A') && ((c) <= 'F'))
1050         return (c) - 'A' + 10; 
1051     failed_already = 1;
1052     return -1;
1053 }
1054
1055 void
1056 client_main(
1057     unsigned short      port, 
1058     int                 connections,
1059     cert_and_key* Cert_And_Key,
1060     const char *        hostName,
1061     const char *        sniHostName)
1062 {
1063     PRFileDesc *model_sock      = NULL;
1064     int         i;
1065     int         rv;
1066     PRStatus    status;
1067     PRNetAddr   addr;
1068
1069     status = PR_StringToNetAddr(hostName, &addr);
1070     if (status == PR_SUCCESS) {
1071         addr.inet.port = PR_htons(port);
1072     } else {
1073         /* Lookup host */
1074         PRAddrInfo *addrInfo;
1075         void       *enumPtr   = NULL;
1076
1077         addrInfo = PR_GetAddrInfoByName(hostName, PR_AF_UNSPEC, 
1078                                         PR_AI_ADDRCONFIG | PR_AI_NOCANONNAME);
1079         if (!addrInfo) {
1080             SECU_PrintError(progName, "error looking up host");
1081             return;
1082         }
1083         do {
1084             enumPtr = PR_EnumerateAddrInfo(enumPtr, addrInfo, port, &addr);
1085         } while (enumPtr != NULL &&
1086                  addr.raw.family != PR_AF_INET &&
1087                  addr.raw.family != PR_AF_INET6);
1088         PR_FreeAddrInfo(addrInfo);
1089         if (enumPtr == NULL) {
1090             SECU_PrintError(progName, "error looking up host address");
1091             return;
1092         }
1093     }
1094
1095     /* all suites except RSA_NULL_MD5 are enabled by Domestic Policy */
1096     NSS_SetDomesticPolicy();
1097
1098     /* all the SSL2 and SSL3 cipher suites are enabled by default. */
1099     if (cipherString) {
1100         int ndx;
1101
1102         /* disable all the ciphers, then enable the ones we want. */
1103         disableAllSSLCiphers();
1104
1105         while (0 != (ndx = *cipherString)) {
1106             const char * startCipher = cipherString++;
1107             int  cipher = 0;
1108             SECStatus rv;
1109
1110             if (ndx == ':') {
1111                 cipher  = hexchar_to_int(*cipherString++);
1112                 cipher <<= 4;
1113                 cipher |= hexchar_to_int(*cipherString++);
1114                 cipher <<= 4;
1115                 cipher |= hexchar_to_int(*cipherString++);
1116                 cipher <<= 4;
1117                 cipher |= hexchar_to_int(*cipherString++);
1118                 if (cipher <= 0) {
1119                     fprintf(stderr, "strsclnt: Invalid cipher value: %-5.5s\n",
1120                                     startCipher);
1121                     failed_already = 1;
1122                     return;
1123                 }
1124             } else {
1125                 if (isalpha(ndx)) {
1126                     const int *cptr;
1127
1128                     cptr = islower(ndx) ? ssl3CipherSuites : ssl2CipherSuites;
1129                     for (ndx &= 0x1f; (cipher = *cptr++) != 0 && --ndx > 0; ) 
1130                         /* do nothing */;
1131                 }
1132                 if (cipher <= 0) {
1133                     fprintf(stderr, "strsclnt: Invalid cipher letter: %c\n", 
1134                                     *startCipher);
1135                     failed_already = 1;
1136                     return;
1137                 }
1138             }
1139             rv = SSL_CipherPrefSetDefault(cipher, PR_TRUE);
1140             if (rv != SECSuccess) {
1141                 fprintf(stderr, 
1142                         "strsclnt: SSL_CipherPrefSetDefault(0x%04x) failed\n",
1143                         cipher);
1144                 failed_already = 1;
1145                 return;
1146             }
1147         }
1148     }
1149
1150     /* configure model SSL socket. */
1151
1152     model_sock = PR_OpenTCPSocket(addr.raw.family);
1153     if (model_sock == NULL) {
1154         errExit("PR_OpenTCPSocket for model socket");
1155     }
1156
1157     model_sock = SSL_ImportFD(NULL, model_sock);
1158     if (model_sock == NULL) {
1159         errExit("SSL_ImportFD");
1160     }
1161
1162     /* do SSL configuration. */
1163
1164     rv = SSL_OptionSet(model_sock, SSL_SECURITY,
1165                        enableSSL2 || enabledVersions.min != 0);
1166     if (rv < 0) {
1167         errExit("SSL_OptionSet SSL_SECURITY");
1168     }
1169
1170     rv = SSL_VersionRangeSet(model_sock, &enabledVersions);
1171     if (rv != SECSuccess) {
1172         errExit("error setting SSL/TLS version range ");
1173     }
1174
1175     rv = SSL_OptionSet(model_sock, SSL_ENABLE_SSL2, enableSSL2);
1176     if (rv != SECSuccess) {
1177        errExit("error enabling SSLv2 ");
1178     }
1179
1180     rv = SSL_OptionSet(model_sock, SSL_V2_COMPATIBLE_HELLO, enableSSL2);
1181     if (rv != SECSuccess) {
1182         errExit("error enabling SSLv2 compatible hellos ");
1183     }
1184
1185     if (bigBuf.data) { /* doing FDX */
1186         rv = SSL_OptionSet(model_sock, SSL_ENABLE_FDX, 1);
1187         if (rv < 0) {
1188             errExit("SSL_OptionSet SSL_ENABLE_FDX");
1189         }
1190     }
1191
1192     if (NoReuse) {
1193         rv = SSL_OptionSet(model_sock, SSL_NO_CACHE, 1);
1194         if (rv < 0) {
1195             errExit("SSL_OptionSet SSL_NO_CACHE");
1196         }
1197     }
1198
1199     if (bypassPKCS11) {
1200         rv = SSL_OptionSet(model_sock, SSL_BYPASS_PKCS11, 1);
1201         if (rv < 0) {
1202             errExit("SSL_OptionSet SSL_BYPASS_PKCS11");
1203         }
1204     }
1205
1206     if (disableLocking) {
1207         rv = SSL_OptionSet(model_sock, SSL_NO_LOCKS, 1);
1208         if (rv < 0) {
1209             errExit("SSL_OptionSet SSL_NO_LOCKS");
1210         }
1211     }
1212
1213     if (enableSessionTickets) {
1214         rv = SSL_OptionSet(model_sock, SSL_ENABLE_SESSION_TICKETS, PR_TRUE);
1215         if (rv != SECSuccess)
1216             errExit("SSL_OptionSet SSL_ENABLE_SESSION_TICKETS");
1217     }
1218
1219     if (enableCompression) {
1220         rv = SSL_OptionSet(model_sock, SSL_ENABLE_DEFLATE, PR_TRUE);
1221         if (rv != SECSuccess)
1222             errExit("SSL_OptionSet SSL_ENABLE_DEFLATE");
1223     }
1224
1225     if (enableFalseStart) {
1226         rv = SSL_OptionSet(model_sock, SSL_ENABLE_FALSE_START, PR_TRUE);
1227         if (rv != SECSuccess)
1228             errExit("SSL_OptionSet SSL_ENABLE_FALSE_START");
1229     }
1230
1231     if (enableCertStatus) {
1232         rv = SSL_OptionSet(model_sock, SSL_ENABLE_OCSP_STAPLING, PR_TRUE);
1233         if (rv != SECSuccess)
1234             errExit("SSL_OptionSet SSL_ENABLE_OCSP_STAPLING");
1235     }
1236
1237     SSL_SetPKCS11PinArg(model_sock, &pwdata);
1238
1239     SSL_SetURL(model_sock, hostName);
1240
1241     SSL_AuthCertificateHook(model_sock, mySSLAuthCertificate, 
1242                         (void *)CERT_GetDefaultCertDB());
1243     SSL_BadCertHook(model_sock, myBadCertHandler, NULL);
1244
1245     SSL_GetClientAuthDataHook(model_sock, StressClient_GetClientAuthData, (void*)Cert_And_Key);
1246
1247     if (sniHostName) {
1248         SSL_SetURL(model_sock, sniHostName);
1249     }
1250     /* I'm not going to set the HandshakeCallback function. */
1251
1252     /* end of ssl configuration. */
1253
1254     init_thread_data();
1255
1256     remaining_connections = total_connections = connections;
1257     total_connections_modulo_100 = total_connections % 100;
1258     total_connections_rounded_down_to_hundreds =
1259         total_connections - total_connections_modulo_100;
1260
1261     if (!NoReuse) {
1262         remaining_connections = 1;
1263         rv = launch_thread(do_connects, &addr, model_sock, 0);
1264         /* wait for the first connection to terminate, then launch the rest. */
1265         reap_threads();
1266         remaining_connections = total_connections - 1 ;
1267     }
1268     if (remaining_connections > 0) {
1269         active_threads  = PR_MIN(active_threads, remaining_connections);
1270         /* Start up the threads */
1271         for (i=0;i<active_threads;i++) {
1272             rv = launch_thread(do_connects, &addr, model_sock, i);
1273         }
1274         reap_threads();
1275     }
1276     destroy_thread_data();
1277
1278     PR_Close(model_sock);
1279 }
1280
1281 SECStatus
1282 readBigFile(const char * fileName)
1283 {
1284     PRFileInfo  info;
1285     PRStatus    status;
1286     SECStatus   rv      = SECFailure;
1287     int         count;
1288     int         hdrLen;
1289     PRFileDesc *local_file_fd = NULL;
1290
1291     status = PR_GetFileInfo(fileName, &info);
1292
1293     if (status == PR_SUCCESS &&
1294         info.type == PR_FILE_FILE &&
1295         info.size > 0 &&
1296         NULL != (local_file_fd = PR_Open(fileName, PR_RDONLY, 0))) {
1297
1298         hdrLen      = PORT_Strlen(outHeader);
1299         bigBuf.len  = hdrLen + info.size;
1300         bigBuf.data = PORT_Malloc(bigBuf.len + 4095);
1301         if (!bigBuf.data) {
1302             errWarn("PORT_Malloc");
1303             goto done;
1304         }
1305
1306         PORT_Memcpy(bigBuf.data, outHeader, hdrLen);
1307
1308         count = PR_Read(local_file_fd, bigBuf.data + hdrLen, info.size);
1309         if (count != info.size) {
1310             errWarn("PR_Read local file");
1311             goto done;
1312         }
1313         rv = SECSuccess;
1314 done:
1315         PR_Close(local_file_fd);
1316     }
1317     return rv;
1318 }
1319
1320 int
1321 main(int argc, char **argv)
1322 {
1323     const char *         dir         = ".";
1324     const char *         fileName    = NULL;
1325     char *               hostName    = NULL;
1326     char *               nickName    = NULL;
1327     char *               tmp         = NULL;
1328     int                  connections = 1;
1329     int                  exitVal;
1330     int                  tmpInt;
1331     unsigned short       port        = 443;
1332     SECStatus            rv;
1333     PLOptState *         optstate;
1334     PLOptStatus          status;
1335     cert_and_key         Cert_And_Key;
1336     char *               sniHostName = NULL;
1337
1338     /* Call the NSPR initialization routines */
1339     PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
1340     SSL_VersionRangeGetSupported(ssl_variant_stream, &enabledVersions);
1341
1342     tmp      = strrchr(argv[0], '/');
1343     tmp      = tmp ? tmp + 1 : argv[0];
1344     progName = strrchr(tmp, '\\');
1345     progName = progName ? progName + 1 : tmp;
1346  
1347
1348     optstate = PL_CreateOptState(argc, argv,
1349                                  "BC:DNP:TUV:W:a:c:d:f:gin:op:qst:uvw:z");
1350     while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
1351         switch(optstate->option) {
1352         case 'B': bypassPKCS11 = PR_TRUE; break;
1353
1354         case 'C': cipherString = optstate->value; break;
1355
1356         case 'D': NoDelay = PR_TRUE; break;
1357
1358         case 'I': /* reserved for OCSP multi-stapling */ break;
1359
1360         case 'N': NoReuse = 1; break;
1361         
1362         case 'P': fullhs = PORT_Atoi(optstate->value); break;
1363
1364         case 'T': enableCertStatus = PR_TRUE; break;
1365
1366         case 'U': ThrottleUp = PR_TRUE; break;
1367         
1368         case 'V': if (SECU_ParseSSLVersionRangeString(optstate->value,
1369                           enabledVersions, enableSSL2,
1370                           &enabledVersions, &enableSSL2) != SECSuccess) {
1371                       Usage(progName);
1372                   }
1373                   break;
1374
1375         case 'a': sniHostName = PL_strdup(optstate->value); break;
1376
1377         case 'c': connections = PORT_Atoi(optstate->value); break;
1378
1379         case 'd': dir = optstate->value; break;
1380
1381         case 'f': fileName = optstate->value; break;
1382
1383         case 'g': enableFalseStart = PR_TRUE; break;
1384
1385         case 'i': ignoreErrors = PR_TRUE; break;
1386
1387         case 'n': nickName = PL_strdup(optstate->value); break;
1388
1389         case 'o': MakeCertOK++; break;
1390
1391         case 'p': port = PORT_Atoi(optstate->value); break;
1392
1393         case 'q': QuitOnTimeout = PR_TRUE; break;
1394
1395         case 's': disableLocking = PR_TRUE; break;
1396
1397         case 't':
1398             tmpInt = PORT_Atoi(optstate->value);
1399             if (tmpInt > 0 && tmpInt < MAX_THREADS) 
1400                 max_threads = active_threads = tmpInt;
1401             break;
1402
1403         case 'u': enableSessionTickets = PR_TRUE; break;
1404
1405         case 'v': verbose++; break;
1406
1407         case 'w':
1408             pwdata.source = PW_PLAINTEXT;
1409             pwdata.data = PL_strdup(optstate->value);
1410             break;
1411
1412         case 'W':
1413             pwdata.source = PW_FROMFILE;
1414             pwdata.data = PL_strdup(optstate->value);
1415             break;
1416
1417         case 'z': enableCompression = PR_TRUE; break;
1418
1419         case 0:   /* positional parameter */
1420             if (hostName) {
1421                 Usage(progName);
1422             }
1423             hostName = PL_strdup(optstate->value);
1424             break;
1425
1426         default:
1427         case '?':
1428             Usage(progName);
1429             break;
1430
1431         }
1432     }
1433     PL_DestroyOptState(optstate);
1434
1435     if (!hostName || status == PL_OPT_BAD)
1436         Usage(progName);
1437
1438     if (fullhs!= NO_FULLHS_PERCENTAGE && (fullhs < 0 || fullhs>100 || NoReuse) )
1439         Usage(progName);
1440
1441     if (port == 0)
1442         Usage(progName);
1443
1444     if (fileName)
1445         readBigFile(fileName);
1446
1447     PK11_SetPasswordFunc(SECU_GetModulePassword);
1448
1449     tmp = PR_GetEnv("NSS_DEBUG_TIMEOUT");
1450     if (tmp && tmp[0]) {
1451         int sec = PORT_Atoi(tmp);
1452         if (sec > 0) {
1453             maxInterval = PR_SecondsToInterval(sec);
1454         }
1455     }
1456
1457     /* Call the NSS initialization routines */
1458     rv = NSS_Initialize(dir, "", "", SECMOD_DB, NSS_INIT_READONLY);
1459     if (rv != SECSuccess) {
1460         fputs("NSS_Init failed.\n", stderr);
1461         exit(1);
1462     }
1463     ssl3stats = SSL_GetStatistics();
1464     Cert_And_Key.lock = PR_NewLock();
1465     Cert_And_Key.nickname = nickName;
1466     Cert_And_Key.wincx = &pwdata;
1467     Cert_And_Key.cert = NULL;
1468     Cert_And_Key.key = NULL;
1469
1470     if (PR_FALSE == FindCertAndKey(&Cert_And_Key)) {
1471
1472         if (Cert_And_Key.cert == NULL) {
1473             fprintf(stderr, "strsclnt: Can't find certificate %s\n", Cert_And_Key.nickname);
1474             exit(1);
1475         }
1476
1477         if (Cert_And_Key.key == NULL) {
1478             fprintf(stderr, "strsclnt: Can't find Private Key for cert %s\n", 
1479                     Cert_And_Key.nickname);
1480             exit(1);
1481         }
1482
1483     }
1484
1485     client_main(port, connections, &Cert_And_Key, hostName,
1486                 sniHostName);
1487
1488     /* clean up */
1489     if (Cert_And_Key.cert) {
1490         CERT_DestroyCertificate(Cert_And_Key.cert);
1491     }
1492     if (Cert_And_Key.key) {
1493         SECKEY_DestroyPrivateKey(Cert_And_Key.key);
1494     }
1495
1496     PR_DestroyLock(Cert_And_Key.lock);
1497
1498     if (pwdata.data) {
1499         PL_strfree(pwdata.data);
1500     }
1501     if (Cert_And_Key.nickname) {
1502         PL_strfree(Cert_And_Key.nickname);
1503     }
1504     if (sniHostName) {
1505         PL_strfree(sniHostName);
1506     }
1507
1508     PL_strfree(hostName);
1509
1510     /* some final stats. */
1511     if (ssl3stats->hsh_sid_cache_hits +
1512         ssl3stats->hsh_sid_cache_misses +
1513         ssl3stats->hsh_sid_cache_not_ok +
1514         ssl3stats->hsh_sid_stateless_resumes == 0) {
1515         /* presumably we were testing SSL2. */
1516         printf("strsclnt: SSL2 - %d server certificates tested.\n",
1517                certsTested);
1518     } else {
1519         printf(
1520         "strsclnt: %ld cache hits; %ld cache misses, %ld cache not reusable\n"
1521         "          %ld stateless resumes\n",
1522             ssl3stats->hsh_sid_cache_hits, 
1523             ssl3stats->hsh_sid_cache_misses,
1524             ssl3stats->hsh_sid_cache_not_ok,
1525             ssl3stats->hsh_sid_stateless_resumes);
1526     }
1527
1528     if (!NoReuse) {
1529         if (enableSessionTickets)
1530             exitVal = (ssl3stats->hsh_sid_stateless_resumes == 0);
1531         else
1532             exitVal = (ssl3stats->hsh_sid_cache_misses > 1) ||
1533                       (ssl3stats->hsh_sid_stateless_resumes != 0);
1534         if (!exitVal)
1535             exitVal = (ssl3stats->hsh_sid_cache_not_ok != 0) ||
1536                       (certsTested > 1);
1537     } else {
1538         printf("strsclnt: NoReuse - %d server certificates tested.\n",
1539                certsTested);
1540         if (ssl3stats->hsh_sid_cache_hits +
1541             ssl3stats->hsh_sid_cache_misses +
1542             ssl3stats->hsh_sid_cache_not_ok +
1543             ssl3stats->hsh_sid_stateless_resumes > 0) {
1544             exitVal = (ssl3stats->hsh_sid_cache_misses != connections) ||
1545                 (ssl3stats->hsh_sid_stateless_resumes != 0) ||
1546                 (certsTested != connections);
1547         } else {                /* ssl2 connections */
1548             exitVal = (certsTested != connections);
1549         }
1550     }
1551
1552     exitVal = ( exitVal || failed_already );
1553     SSL_ClearSessionCache();
1554     if (NSS_Shutdown() != SECSuccess) {
1555         printf("strsclnt: NSS_Shutdown() failed.\n");
1556         exit(1);
1557     }
1558
1559     PR_Cleanup();
1560     return exitVal;
1561 }
1562