PageRenderTime 92ms CodeModel.GetById 19ms app.highlight 62ms RepoModel.GetById 1ms app.codeStats 0ms

/security/nss/cmd/strsclnt/strsclnt.c

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