Back to index

lightning-sunbird  0.9+nobinonly
strsclnt.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 #include <stdio.h>
00037 #include <string.h>
00038 
00039 #include "secutil.h"
00040 
00041 #if defined(XP_UNIX)
00042 #include <unistd.h>
00043 #endif
00044 #include <stdlib.h>
00045 #if !defined(_WIN32_WCE)
00046 #include <errno.h>
00047 #include <fcntl.h>
00048 #endif
00049 #include <stdarg.h>
00050 
00051 #include "plgetopt.h"
00052 
00053 #include "nspr.h"
00054 #include "prio.h"
00055 #include "prnetdb.h"
00056 #include "prerror.h"
00057 
00058 #include "pk11func.h"
00059 #include "secitem.h"
00060 #include "sslproto.h"
00061 #include "nss.h"
00062 #include "ssl.h"
00063 
00064 #ifndef PORT_Sprintf
00065 #define PORT_Sprintf sprintf
00066 #endif
00067 
00068 #ifndef PORT_Strstr
00069 #define PORT_Strstr strstr
00070 #endif
00071 
00072 #ifndef PORT_Malloc
00073 #define PORT_Malloc PR_Malloc
00074 #endif
00075 
00076 #define RD_BUF_SIZE (60 * 1024)
00077 
00078 /* Include these cipher suite arrays to re-use tstclnt's 
00079  * cipher selection code.
00080  */
00081 
00082 int ssl2CipherSuites[] = {
00083     SSL_EN_RC4_128_WITH_MD5,                    /* A */
00084     SSL_EN_RC4_128_EXPORT40_WITH_MD5,           /* B */
00085     SSL_EN_RC2_128_CBC_WITH_MD5,                /* C */
00086     SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5,       /* D */
00087     SSL_EN_DES_64_CBC_WITH_MD5,                 /* E */
00088     SSL_EN_DES_192_EDE3_CBC_WITH_MD5,           /* F */
00089     0
00090 };
00091 
00092 int ssl3CipherSuites[] = {
00093     -1, /* SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA* a */
00094     -1, /* SSL_FORTEZZA_DMS_WITH_RC4_128_SHA     * b */
00095     SSL_RSA_WITH_RC4_128_MD5,                   /* c */
00096     SSL_RSA_WITH_3DES_EDE_CBC_SHA,              /* d */
00097     SSL_RSA_WITH_DES_CBC_SHA,                   /* e */
00098     SSL_RSA_EXPORT_WITH_RC4_40_MD5,             /* f */
00099     SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5,         /* g */
00100     -1, /* SSL_FORTEZZA_DMS_WITH_NULL_SHA        * h */
00101     SSL_RSA_WITH_NULL_MD5,                      /* i */
00102     SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA,         /* j */
00103     SSL_RSA_FIPS_WITH_DES_CBC_SHA,              /* k */
00104     TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA,  /* l */
00105     TLS_RSA_EXPORT1024_WITH_RC4_56_SHA,          /* m */
00106     SSL_RSA_WITH_RC4_128_SHA,                   /* n */
00107     TLS_DHE_DSS_WITH_RC4_128_SHA,         /* o */
00108     SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA,           /* p */
00109     SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA,           /* q */
00110     SSL_DHE_RSA_WITH_DES_CBC_SHA,         /* r */
00111     SSL_DHE_DSS_WITH_DES_CBC_SHA,         /* s */
00112     TLS_DHE_DSS_WITH_AES_128_CBC_SHA,            /* t */
00113     TLS_DHE_RSA_WITH_AES_128_CBC_SHA,            /* u */
00114     TLS_RSA_WITH_AES_128_CBC_SHA,                /* v */
00115     TLS_DHE_DSS_WITH_AES_256_CBC_SHA,            /* w */
00116     TLS_DHE_RSA_WITH_AES_256_CBC_SHA,            /* x */
00117     TLS_RSA_WITH_AES_256_CBC_SHA,                /* y */
00118     0
00119 };
00120 
00121 #define NO_FULLHS_PERCENTAGE -1
00122 
00123 /* This global string is so that client main can see 
00124  * which ciphers to use. 
00125  */
00126 
00127 static const char *cipherString;
00128 
00129 static PRInt32 certsTested;
00130 static int MakeCertOK;
00131 static int NoReuse;
00132 static int fullhs = NO_FULLHS_PERCENTAGE; /* percentage of full handshakes to
00133                                           ** perform */
00134 static PRInt32 globalconid = 0; /* atomically set */
00135 static int total_connections;  /* total number of connections to perform */
00136 static int total_connections_rounded_down_to_hundreds;
00137 static int total_connections_modulo_100;
00138 
00139 static PRBool NoDelay;
00140 static PRBool QuitOnTimeout = PR_FALSE;
00141 static PRBool ThrottleUp = PR_FALSE;
00142 
00143 static PRLock    * threadLock; /* protects the global variables below */
00144 static PRTime lastConnectFailure;
00145 static PRTime lastConnectSuccess;
00146 static PRTime lastThrottleUp;
00147 static PRInt32 remaining_connections;  /* number of connections left */
00148 static int active_threads = 8; /* number of threads currently trying to
00149                                ** connect */
00150 static PRInt32 numUsed;
00151 /* end of variables protected by threadLock */
00152 
00153 static SSL3Statistics * ssl3stats;
00154 
00155 static int failed_already = 0;
00156 static PRBool disableSSL2     = PR_FALSE;
00157 static PRBool disableSSL3     = PR_FALSE;
00158 static PRBool disableTLS      = PR_FALSE;
00159 static PRBool bypassPKCS11    = PR_FALSE;
00160 static PRBool disableLocking  = PR_FALSE;
00161 static PRBool ignoreErrors    = PR_FALSE;
00162 
00163 PRIntervalTime maxInterval    = PR_INTERVAL_NO_TIMEOUT;
00164 
00165 char * ownPasswd( PK11SlotInfo *slot, PRBool retry, void *arg)
00166 {
00167         char *passwd = NULL;
00168 
00169         if ( (!retry) && arg ) {
00170                 passwd = PL_strdup((char *)arg);
00171         }
00172 
00173         return passwd;
00174 }
00175 
00176 int    stopping;
00177 int    verbose;
00178 SECItem       bigBuf;
00179 
00180 #define PRINTF  if (verbose)  printf
00181 #define FPRINTF if (verbose) fprintf
00182 
00183 static void
00184 Usage(const char *progName)
00185 {
00186     fprintf(stderr, 
00187        "Usage: %s [-n nickname] [-p port] [-d dbdir] [-c connections]\n"
00188        "          [-23BDNTovqs] [-f filename] [-N | -P percentage]\n"
00189        "          [-w dbpasswd] [-C cipher(s)] [-t threads] hostname\n"
00190        " where -v means verbose\n"
00191         "       -o flag is interpreted as follows:\n"
00192         "          1 -o   means override the result of server certificate validation.\n"
00193         "          2 -o's mean skip server certificate validation altogether.\n"
00194        "       -D means no TCP delays\n"
00195        "       -q means quit when server gone (timeout rather than retry forever)\n"
00196        "       -s means disable SSL socket locking\n"
00197        "       -N means no session reuse\n"
00198        "       -P means do a specified percentage of full handshakes (0-100)\n"
00199         "       -2 means disable SSL2\n"
00200         "       -3 means disable SSL3\n"
00201         "       -T means disable TLS\n"
00202         "       -U means enable throttling up threads\n"
00203        "       -B bypasses the PKCS11 layer for SSL encryption and MACing\n",
00204        progName);
00205     exit(1);
00206 }
00207 
00208 
00209 static void
00210 errWarn(char * funcString)
00211 {
00212     PRErrorCode  perr      = PR_GetError();
00213     const char * errString = SECU_Strerror(perr);
00214 
00215     fprintf(stderr, "strsclnt: %s returned error %d:\n%s\n",
00216             funcString, perr, errString);
00217 }
00218 
00219 static void
00220 errExit(char * funcString)
00221 {
00222     errWarn(funcString);
00223     exit(1);
00224 }
00225 
00226 /**************************************************************************
00227 ** 
00228 ** Routines for disabling SSL ciphers.
00229 **
00230 **************************************************************************/
00231 
00232 void
00233 disableAllSSLCiphers(void)
00234 {
00235     const PRUint16 *cipherSuites = SSL_ImplementedCiphers;
00236     int             i            = SSL_NumImplementedCiphers;
00237     SECStatus       rv;
00238 
00239     /* disable all the SSL3 cipher suites */
00240     while (--i >= 0) {
00241        PRUint16 suite = cipherSuites[i];
00242         rv = SSL_CipherPrefSetDefault(suite, PR_FALSE);
00243        if (rv != SECSuccess) {
00244            printf("SSL_CipherPrefSetDefault didn't like value 0x%04x (i = %d)\n",
00245                  suite, i);
00246            errWarn("SSL_CipherPrefSetDefault");
00247            exit(2);
00248        }
00249     }
00250 }
00251 
00252 static SECStatus
00253 myGoodSSLAuthCertificate(void *arg, PRFileDesc *fd, PRBool checkSig,
00254                    PRBool isServer)
00255 {
00256     return SECSuccess;
00257 }
00258 
00259 /* This invokes the "default" AuthCert handler in libssl.
00260 ** The only reason to use this one is that it prints out info as it goes. 
00261 */
00262 static SECStatus
00263 mySSLAuthCertificate(void *arg, PRFileDesc *fd, PRBool checkSig,
00264                    PRBool isServer)
00265 {
00266     SECStatus rv;
00267     CERTCertificate *    peerCert;
00268 
00269     if (MakeCertOK>=2) {
00270         return SECSuccess;
00271     }
00272     peerCert = SSL_PeerCertificate(fd);
00273 
00274     PRINTF("strsclnt: Subject: %s\nstrsclnt: Issuer : %s\n", 
00275            peerCert->subjectName, peerCert->issuerName); 
00276     /* invoke the "default" AuthCert handler. */
00277     rv = SSL_AuthCertificate(arg, fd, checkSig, isServer);
00278 
00279     PR_AtomicIncrement(&certsTested);
00280     if (rv == SECSuccess) {
00281        fputs("strsclnt: -- SSL: Server Certificate Validated.\n", stderr);
00282     }
00283     CERT_DestroyCertificate(peerCert);
00284     /* error, if any, will be displayed by the Bad Cert Handler. */
00285     return rv;  
00286 }
00287 
00288 static SECStatus
00289 myBadCertHandler( void *arg, PRFileDesc *fd)
00290 {
00291     int err = PR_GetError();
00292     if (!MakeCertOK)
00293        fprintf(stderr, 
00294            "strsclnt: -- SSL: Server Certificate Invalid, err %d.\n%s\n", 
00295             err, SECU_Strerror(err));
00296     return (MakeCertOK ? SECSuccess : SECFailure);
00297 }
00298 
00299 void 
00300 printSecurityInfo(PRFileDesc *fd)
00301 {
00302     CERTCertificate * cert = NULL;
00303     SSL3Statistics * ssl3stats = SSL_GetStatistics();
00304     SECStatus result;
00305     SSLChannelInfo    channel;
00306     SSLCipherSuiteInfo suite;
00307 
00308     static int only_once;
00309 
00310     if (only_once && verbose < 2)
00311        return;
00312     only_once = 1;
00313 
00314     result = SSL_GetChannelInfo(fd, &channel, sizeof channel);
00315     if (result == SECSuccess && 
00316         channel.length == sizeof channel && 
00317        channel.cipherSuite) {
00318        result = SSL_GetCipherSuiteInfo(channel.cipherSuite, 
00319                                    &suite, sizeof suite);
00320        if (result == SECSuccess) {
00321            FPRINTF(stderr, 
00322            "strsclnt: SSL version %d.%d using %d-bit %s with %d-bit %s MAC\n",
00323               channel.protocolVersion >> 8, channel.protocolVersion & 0xff,
00324               suite.effectiveKeyBits, suite.symCipherName, 
00325               suite.macBits, suite.macAlgorithmName);
00326            FPRINTF(stderr, 
00327            "strsclnt: Server Auth: %d-bit %s, Key Exchange: %d-bit %s\n",
00328               channel.authKeyBits, suite.authAlgorithmName,
00329               channel.keaKeyBits,  suite.keaTypeName);
00330        }
00331     }
00332 
00333     cert = SSL_LocalCertificate(fd);
00334     if (!cert)
00335        cert = SSL_PeerCertificate(fd);
00336 
00337     if (verbose && cert) {
00338        char * ip = CERT_NameToAscii(&cert->issuer);
00339        char * sp = CERT_NameToAscii(&cert->subject);
00340         if (sp) {
00341            fprintf(stderr, "strsclnt: subject DN: %s\n", sp);
00342            PORT_Free(sp);
00343        }
00344         if (ip) {
00345            fprintf(stderr, "strsclnt: issuer  DN: %s\n", ip);
00346            PORT_Free(ip);
00347        }
00348     }
00349     if (cert) {
00350        CERT_DestroyCertificate(cert);
00351        cert = NULL;
00352     }
00353     fprintf(stderr,
00354        "strsclnt: %ld cache hits; %ld cache misses, %ld cache not reusable\n",
00355        ssl3stats->hsh_sid_cache_hits, 
00356        ssl3stats->hsh_sid_cache_misses,
00357        ssl3stats->hsh_sid_cache_not_ok);
00358 
00359 }
00360 
00361 /**************************************************************************
00362 ** Begin thread management routines and data.
00363 **************************************************************************/
00364 
00365 #define MAX_THREADS 128
00366 
00367 typedef int startFn(void *a, void *b, int c);
00368 
00369 
00370 static PRInt32     numConnected;
00371 static int         max_threads;    /* peak threads allowed */
00372 
00373 typedef struct perThreadStr {
00374     void *    a;
00375     void *    b;
00376     int         tid;
00377     int         rv;
00378     startFn  *  startFunc;
00379     PRThread *  prThread;
00380     PRBool    inUse;
00381 } perThread;
00382 
00383 perThread threads[MAX_THREADS];
00384 
00385 void
00386 thread_wrapper(void * arg)
00387 {
00388     perThread * slot = (perThread *)arg;
00389     PRBool done = PR_FALSE;
00390 
00391     do {
00392         PRBool doop = PR_FALSE;
00393         PRBool dosleep = PR_FALSE;
00394         PRTime now = PR_Now();
00395 
00396         PR_Lock(threadLock);
00397         if (! (slot->tid < active_threads)) {
00398             /* this thread isn't supposed to be running */
00399             if (!ThrottleUp) {
00400                 /* we'll never need this thread again, so abort it */
00401                 done = PR_TRUE;
00402             } else if (remaining_connections > 0) {
00403                 /* we may still need this thread, so just sleep for 1s */
00404                 dosleep = PR_TRUE;
00405                 /* the conditions to trigger a throttle up are :
00406                 ** 1. last PR_Connect failure must have happened more than
00407                 **    10s ago
00408                 ** 2. last throttling up must have happened more than 0.5s ago
00409                 ** 3. there must be a more recent PR_Connect success than
00410                 **    failure
00411                 */
00412                 if ( (now - lastConnectFailure > 10 * PR_USEC_PER_SEC) &&
00413                     ( (!lastThrottleUp) || ( (now - lastThrottleUp) >=
00414                                              (PR_USEC_PER_SEC/2)) ) &&
00415                     (lastConnectSuccess > lastConnectFailure) ) {
00416                     /* try throttling up by one thread */
00417                     active_threads = PR_MIN(max_threads, active_threads+1);
00418                     fprintf(stderr,"active_threads set up to %d\n",
00419                             active_threads);
00420                     lastThrottleUp = PR_MAX(now, lastThrottleUp);
00421                 }
00422             } else {
00423                 /* no more connections left, we are done */
00424                 done = PR_TRUE;
00425             }
00426         } else {
00427             /* this thread should run */
00428             if (--remaining_connections >= 0) { /* protected by threadLock */
00429                 doop = PR_TRUE;
00430             } else {
00431                 done = PR_TRUE;
00432             }
00433         }
00434         PR_Unlock(threadLock);
00435         if (doop) {
00436             slot->rv = (* slot->startFunc)(slot->a, slot->b, slot->tid);
00437             PRINTF("strsclnt: Thread in slot %d returned %d\n", 
00438                    slot->tid, slot->rv);
00439         }
00440         if (dosleep) {
00441             PR_Sleep(PR_SecondsToInterval(1));
00442         }
00443     } while (!done && (!failed_already || ignoreErrors));
00444 }
00445 
00446 SECStatus
00447 launch_thread(
00448     startFn * startFunc,
00449     void *    a,
00450     void *    b,
00451     int         tid)
00452 {
00453     PRUint32 i;
00454     perThread * slot;
00455 
00456     PR_Lock(threadLock);
00457 
00458     PORT_Assert(numUsed < MAX_THREADS);
00459     if (! (numUsed < MAX_THREADS)) {
00460         PR_Unlock(threadLock);
00461         return SECFailure;
00462     }
00463 
00464     i = numUsed++;
00465     slot = &threads[i];
00466     slot->a = a;
00467     slot->b = b;
00468     slot->tid = tid;
00469 
00470     slot->startFunc = startFunc;
00471 
00472     slot->prThread      = PR_CreateThread(PR_USER_THREAD,
00473                                       thread_wrapper, slot,
00474                                   PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
00475                                   PR_JOINABLE_THREAD, 0);
00476     if (slot->prThread == NULL) {
00477        PR_Unlock(threadLock);
00478        printf("strsclnt: Failed to launch thread!\n");
00479        return SECFailure;
00480     } 
00481 
00482     slot->inUse   = 1;
00483     PR_Unlock(threadLock);
00484     PRINTF("strsclnt: Launched thread in slot %d \n", i);
00485 
00486     return SECSuccess;
00487 }
00488 
00489 /* join all the threads */
00490 int 
00491 reap_threads(void)
00492 {
00493     int         i;
00494 
00495     for (i = 0; i < MAX_THREADS; ++i) {
00496         if (threads[i].prThread) {
00497             PR_JoinThread(threads[i].prThread);
00498             threads[i].prThread = NULL;
00499         }
00500     }
00501     return 0;
00502 }
00503 
00504 void
00505 destroy_thread_data(void)
00506 {
00507     PORT_Memset(threads, 0, sizeof threads);
00508 
00509     if (threadLock) {
00510        PR_DestroyLock(threadLock);
00511        threadLock = NULL;
00512     }
00513 }
00514 
00515 void
00516 init_thread_data(void)
00517 {
00518     threadLock = PR_NewLock();
00519 }
00520 
00521 /**************************************************************************
00522 ** End   thread management routines.
00523 **************************************************************************/
00524 
00525 PRBool useModelSocket = PR_TRUE;
00526 
00527 static const char stopCmd[] = { "GET /stop " };
00528 static const char outHeader[] = {
00529     "HTTP/1.0 200 OK\r\n"
00530     "Server: Netscape-Enterprise/2.0a\r\n"
00531     "Date: Tue, 26 Aug 1997 22:10:05 GMT\r\n"
00532     "Content-type: text/plain\r\n"
00533     "\r\n"
00534 };
00535 
00536 struct lockedVarsStr {
00537     PRLock *  lock;
00538     int              count;
00539     int              waiters;
00540     PRCondVar *      condVar;
00541 };
00542 
00543 typedef struct lockedVarsStr lockedVars;
00544 
00545 void 
00546 lockedVars_Init( lockedVars * lv)
00547 {
00548     lv->count   = 0;
00549     lv->waiters = 0;
00550     lv->lock    = PR_NewLock();
00551     lv->condVar = PR_NewCondVar(lv->lock);
00552 }
00553 
00554 void
00555 lockedVars_Destroy( lockedVars * lv)
00556 {
00557     PR_DestroyCondVar(lv->condVar);
00558     lv->condVar = NULL;
00559 
00560     PR_DestroyLock(lv->lock);
00561     lv->lock = NULL;
00562 }
00563 
00564 void
00565 lockedVars_WaitForDone(lockedVars * lv)
00566 {
00567     PR_Lock(lv->lock);
00568     while (lv->count > 0) {
00569        PR_WaitCondVar(lv->condVar, PR_INTERVAL_NO_TIMEOUT);
00570     }
00571     PR_Unlock(lv->lock);
00572 }
00573 
00574 int    /* returns count */
00575 lockedVars_AddToCount(lockedVars * lv, int addend)
00576 {
00577     int rv;
00578 
00579     PR_Lock(lv->lock);
00580     rv = lv->count += addend;
00581     if (rv <= 0) {
00582        PR_NotifyCondVar(lv->condVar);
00583     }
00584     PR_Unlock(lv->lock);
00585     return rv;
00586 }
00587 
00588 int
00589 do_writes(
00590     void *       a,
00591     void *       b,
00592     int          c)
00593 {
00594     PRFileDesc *     ssl_sock      = (PRFileDesc *)a;
00595     lockedVars *     lv            = (lockedVars *)b;
00596     int                     sent          = 0;
00597     int              count         = 0;
00598 
00599     while (sent < bigBuf.len) {
00600 
00601        count = PR_Send(ssl_sock, bigBuf.data + sent, bigBuf.len - sent, 
00602                        0, maxInterval);
00603        if (count < 0) {
00604            errWarn("PR_Send bigBuf");
00605            break;
00606        }
00607        FPRINTF(stderr, "strsclnt: PR_Send wrote %d bytes from bigBuf\n", 
00608               count );
00609        sent += count;
00610     }
00611     if (count >= 0) {       /* last write didn't fail. */
00612        PR_Shutdown(ssl_sock, PR_SHUTDOWN_SEND);
00613     }
00614 
00615     /* notify the reader that we're done. */
00616     lockedVars_AddToCount(lv, -1);
00617     return (sent < bigBuf.len) ? SECFailure : SECSuccess;
00618 }
00619 
00620 int 
00621 handle_fdx_connection( PRFileDesc * ssl_sock, int connection)
00622 {
00623     SECStatus          result;
00624     int                firstTime = 1;
00625     int                countRead = 0;
00626     lockedVars         lv;
00627     char               *buf;
00628 
00629 
00630     lockedVars_Init(&lv);
00631     lockedVars_AddToCount(&lv, 1);
00632 
00633     /* Attempt to launch the writer thread. */
00634     result = launch_thread(do_writes, ssl_sock, &lv, connection);
00635 
00636     if (result != SECSuccess) 
00637        goto cleanup;
00638 
00639     buf = PR_Malloc(RD_BUF_SIZE);
00640 
00641     if (buf) {
00642        do {
00643            /* do reads here. */
00644            PRInt32 count;
00645 
00646            count = PR_Recv(ssl_sock, buf, RD_BUF_SIZE, 0, maxInterval);
00647            if (count < 0) {
00648               errWarn("PR_Recv");
00649               break;
00650            }
00651            countRead += count;
00652            FPRINTF(stderr, 
00653                   "strsclnt: connection %d read %d bytes (%d total).\n", 
00654                   connection, count, countRead );
00655            if (firstTime) {
00656               firstTime = 0;
00657               printSecurityInfo(ssl_sock);
00658            }
00659        } while (lockedVars_AddToCount(&lv, 0) > 0);
00660        PR_Free(buf);
00661        buf = 0;
00662     }
00663 
00664     /* Wait for writer to finish */
00665     lockedVars_WaitForDone(&lv);
00666     lockedVars_Destroy(&lv);
00667 
00668     FPRINTF(stderr, 
00669     "strsclnt: connection %d read %d bytes total. -----------------------\n", 
00670            connection, countRead);
00671 
00672 cleanup:
00673     /* Caller closes the socket. */
00674 
00675     return SECSuccess;
00676 }
00677 
00678 const char request[] = {"GET /abc HTTP/1.0\r\n\r\n" };
00679 
00680 SECStatus
00681 handle_connection( PRFileDesc *ssl_sock, int tid)
00682 {
00683     int           countRead = 0;
00684     PRInt32 rv;
00685     char    *buf;
00686 
00687     buf = PR_Malloc(RD_BUF_SIZE);
00688     if (!buf)
00689        return SECFailure;
00690 
00691     /* compose the http request here. */
00692 
00693     rv = PR_Send(ssl_sock, request, strlen(request), 0, maxInterval);
00694     if (rv <= 0) {
00695        errWarn("PR_Send");
00696        PR_Free(buf);
00697        buf = 0;
00698         failed_already = 1;
00699        return SECFailure;
00700     }
00701     printSecurityInfo(ssl_sock);
00702 
00703     /* read until EOF */
00704     while (1) {
00705        rv = PR_Recv(ssl_sock, buf, RD_BUF_SIZE, 0, maxInterval);
00706        if (rv == 0) {
00707            break;    /* EOF */
00708        }
00709        if (rv < 0) {
00710            errWarn("PR_Recv");
00711            failed_already = 1;
00712            break;
00713        }
00714 
00715        countRead += rv;
00716        FPRINTF(stderr,
00717                 "strsclnt: connection on thread %d read %d bytes (%d total).\n",
00718               tid, rv, countRead );
00719     }
00720     PR_Free(buf);
00721     buf = 0;
00722 
00723     /* Caller closes the socket. */
00724 
00725     FPRINTF(stderr, 
00726     "strsclnt: connection on thread %d read %d bytes total. ---------\n", 
00727            tid, countRead);
00728 
00729     return SECSuccess;      /* success */
00730 }
00731 
00732 #define USE_SOCK_PEER_ID 1
00733 
00734 #ifdef USE_SOCK_PEER_ID
00735 
00736 PRInt32 lastFullHandshakePeerID;
00737 
00738 SECStatus 
00739 myHandshakeCallback(PRFileDesc *socket, void *arg) 
00740 {
00741     PR_AtomicSet(&lastFullHandshakePeerID, (PRInt32) arg);
00742     return SECSuccess;
00743 }
00744 
00745 #endif
00746 
00747 /* one copy of this function is launched in a separate thread for each
00748 ** connection to be made.
00749 */
00750 int
00751 do_connects(
00752     void *    a,
00753     void *    b,
00754     int         tid)
00755 {
00756     PRNetAddr  *        addr              = (PRNetAddr *)  a;
00757     PRFileDesc *        model_sock = (PRFileDesc *) b;
00758     PRFileDesc *        ssl_sock   = 0;
00759     PRFileDesc *        tcp_sock   = 0;
00760     PRStatus          prStatus;
00761     PRUint32            sleepInterval     = 50; /* milliseconds */
00762     SECStatus        result;
00763     int                 rv         = SECSuccess;
00764     PRSocketOptionData  opt;
00765 
00766 retry:
00767 
00768     tcp_sock = PR_NewTCPSocket();
00769     if (tcp_sock == NULL) {
00770        errExit("PR_NewTCPSocket");
00771     }
00772 
00773     opt.option             = PR_SockOpt_Nonblocking;
00774     opt.value.non_blocking = PR_FALSE;
00775     prStatus = PR_SetSocketOption(tcp_sock, &opt);
00776     if (prStatus != PR_SUCCESS) {
00777        errWarn("PR_SetSocketOption(PR_SockOpt_Nonblocking, PR_FALSE)");
00778        PR_Close(tcp_sock);
00779        return SECSuccess;
00780     } 
00781 
00782     if (NoDelay) {
00783        opt.option         = PR_SockOpt_NoDelay;
00784        opt.value.no_delay = PR_TRUE;
00785        prStatus = PR_SetSocketOption(tcp_sock, &opt);
00786        if (prStatus != PR_SUCCESS) {
00787            errWarn("PR_SetSocketOption(PR_SockOpt_NoDelay, PR_TRUE)");
00788            PR_Close(tcp_sock);
00789            return SECSuccess;
00790        } 
00791     }
00792 
00793     prStatus = PR_Connect(tcp_sock, addr, PR_INTERVAL_NO_TIMEOUT);
00794     if (prStatus != PR_SUCCESS) {
00795         PRErrorCode err = PR_GetError(); /* save error code */
00796         if (ThrottleUp) {
00797             PRTime now = PR_Now();
00798             PR_Lock(threadLock);
00799             lastConnectFailure = PR_MAX(now, lastConnectFailure);
00800             PR_Unlock(threadLock);
00801         }
00802         if ((err == PR_CONNECT_REFUSED_ERROR) || 
00803            (err == PR_CONNECT_RESET_ERROR)      ) {
00804            int connections = numConnected;
00805 
00806            PR_Close(tcp_sock);
00807             PR_Lock(threadLock);
00808             if (connections > 2 && active_threads >= connections) {
00809                 active_threads = connections - 1;
00810                 fprintf(stderr,"active_threads set down to %d\n",
00811                         active_threads);
00812             }
00813             PR_Unlock(threadLock);
00814 
00815             if (QuitOnTimeout && sleepInterval > 40000) {
00816                 fprintf(stderr,
00817                    "strsclnt: Client timed out waiting for connection to server.\n");
00818                 exit(1);
00819             }
00820            PR_Sleep(PR_MillisecondsToInterval(sleepInterval));
00821            sleepInterval <<= 1;
00822            goto retry;
00823        }
00824        errWarn("PR_Connect");
00825        rv = SECFailure;
00826        goto done;
00827     } else {
00828         if (ThrottleUp) {
00829             PRTime now = PR_Now();
00830             PR_Lock(threadLock);
00831             lastConnectSuccess = PR_MAX(now, lastConnectSuccess);
00832             PR_Unlock(threadLock);
00833         }
00834     }
00835 
00836     ssl_sock = SSL_ImportFD(model_sock, tcp_sock);
00837     /* XXX if this import fails, close tcp_sock and return. */
00838     if (!ssl_sock) {
00839        PR_Close(tcp_sock);
00840        return SECSuccess;
00841     }
00842     if (fullhs != NO_FULLHS_PERCENTAGE) {
00843 #ifdef USE_SOCK_PEER_ID
00844         char sockPeerIDString[512];
00845         static PRInt32 sockPeerID = 0; /* atomically incremented */
00846         PRInt32 thisPeerID;
00847 #endif
00848         PRInt32 savid = PR_AtomicIncrement(&globalconid);
00849         PRInt32 conid = 1 + (savid - 1) % 100;
00850         /* don't change peer ID on the very first handshake, which is always
00851            a full, so the session gets stored into the client cache */
00852         if ( (savid != 1) &&
00853             ( ( (savid <= total_connections_rounded_down_to_hundreds) &&
00854                 (conid <= fullhs) ) ||
00855               (conid*100 <= total_connections_modulo_100*fullhs ) ) ) {
00856 #ifdef USE_SOCK_PEER_ID
00857             /* force a full handshake by changing the socket peer ID */
00858             thisPeerID = PR_AtomicIncrement(&sockPeerID);
00859         } else {
00860             /* reuse previous sockPeerID for restart handhsake */
00861             thisPeerID = lastFullHandshakePeerID;
00862         }
00863         PR_snprintf(sockPeerIDString, sizeof(sockPeerIDString), "ID%d",
00864                     thisPeerID);
00865         SSL_SetSockPeerID(ssl_sock, sockPeerIDString);
00866         SSL_HandshakeCallback(ssl_sock, myHandshakeCallback, (void*)thisPeerID);
00867 #else
00868             /* force a full handshake by setting the no cache option */
00869             SSL_OptionSet(ssl_sock, SSL_NO_CACHE, 1);
00870         }
00871 #endif
00872     }
00873     rv = SSL_ResetHandshake(ssl_sock, /* asServer */ 0);
00874     if (rv != SECSuccess) {
00875        errWarn("SSL_ResetHandshake");
00876        goto done;
00877     }
00878 
00879     PR_AtomicIncrement(&numConnected);
00880 
00881     if (bigBuf.data != NULL) {
00882        result = handle_fdx_connection( ssl_sock, tid);
00883     } else {
00884        result = handle_connection( ssl_sock, tid);
00885     }
00886 
00887     PR_AtomicDecrement(&numConnected);
00888 
00889 done:
00890     if (ssl_sock) {
00891        PR_Close(ssl_sock);
00892     } else if (tcp_sock) {
00893        PR_Close(tcp_sock);
00894     }
00895     return SECSuccess;
00896 }
00897 
00898 /* Returns IP address for hostname as PRUint32 in Host Byte Order.
00899 ** Since the value returned is an integer (not a string of bytes), 
00900 ** it is inherently in Host Byte Order. 
00901 */
00902 PRUint32
00903 getIPAddress(const char * hostName) 
00904 {
00905     const unsigned char *p;
00906     PRStatus           prStatus;
00907     PRUint32           rv;
00908     PRHostEnt          prHostEnt;
00909     char                 scratch[PR_NETDB_BUF_SIZE];
00910 
00911     prStatus = PR_GetHostByName(hostName, scratch, sizeof scratch, &prHostEnt);
00912     if (prStatus != PR_SUCCESS)
00913        errExit("PR_GetHostByName");
00914 
00915 #undef  h_addr
00916 #define h_addr  h_addr_list[0]   /* address, for backward compatibility */
00917 
00918     p = (const unsigned char *)(prHostEnt.h_addr); /* in Network Byte order */
00919     FPRINTF(stderr, "strsclnt: %s -> %d.%d.%d.%d\n", hostName, 
00920            p[0], p[1], p[2], p[3]);
00921     rv = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
00922     return rv;
00923 }
00924 
00925 typedef struct {
00926     PRLock* lock;
00927     char* nickname;
00928     CERTCertificate* cert;
00929     SECKEYPrivateKey* key;
00930     char* password;
00931 } cert_and_key;
00932 
00933 PRBool FindCertAndKey(cert_and_key* Cert_And_Key)
00934 {
00935     if ( (NULL == Cert_And_Key->nickname) || (0 == strcmp(Cert_And_Key->nickname,"none"))) {
00936         return PR_TRUE;
00937     }
00938     Cert_And_Key->cert = CERT_FindUserCertByUsage(CERT_GetDefaultCertDB(),
00939                             Cert_And_Key->nickname, certUsageSSLClient,
00940                             PR_FALSE, Cert_And_Key->password);
00941     if (Cert_And_Key->cert) {
00942         Cert_And_Key->key = PK11_FindKeyByAnyCert(Cert_And_Key->cert, Cert_And_Key->password);
00943     }
00944     if (Cert_And_Key->cert && Cert_And_Key->key) {
00945         return PR_TRUE;
00946     } else {
00947         return PR_FALSE;
00948     }
00949 }
00950 
00951 PRBool LoggedIn(CERTCertificate* cert, SECKEYPrivateKey* key)
00952 {
00953     if ( (cert->slot) && (key->pkcs11Slot) &&
00954          (PR_TRUE == PK11_IsLoggedIn(cert->slot, NULL)) &&
00955          (PR_TRUE == PK11_IsLoggedIn(key->pkcs11Slot, NULL)) ) {
00956         return PR_TRUE;
00957     }
00958  
00959     return PR_FALSE;
00960 }
00961 
00962 SECStatus 
00963 StressClient_GetClientAuthData(void * arg,
00964                       PRFileDesc * socket,
00965                     struct CERTDistNamesStr * caNames,
00966                     struct CERTCertificateStr ** pRetCert,
00967                     struct SECKEYPrivateKeyStr **pRetKey)
00968 {
00969     cert_and_key* Cert_And_Key = (cert_and_key*) arg;
00970 
00971     if (!pRetCert || !pRetKey) {
00972         /* bad pointers, can't return a cert or key */
00973         return SECFailure;
00974     }
00975 
00976     *pRetCert = NULL;
00977     *pRetKey = NULL;
00978 
00979     if (Cert_And_Key && Cert_And_Key->nickname) {
00980         while (PR_TRUE) {
00981             if (Cert_And_Key && Cert_And_Key->lock) {
00982                 int timeout = 0;
00983                 PR_Lock(Cert_And_Key->lock);
00984 
00985                 if (Cert_And_Key->cert) {
00986                     *pRetCert = CERT_DupCertificate(Cert_And_Key->cert);
00987                 }
00988 
00989                 if (Cert_And_Key->key) {
00990                     *pRetKey = SECKEY_CopyPrivateKey(Cert_And_Key->key);
00991                 }
00992                 PR_Unlock(Cert_And_Key->lock);
00993                 if (!*pRetCert || !*pRetKey) {
00994                     /* one or both of them failed to copy. Either the source was NULL, or there was
00995                     ** an out of memory condition. Free any allocated copy and fail */
00996                     if (*pRetCert) {
00997                         CERT_DestroyCertificate(*pRetCert);
00998                         *pRetCert = NULL;
00999                     }
01000                     if (*pRetKey) {
01001                         SECKEY_DestroyPrivateKey(*pRetKey);
01002                         *pRetKey = NULL;
01003                     }
01004                     break;
01005                 }
01006                 /* now check if those objects are valid */
01007                 if ( PR_FALSE == LoggedIn(*pRetCert, *pRetKey) ) {
01008                     /* token is no longer logged in, it was removed */
01009 
01010                     /* first, delete and clear our invalid local objects */
01011                     CERT_DestroyCertificate(*pRetCert);
01012                     SECKEY_DestroyPrivateKey(*pRetKey);
01013                     *pRetCert = NULL;
01014                     *pRetKey = NULL;
01015 
01016                     PR_Lock(Cert_And_Key->lock);
01017                     /* check if another thread already logged back in */
01018                     if (PR_TRUE == LoggedIn(Cert_And_Key->cert, Cert_And_Key->key)) {
01019                         /* yes : try again */
01020                         PR_Unlock(Cert_And_Key->lock);
01021                         continue;
01022                     }
01023                     /* this is the thread to retry */
01024                     CERT_DestroyCertificate(Cert_And_Key->cert);
01025                     SECKEY_DestroyPrivateKey(Cert_And_Key->key);
01026                     Cert_And_Key->cert = NULL;
01027                     Cert_And_Key->key = NULL;
01028 
01029 
01030                     /* now look up the cert and key again */
01031                     while (PR_FALSE == FindCertAndKey(Cert_And_Key) ) {
01032                         PR_Sleep(PR_SecondsToInterval(1));
01033                         timeout++;
01034                         if (timeout>=60) {
01035                             printf("\nToken pulled and not reinserted early enough : aborting.\n");
01036                             exit(1);
01037                         }
01038                     }
01039                     PR_Unlock(Cert_And_Key->lock);
01040                     continue;
01041                     /* try again to reduce code size */
01042                 }
01043                 return SECSuccess;
01044             }
01045         }
01046         *pRetCert = NULL;
01047         *pRetKey = NULL;
01048         return SECFailure;
01049     } else {
01050         /* no cert configured, automatically find the right cert. */
01051         CERTCertificate *  cert = NULL;
01052         SECKEYPrivateKey * privkey = NULL;
01053         CERTCertNicknames * names;
01054         int                 i;
01055         void *             proto_win = NULL;
01056         SECStatus          rv         = SECFailure;
01057 
01058         if (Cert_And_Key) {
01059             proto_win = Cert_And_Key->password;
01060         }
01061 
01062         names = CERT_GetCertNicknames(CERT_GetDefaultCertDB(),
01063                                       SEC_CERT_NICKNAMES_USER, proto_win);
01064         if (names != NULL) {
01065             for (i = 0; i < names->numnicknames; i++) {
01066                 cert = CERT_FindUserCertByUsage(CERT_GetDefaultCertDB(),
01067                             names->nicknames[i], certUsageSSLClient,
01068                             PR_FALSE, proto_win);       
01069                 if ( !cert )
01070                     continue;
01071                 /* Only check unexpired certs */
01072                 if (CERT_CheckCertValidTimes(cert, PR_Now(), PR_TRUE) != 
01073                                              secCertTimeValid ) {
01074                     CERT_DestroyCertificate(cert);
01075                     continue;
01076                 }
01077                 rv = NSS_CmpCertChainWCANames(cert, caNames);
01078                 if ( rv == SECSuccess ) {
01079                     privkey = PK11_FindKeyByAnyCert(cert, proto_win);
01080                     if ( privkey )
01081                         break;
01082                 }
01083                 rv = SECFailure;
01084                 CERT_DestroyCertificate(cert);
01085             }
01086             CERT_FreeNicknames(names);
01087         }
01088         if (rv == SECSuccess) {
01089             *pRetCert = cert;
01090             *pRetKey  = privkey;
01091         }
01092         return rv;
01093     }
01094 }
01095 
01096 #define HEXCHAR_TO_INT(c, i) \
01097     if (((c) >= '0') && ((c) <= '9')) { \
01098        i = (c) - '0'; \
01099     } else if (((c) >= 'a') && ((c) <= 'f')) { \
01100        i = (c) - 'a' + 10; \
01101     } else if (((c) >= 'A') && ((c) <= 'F')) { \
01102        i = (c) - 'A' + 10; \
01103     } else { \
01104        Usage("strsclnt"); \
01105     }
01106 
01107 void
01108 client_main(
01109     unsigned short      port, 
01110     int                 connections,
01111     cert_and_key* Cert_And_Key,
01112     const char *     hostName)
01113 {
01114     PRFileDesc *model_sock  = NULL;
01115     int         i;
01116     int         rv;
01117     PRUint32  ipAddress;    /* in host byte order */
01118     PRNetAddr   addr;
01119 
01120     /* Assemble NetAddr struct for connections. */
01121     ipAddress = getIPAddress(hostName);
01122 
01123     addr.inet.family = PR_AF_INET;
01124     addr.inet.port   = PR_htons(port);
01125     addr.inet.ip     = PR_htonl(ipAddress);
01126 
01127     /* all suites except RSA_NULL_MD5 are enabled by Domestic Policy */
01128     NSS_SetDomesticPolicy();
01129 
01130     /* all the SSL2 and SSL3 cipher suites are enabled by default. */
01131     if (cipherString) {
01132         int ndx;
01133 
01134         /* disable all the ciphers, then enable the ones we want. */
01135         disableAllSSLCiphers();
01136 
01137         while (0 != (ndx = *cipherString++)) {
01138             int  cipher;
01139 
01140            if (ndx == ':') {
01141               int ctmp;
01142 
01143               cipher = 0;
01144               HEXCHAR_TO_INT(*cipherString, ctmp)
01145               cipher |= (ctmp << 12);
01146               cipherString++;
01147               HEXCHAR_TO_INT(*cipherString, ctmp)
01148               cipher |= (ctmp << 8);
01149               cipherString++;
01150               HEXCHAR_TO_INT(*cipherString, ctmp)
01151               cipher |= (ctmp << 4);
01152               cipherString++;
01153               HEXCHAR_TO_INT(*cipherString, ctmp)
01154               cipher |= ctmp;
01155               cipherString++;
01156            } else {
01157               const int *cptr;
01158 
01159               if (! isalpha(ndx))
01160                   Usage("strsclnt");
01161               cptr = islower(ndx) ? ssl3CipherSuites : ssl2CipherSuites;
01162               for (ndx &= 0x1f; (cipher = *cptr++) != 0 && --ndx > 0; ) 
01163                   /* do nothing */;
01164            }
01165             if (cipher > 0) {
01166               SECStatus rv;
01167                 rv = SSL_CipherPrefSetDefault(cipher, PR_TRUE);
01168               if (rv != SECSuccess) {
01169                   fprintf(stderr, 
01170               "strsclnt: SSL_CipherPrefSetDefault failed with value 0x%04x\n",
01171                          cipher);
01172                   exit(1);
01173               }
01174             } else {
01175               Usage("strsclnt");
01176             }
01177         }
01178     }
01179 
01180     /* configure model SSL socket. */
01181 
01182     model_sock = PR_NewTCPSocket();
01183     if (model_sock == NULL) {
01184        errExit("PR_NewTCPSocket on model socket");
01185     }
01186 
01187     model_sock = SSL_ImportFD(NULL, model_sock);
01188     if (model_sock == NULL) {
01189        errExit("SSL_ImportFD");
01190     }
01191 
01192     /* do SSL configuration. */
01193 
01194     rv = SSL_OptionSet(model_sock, SSL_SECURITY, 1);
01195     if (rv < 0) {
01196        errExit("SSL_OptionSet SSL_SECURITY");
01197     }
01198 
01199     /* disabling SSL2 compatible hellos also disables SSL2 */
01200     rv = SSL_OptionSet(model_sock, SSL_V2_COMPATIBLE_HELLO, !disableSSL2);
01201     if (rv != SECSuccess) {
01202        errExit("error enabling SSLv2 compatible hellos ");
01203     }
01204 
01205     rv = SSL_OptionSet(model_sock, SSL_ENABLE_SSL3, !disableSSL3);
01206     if (rv != SECSuccess) {
01207        errExit("error enabling SSLv3 ");
01208     }
01209 
01210     rv = SSL_OptionSet(model_sock, SSL_ENABLE_TLS, !disableTLS);
01211     if (rv != SECSuccess) {
01212        errExit("error enabling TLS ");
01213     }
01214 
01215     if (bigBuf.data) { /* doing FDX */
01216        rv = SSL_OptionSet(model_sock, SSL_ENABLE_FDX, 1);
01217        if (rv < 0) {
01218            errExit("SSL_OptionSet SSL_ENABLE_FDX");
01219        }
01220     }
01221 
01222     if (NoReuse) {
01223        rv = SSL_OptionSet(model_sock, SSL_NO_CACHE, 1);
01224        if (rv < 0) {
01225            errExit("SSL_OptionSet SSL_NO_CACHE");
01226        }
01227     }
01228 
01229     if (bypassPKCS11) {
01230        rv = SSL_OptionSet(model_sock, SSL_BYPASS_PKCS11, 1);
01231        if (rv < 0) {
01232            errExit("SSL_OptionSet SSL_BYPASS_PKCS11");
01233        }
01234     }
01235 
01236     if (disableLocking) {
01237         rv = SSL_OptionSet(model_sock, SSL_NO_LOCKS, 1);
01238        if (rv < 0) {
01239            errExit("SSL_OptionSet SSL_NO_LOCKS");
01240        }
01241     }
01242 
01243     SSL_SetURL(model_sock, hostName);
01244 
01245     SSL_AuthCertificateHook(model_sock, mySSLAuthCertificate, 
01246                      (void *)CERT_GetDefaultCertDB());
01247     SSL_BadCertHook(model_sock, myBadCertHandler, NULL);
01248 
01249     SSL_GetClientAuthDataHook(model_sock, StressClient_GetClientAuthData, (void*)Cert_And_Key);
01250 
01251     /* I'm not going to set the HandshakeCallback function. */
01252 
01253     /* end of ssl configuration. */
01254 
01255     init_thread_data();
01256 
01257     remaining_connections = total_connections = connections;
01258     total_connections_modulo_100 = total_connections % 100;
01259     total_connections_rounded_down_to_hundreds =
01260         total_connections - total_connections_modulo_100;
01261 
01262     if (!NoReuse) {
01263         remaining_connections = 1;
01264        rv = launch_thread(do_connects, &addr, model_sock, 0);
01265        /* wait for the first connection to terminate, then launch the rest. */
01266        reap_threads();
01267         remaining_connections = total_connections - 1 ;
01268     }
01269     if (remaining_connections > 0) {
01270         active_threads  = PR_MIN(active_threads, remaining_connections);
01271        /* Start up the threads */
01272        for (i=0;i<active_threads;i++) {
01273            rv = launch_thread(do_connects, &addr, model_sock, i);
01274        }
01275        reap_threads();
01276     }
01277     destroy_thread_data();
01278 
01279     PR_Close(model_sock);
01280 }
01281 
01282 SECStatus
01283 readBigFile(const char * fileName)
01284 {
01285     PRFileInfo  info;
01286     PRStatus  status;
01287     SECStatus rv     = SECFailure;
01288     int              count;
01289     int              hdrLen;
01290     PRFileDesc *local_file_fd = NULL;
01291 
01292     status = PR_GetFileInfo(fileName, &info);
01293 
01294     if (status == PR_SUCCESS &&
01295        info.type == PR_FILE_FILE &&
01296        info.size > 0 &&
01297        NULL != (local_file_fd = PR_Open(fileName, PR_RDONLY, 0))) {
01298 
01299        hdrLen      = PORT_Strlen(outHeader);
01300        bigBuf.len  = hdrLen + info.size;
01301        bigBuf.data = PORT_Malloc(bigBuf.len + 4095);
01302        if (!bigBuf.data) {
01303            errWarn("PORT_Malloc");
01304            goto done;
01305        }
01306 
01307        PORT_Memcpy(bigBuf.data, outHeader, hdrLen);
01308 
01309        count = PR_Read(local_file_fd, bigBuf.data + hdrLen, info.size);
01310        if (count != info.size) {
01311            errWarn("PR_Read local file");
01312            goto done;
01313        }
01314        rv = SECSuccess;
01315 done:
01316        PR_Close(local_file_fd);
01317     }
01318     return rv;
01319 }
01320 
01321 int
01322 main(int argc, char **argv)
01323 {
01324     const char *         dir         = ".";
01325     const char *         fileName    = NULL;
01326     char *               hostName    = NULL;
01327     char *               nickName    = NULL;
01328     char *               progName    = NULL;
01329     char *               tmp         = NULL;
01330     char *            passwd      = NULL;
01331     int                  connections = 1;
01332     int                  exitVal;
01333     int                  tmpInt;
01334     unsigned short       port        = 443;
01335     SECStatus            rv;
01336     PLOptState *         optstate;
01337     PLOptStatus          status;
01338     cert_and_key Cert_And_Key;
01339 
01340     /* Call the NSPR initialization routines */
01341     PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
01342 
01343     tmp      = strrchr(argv[0], '/');
01344     tmp      = tmp ? tmp + 1 : argv[0];
01345     progName = strrchr(tmp, '\\');
01346     progName = progName ? progName + 1 : tmp;
01347  
01348 
01349     optstate = PL_CreateOptState(argc, argv, "23BC:DNP:TUc:d:f:in:op:qst:vw:");
01350     while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
01351        switch(optstate->option) {
01352 
01353        case '2': disableSSL2 = PR_TRUE; break;
01354 
01355        case '3': disableSSL3 = PR_TRUE; break;
01356 
01357        case 'B': bypassPKCS11 = PR_TRUE; break;
01358 
01359        case 'C': cipherString = optstate->value; break;
01360 
01361        case 'D': NoDelay = PR_TRUE; break;
01362 
01363        case 'N': NoReuse = 1; break;
01364         
01365        case 'P': fullhs = PORT_Atoi(optstate->value); break;
01366 
01367        case 'T': disableTLS = PR_TRUE; break;
01368             
01369        case 'U': ThrottleUp = PR_TRUE; break;
01370 
01371        case 'c': connections = PORT_Atoi(optstate->value); break;
01372 
01373        case 'd': dir = optstate->value; break;
01374 
01375        case 'f': fileName = optstate->value; break;
01376 
01377        case 'i': ignoreErrors = PR_TRUE; break;
01378 
01379         case 'n': nickName = PL_strdup(optstate->value); break;
01380 
01381        case 'o': MakeCertOK++; break;
01382 
01383        case 'p': port = PORT_Atoi(optstate->value); break;
01384 
01385        case 'q': QuitOnTimeout = PR_TRUE; break;
01386 
01387        case 's': disableLocking = PR_TRUE; break;
01388 
01389        case 't':
01390            tmpInt = PORT_Atoi(optstate->value);
01391            if (tmpInt > 0 && tmpInt < MAX_THREADS) 
01392                max_threads = active_threads = tmpInt;
01393            break;
01394 
01395         case 'v': verbose++; break;
01396 
01397        case 'w': passwd = PL_strdup(optstate->value); break;
01398 
01399        case 0:   /* positional parameter */
01400            if (hostName) {
01401               Usage(progName);
01402            }
01403            hostName = PL_strdup(optstate->value);
01404            break;
01405 
01406        default:
01407        case '?':
01408            Usage(progName);
01409            break;
01410 
01411        }
01412     }
01413     if (!hostName || status == PL_OPT_BAD)
01414        Usage(progName);
01415 
01416     if (fullhs!= NO_FULLHS_PERCENTAGE && (fullhs < 0 || fullhs>100 || NoReuse) )
01417         Usage(progName);
01418 
01419     if (port == 0)
01420        Usage(progName);
01421 
01422     if (fileName)
01423        readBigFile(fileName);
01424 
01425     /* set our password function */
01426     if ( passwd ) {
01427        PK11_SetPasswordFunc(ownPasswd);
01428     } else {
01429        PK11_SetPasswordFunc(SECU_GetModulePassword);
01430     }
01431 
01432     tmp = PR_GetEnv("NSS_DEBUG_TIMEOUT");
01433     if (tmp && tmp[0]) {
01434         int sec = PORT_Atoi(tmp);
01435        if (sec > 0) {
01436            maxInterval = PR_SecondsToInterval(sec);
01437        }
01438     }
01439 
01440     /* Call the libsec initialization routines */
01441     rv = NSS_Initialize(dir, "", "", SECMOD_DB, NSS_INIT_READONLY);
01442     if (rv != SECSuccess) {
01443        fputs("NSS_Init failed.\n", stderr);
01444        exit(1);
01445     }
01446     ssl3stats = SSL_GetStatistics();
01447     Cert_And_Key.lock = PR_NewLock();
01448     Cert_And_Key.nickname = nickName;
01449     Cert_And_Key.password = passwd;
01450     Cert_And_Key.cert = NULL;
01451     Cert_And_Key.key = NULL;
01452 
01453     if (PR_FALSE == FindCertAndKey(&Cert_And_Key)) {
01454 
01455        if (Cert_And_Key.cert == NULL) {
01456            fprintf(stderr, "strsclnt: Can't find certificate %s\n", Cert_And_Key.nickname);
01457            exit(1);
01458        }
01459 
01460        if (Cert_And_Key.key == NULL) {
01461            fprintf(stderr, "strsclnt: Can't find Private Key for cert %s\n", 
01462                   Cert_And_Key.nickname);
01463            exit(1);
01464        }
01465 
01466     }
01467 
01468     client_main(port, connections, &Cert_And_Key, hostName);
01469 
01470     /* clean up */
01471     if (Cert_And_Key.cert) {
01472        CERT_DestroyCertificate(Cert_And_Key.cert);
01473     }
01474     if (Cert_And_Key.key) {
01475        SECKEY_DestroyPrivateKey(Cert_And_Key.key);
01476     }
01477     PR_DestroyLock(Cert_And_Key.lock);
01478 
01479     /* some final stats. */
01480     if (ssl3stats->hsh_sid_cache_hits + ssl3stats->hsh_sid_cache_misses +
01481         ssl3stats->hsh_sid_cache_not_ok == 0) {
01482        /* presumably we were testing SSL2. */
01483        printf("strsclnt: SSL2 - %d server certificates tested.\n",
01484                certsTested);
01485     } else {
01486        printf(
01487        "strsclnt: %ld cache hits; %ld cache misses, %ld cache not reusable\n",
01488            ssl3stats->hsh_sid_cache_hits, 
01489            ssl3stats->hsh_sid_cache_misses,
01490            ssl3stats->hsh_sid_cache_not_ok);
01491     }
01492 
01493     if (!NoReuse)
01494        exitVal = (ssl3stats->hsh_sid_cache_misses > 1) ||
01495                 (ssl3stats->hsh_sid_cache_not_ok != 0) ||
01496                 (certsTested > 1);
01497     else {
01498        printf("strsclnt: NoReuse - %d server certificates tested.\n",
01499                certsTested);
01500         if (ssl3stats->hsh_sid_cache_hits + ssl3stats->hsh_sid_cache_misses +
01501             ssl3stats->hsh_sid_cache_not_ok > 0) {
01502             exitVal = (ssl3stats->hsh_sid_cache_misses != connections) ||
01503                 (certsTested != connections);
01504         } else {                /* ssl2 connections */
01505             exitVal = (certsTested != connections);
01506         }
01507     }
01508 
01509     exitVal = ( exitVal || failed_already );
01510     SSL_ClearSessionCache();
01511     if (NSS_Shutdown() != SECSuccess) {
01512         printf("strsclnt: NSS_Shutdown() failed.\n");
01513         exit(1);
01514     }
01515 
01516     PR_Cleanup();
01517     return exitVal;
01518 }
01519