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     SSL_RSA_WITH_NULL_SHA,                /* z */
00119     0
00120 };
00121 
00122 #define NO_FULLHS_PERCENTAGE -1
00123 
00124 /* This global string is so that client main can see 
00125  * which ciphers to use. 
00126  */
00127 
00128 static const char *cipherString;
00129 
00130 static PRInt32 certsTested;
00131 static int MakeCertOK;
00132 static int NoReuse;
00133 static int fullhs = NO_FULLHS_PERCENTAGE; /* percentage of full handshakes to
00134                                           ** perform */
00135 static PRInt32 globalconid = 0; /* atomically set */
00136 static int total_connections;  /* total number of connections to perform */
00137 static int total_connections_rounded_down_to_hundreds;
00138 static int total_connections_modulo_100;
00139 
00140 static PRBool NoDelay;
00141 static PRBool QuitOnTimeout = PR_FALSE;
00142 static PRBool ThrottleUp = PR_FALSE;
00143 
00144 static PRLock    * threadLock; /* protects the global variables below */
00145 static PRTime lastConnectFailure;
00146 static PRTime lastConnectSuccess;
00147 static PRTime lastThrottleUp;
00148 static PRInt32 remaining_connections;  /* number of connections left */
00149 static int active_threads = 8; /* number of threads currently trying to
00150                                ** connect */
00151 static PRInt32 numUsed;
00152 /* end of variables protected by threadLock */
00153 
00154 static SSL3Statistics * ssl3stats;
00155 
00156 static int failed_already = 0;
00157 static PRBool disableSSL2     = PR_FALSE;
00158 static PRBool disableSSL3     = PR_FALSE;
00159 static PRBool disableTLS      = PR_FALSE;
00160 static PRBool bypassPKCS11    = PR_FALSE;
00161 static PRBool disableLocking  = PR_FALSE;
00162 static PRBool ignoreErrors    = PR_FALSE;
00163 
00164 PRIntervalTime maxInterval    = PR_INTERVAL_NO_TIMEOUT;
00165 
00166 char * progName;
00167 
00168 char * ownPasswd( PK11SlotInfo *slot, PRBool retry, void *arg)
00169 {
00170         char *passwd = NULL;
00171 
00172         if ( (!retry) && arg ) {
00173                 passwd = PL_strdup((char *)arg);
00174         }
00175 
00176         return passwd;
00177 }
00178 
00179 int    stopping;
00180 int    verbose;
00181 SECItem       bigBuf;
00182 
00183 #define PRINTF  if (verbose)  printf
00184 #define FPRINTF if (verbose) fprintf
00185 
00186 static void
00187 Usage(const char *progName)
00188 {
00189     fprintf(stderr, 
00190        "Usage: %s [-n nickname] [-p port] [-d dbdir] [-c connections]\n"
00191        "          [-23BDNTovqs] [-f filename] [-N | -P percentage]\n"
00192        "          [-w dbpasswd] [-C cipher(s)] [-t threads] hostname\n"
00193        " where -v means verbose\n"
00194         "       -o flag is interpreted as follows:\n"
00195         "          1 -o   means override the result of server certificate validation.\n"
00196         "          2 -o's mean skip server certificate validation altogether.\n"
00197        "       -D means no TCP delays\n"
00198        "       -q means quit when server gone (timeout rather than retry forever)\n"
00199        "       -s means disable SSL socket locking\n"
00200        "       -N means no session reuse\n"
00201        "       -P means do a specified percentage of full handshakes (0-100)\n"
00202         "       -2 means disable SSL2\n"
00203         "       -3 means disable SSL3\n"
00204         "       -T means disable TLS\n"
00205         "       -U means enable throttling up threads\n"
00206        "       -B bypasses the PKCS11 layer for SSL encryption and MACing\n",
00207        progName);
00208     exit(1);
00209 }
00210 
00211 
00212 static void
00213 errWarn(char * funcString)
00214 {
00215     PRErrorCode  perr      = PR_GetError();
00216     const char * errString = SECU_Strerror(perr);
00217 
00218     fprintf(stderr, "strsclnt: %s returned error %d:\n%s\n",
00219             funcString, perr, errString);
00220 }
00221 
00222 static void
00223 errExit(char * funcString)
00224 {
00225     errWarn(funcString);
00226     exit(1);
00227 }
00228 
00229 /**************************************************************************
00230 ** 
00231 ** Routines for disabling SSL ciphers.
00232 **
00233 **************************************************************************/
00234 
00235 void
00236 disableAllSSLCiphers(void)
00237 {
00238     const PRUint16 *cipherSuites = SSL_ImplementedCiphers;
00239     int             i            = SSL_NumImplementedCiphers;
00240     SECStatus       rv;
00241 
00242     /* disable all the SSL3 cipher suites */
00243     while (--i >= 0) {
00244        PRUint16 suite = cipherSuites[i];
00245         rv = SSL_CipherPrefSetDefault(suite, PR_FALSE);
00246        if (rv != SECSuccess) {
00247            printf("SSL_CipherPrefSetDefault didn't like value 0x%04x (i = %d)\n",
00248                  suite, i);
00249            errWarn("SSL_CipherPrefSetDefault");
00250            exit(2);
00251        }
00252     }
00253 }
00254 
00255 static SECStatus
00256 myGoodSSLAuthCertificate(void *arg, PRFileDesc *fd, PRBool checkSig,
00257                    PRBool isServer)
00258 {
00259     return SECSuccess;
00260 }
00261 
00262 /* This invokes the "default" AuthCert handler in libssl.
00263 ** The only reason to use this one is that it prints out info as it goes. 
00264 */
00265 static SECStatus
00266 mySSLAuthCertificate(void *arg, PRFileDesc *fd, PRBool checkSig,
00267                    PRBool isServer)
00268 {
00269     SECStatus rv;
00270     CERTCertificate *    peerCert;
00271 
00272     if (MakeCertOK>=2) {
00273         return SECSuccess;
00274     }
00275     peerCert = SSL_PeerCertificate(fd);
00276 
00277     PRINTF("strsclnt: Subject: %s\nstrsclnt: Issuer : %s\n", 
00278            peerCert->subjectName, peerCert->issuerName); 
00279     /* invoke the "default" AuthCert handler. */
00280     rv = SSL_AuthCertificate(arg, fd, checkSig, isServer);
00281 
00282     PR_AtomicIncrement(&certsTested);
00283     if (rv == SECSuccess) {
00284        fputs("strsclnt: -- SSL: Server Certificate Validated.\n", stderr);
00285     }
00286     CERT_DestroyCertificate(peerCert);
00287     /* error, if any, will be displayed by the Bad Cert Handler. */
00288     return rv;  
00289 }
00290 
00291 static SECStatus
00292 myBadCertHandler( void *arg, PRFileDesc *fd)
00293 {
00294     int err = PR_GetError();
00295     if (!MakeCertOK)
00296        fprintf(stderr, 
00297            "strsclnt: -- SSL: Server Certificate Invalid, err %d.\n%s\n", 
00298             err, SECU_Strerror(err));
00299     return (MakeCertOK ? SECSuccess : SECFailure);
00300 }
00301 
00302 void 
00303 printSecurityInfo(PRFileDesc *fd)
00304 {
00305     CERTCertificate * cert = NULL;
00306     SSL3Statistics * ssl3stats = SSL_GetStatistics();
00307     SECStatus result;
00308     SSLChannelInfo    channel;
00309     SSLCipherSuiteInfo suite;
00310 
00311     static int only_once;
00312 
00313     if (only_once && verbose < 2)
00314        return;
00315     only_once = 1;
00316 
00317     result = SSL_GetChannelInfo(fd, &channel, sizeof channel);
00318     if (result == SECSuccess && 
00319         channel.length == sizeof channel && 
00320        channel.cipherSuite) {
00321        result = SSL_GetCipherSuiteInfo(channel.cipherSuite, 
00322                                    &suite, sizeof suite);
00323        if (result == SECSuccess) {
00324            FPRINTF(stderr, 
00325            "strsclnt: SSL version %d.%d using %d-bit %s with %d-bit %s MAC\n",
00326               channel.protocolVersion >> 8, channel.protocolVersion & 0xff,
00327               suite.effectiveKeyBits, suite.symCipherName, 
00328               suite.macBits, suite.macAlgorithmName);
00329            FPRINTF(stderr, 
00330            "strsclnt: Server Auth: %d-bit %s, Key Exchange: %d-bit %s\n",
00331               channel.authKeyBits, suite.authAlgorithmName,
00332               channel.keaKeyBits,  suite.keaTypeName);
00333        }
00334     }
00335 
00336     cert = SSL_LocalCertificate(fd);
00337     if (!cert)
00338        cert = SSL_PeerCertificate(fd);
00339 
00340     if (verbose && cert) {
00341        char * ip = CERT_NameToAscii(&cert->issuer);
00342        char * sp = CERT_NameToAscii(&cert->subject);
00343         if (sp) {
00344            fprintf(stderr, "strsclnt: subject DN: %s\n", sp);
00345            PORT_Free(sp);
00346        }
00347         if (ip) {
00348            fprintf(stderr, "strsclnt: issuer  DN: %s\n", ip);
00349            PORT_Free(ip);
00350        }
00351     }
00352     if (cert) {
00353        CERT_DestroyCertificate(cert);
00354        cert = NULL;
00355     }
00356     fprintf(stderr,
00357        "strsclnt: %ld cache hits; %ld cache misses, %ld cache not reusable\n",
00358        ssl3stats->hsh_sid_cache_hits, 
00359        ssl3stats->hsh_sid_cache_misses,
00360        ssl3stats->hsh_sid_cache_not_ok);
00361 
00362 }
00363 
00364 /**************************************************************************
00365 ** Begin thread management routines and data.
00366 **************************************************************************/
00367 
00368 #define MAX_THREADS 128
00369 
00370 typedef int startFn(void *a, void *b, int c);
00371 
00372 
00373 static PRInt32     numConnected;
00374 static int         max_threads;    /* peak threads allowed */
00375 
00376 typedef struct perThreadStr {
00377     void *    a;
00378     void *    b;
00379     int         tid;
00380     int         rv;
00381     startFn  *  startFunc;
00382     PRThread *  prThread;
00383     PRBool    inUse;
00384 } perThread;
00385 
00386 perThread threads[MAX_THREADS];
00387 
00388 void
00389 thread_wrapper(void * arg)
00390 {
00391     perThread * slot = (perThread *)arg;
00392     PRBool done = PR_FALSE;
00393 
00394     do {
00395         PRBool doop = PR_FALSE;
00396         PRBool dosleep = PR_FALSE;
00397         PRTime now = PR_Now();
00398 
00399         PR_Lock(threadLock);
00400         if (! (slot->tid < active_threads)) {
00401             /* this thread isn't supposed to be running */
00402             if (!ThrottleUp) {
00403                 /* we'll never need this thread again, so abort it */
00404                 done = PR_TRUE;
00405             } else if (remaining_connections > 0) {
00406                 /* we may still need this thread, so just sleep for 1s */
00407                 dosleep = PR_TRUE;
00408                 /* the conditions to trigger a throttle up are :
00409                 ** 1. last PR_Connect failure must have happened more than
00410                 **    10s ago
00411                 ** 2. last throttling up must have happened more than 0.5s ago
00412                 ** 3. there must be a more recent PR_Connect success than
00413                 **    failure
00414                 */
00415                 if ( (now - lastConnectFailure > 10 * PR_USEC_PER_SEC) &&
00416                     ( (!lastThrottleUp) || ( (now - lastThrottleUp) >=
00417                                              (PR_USEC_PER_SEC/2)) ) &&
00418                     (lastConnectSuccess > lastConnectFailure) ) {
00419                     /* try throttling up by one thread */
00420                     active_threads = PR_MIN(max_threads, active_threads+1);
00421                     fprintf(stderr,"active_threads set up to %d\n",
00422                             active_threads);
00423                     lastThrottleUp = PR_MAX(now, lastThrottleUp);
00424                 }
00425             } else {
00426                 /* no more connections left, we are done */
00427                 done = PR_TRUE;
00428             }
00429         } else {
00430             /* this thread should run */
00431             if (--remaining_connections >= 0) { /* protected by threadLock */
00432                 doop = PR_TRUE;
00433             } else {
00434                 done = PR_TRUE;
00435             }
00436         }
00437         PR_Unlock(threadLock);
00438         if (doop) {
00439             slot->rv = (* slot->startFunc)(slot->a, slot->b, slot->tid);
00440             PRINTF("strsclnt: Thread in slot %d returned %d\n", 
00441                    slot->tid, slot->rv);
00442         }
00443         if (dosleep) {
00444             PR_Sleep(PR_SecondsToInterval(1));
00445         }
00446     } while (!done && (!failed_already || ignoreErrors));
00447 }
00448 
00449 SECStatus
00450 launch_thread(
00451     startFn * startFunc,
00452     void *    a,
00453     void *    b,
00454     int         tid)
00455 {
00456     PRUint32 i;
00457     perThread * slot;
00458 
00459     PR_Lock(threadLock);
00460 
00461     PORT_Assert(numUsed < MAX_THREADS);
00462     if (! (numUsed < MAX_THREADS)) {
00463         PR_Unlock(threadLock);
00464         return SECFailure;
00465     }
00466 
00467     i = numUsed++;
00468     slot = &threads[i];
00469     slot->a = a;
00470     slot->b = b;
00471     slot->tid = tid;
00472 
00473     slot->startFunc = startFunc;
00474 
00475     slot->prThread      = PR_CreateThread(PR_USER_THREAD,
00476                                       thread_wrapper, slot,
00477                                   PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
00478                                   PR_JOINABLE_THREAD, 0);
00479     if (slot->prThread == NULL) {
00480        PR_Unlock(threadLock);
00481        printf("strsclnt: Failed to launch thread!\n");
00482        return SECFailure;
00483     } 
00484 
00485     slot->inUse   = 1;
00486     PR_Unlock(threadLock);
00487     PRINTF("strsclnt: Launched thread in slot %d \n", i);
00488 
00489     return SECSuccess;
00490 }
00491 
00492 /* join all the threads */
00493 int 
00494 reap_threads(void)
00495 {
00496     int         i;
00497 
00498     for (i = 0; i < MAX_THREADS; ++i) {
00499         if (threads[i].prThread) {
00500             PR_JoinThread(threads[i].prThread);
00501             threads[i].prThread = NULL;
00502         }
00503     }
00504     return 0;
00505 }
00506 
00507 void
00508 destroy_thread_data(void)
00509 {
00510     PORT_Memset(threads, 0, sizeof threads);
00511 
00512     if (threadLock) {
00513        PR_DestroyLock(threadLock);
00514        threadLock = NULL;
00515     }
00516 }
00517 
00518 void
00519 init_thread_data(void)
00520 {
00521     threadLock = PR_NewLock();
00522 }
00523 
00524 /**************************************************************************
00525 ** End   thread management routines.
00526 **************************************************************************/
00527 
00528 PRBool useModelSocket = PR_TRUE;
00529 
00530 static const char stopCmd[] = { "GET /stop " };
00531 static const char outHeader[] = {
00532     "HTTP/1.0 200 OK\r\n"
00533     "Server: Netscape-Enterprise/2.0a\r\n"
00534     "Date: Tue, 26 Aug 1997 22:10:05 GMT\r\n"
00535     "Content-type: text/plain\r\n"
00536     "\r\n"
00537 };
00538 
00539 struct lockedVarsStr {
00540     PRLock *  lock;
00541     int              count;
00542     int              waiters;
00543     PRCondVar *      condVar;
00544 };
00545 
00546 typedef struct lockedVarsStr lockedVars;
00547 
00548 void 
00549 lockedVars_Init( lockedVars * lv)
00550 {
00551     lv->count   = 0;
00552     lv->waiters = 0;
00553     lv->lock    = PR_NewLock();
00554     lv->condVar = PR_NewCondVar(lv->lock);
00555 }
00556 
00557 void
00558 lockedVars_Destroy( lockedVars * lv)
00559 {
00560     PR_DestroyCondVar(lv->condVar);
00561     lv->condVar = NULL;
00562 
00563     PR_DestroyLock(lv->lock);
00564     lv->lock = NULL;
00565 }
00566 
00567 void
00568 lockedVars_WaitForDone(lockedVars * lv)
00569 {
00570     PR_Lock(lv->lock);
00571     while (lv->count > 0) {
00572        PR_WaitCondVar(lv->condVar, PR_INTERVAL_NO_TIMEOUT);
00573     }
00574     PR_Unlock(lv->lock);
00575 }
00576 
00577 int    /* returns count */
00578 lockedVars_AddToCount(lockedVars * lv, int addend)
00579 {
00580     int rv;
00581 
00582     PR_Lock(lv->lock);
00583     rv = lv->count += addend;
00584     if (rv <= 0) {
00585        PR_NotifyCondVar(lv->condVar);
00586     }
00587     PR_Unlock(lv->lock);
00588     return rv;
00589 }
00590 
00591 int
00592 do_writes(
00593     void *       a,
00594     void *       b,
00595     int          c)
00596 {
00597     PRFileDesc *     ssl_sock      = (PRFileDesc *)a;
00598     lockedVars *     lv            = (lockedVars *)b;
00599     int                     sent          = 0;
00600     int              count         = 0;
00601 
00602     while (sent < bigBuf.len) {
00603 
00604        count = PR_Send(ssl_sock, bigBuf.data + sent, bigBuf.len - sent, 
00605                        0, maxInterval);
00606        if (count < 0) {
00607            errWarn("PR_Send bigBuf");
00608            break;
00609        }
00610        FPRINTF(stderr, "strsclnt: PR_Send wrote %d bytes from bigBuf\n", 
00611               count );
00612        sent += count;
00613     }
00614     if (count >= 0) {       /* last write didn't fail. */
00615        PR_Shutdown(ssl_sock, PR_SHUTDOWN_SEND);
00616     }
00617 
00618     /* notify the reader that we're done. */
00619     lockedVars_AddToCount(lv, -1);
00620     return (sent < bigBuf.len) ? SECFailure : SECSuccess;
00621 }
00622 
00623 int 
00624 handle_fdx_connection( PRFileDesc * ssl_sock, int connection)
00625 {
00626     SECStatus          result;
00627     int                firstTime = 1;
00628     int                countRead = 0;
00629     lockedVars         lv;
00630     char               *buf;
00631 
00632 
00633     lockedVars_Init(&lv);
00634     lockedVars_AddToCount(&lv, 1);
00635 
00636     /* Attempt to launch the writer thread. */
00637     result = launch_thread(do_writes, ssl_sock, &lv, connection);
00638 
00639     if (result != SECSuccess) 
00640        goto cleanup;
00641 
00642     buf = PR_Malloc(RD_BUF_SIZE);
00643 
00644     if (buf) {
00645        do {
00646            /* do reads here. */
00647            PRInt32 count;
00648 
00649            count = PR_Recv(ssl_sock, buf, RD_BUF_SIZE, 0, maxInterval);
00650            if (count < 0) {
00651               errWarn("PR_Recv");
00652               break;
00653            }
00654            countRead += count;
00655            FPRINTF(stderr, 
00656                   "strsclnt: connection %d read %d bytes (%d total).\n", 
00657                   connection, count, countRead );
00658            if (firstTime) {
00659               firstTime = 0;
00660               printSecurityInfo(ssl_sock);
00661            }
00662        } while (lockedVars_AddToCount(&lv, 0) > 0);
00663        PR_Free(buf);
00664        buf = 0;
00665     }
00666 
00667     /* Wait for writer to finish */
00668     lockedVars_WaitForDone(&lv);
00669     lockedVars_Destroy(&lv);
00670 
00671     FPRINTF(stderr, 
00672     "strsclnt: connection %d read %d bytes total. -----------------------\n", 
00673            connection, countRead);
00674 
00675 cleanup:
00676     /* Caller closes the socket. */
00677 
00678     return SECSuccess;
00679 }
00680 
00681 const char request[] = {"GET /abc HTTP/1.0\r\n\r\n" };
00682 
00683 SECStatus
00684 handle_connection( PRFileDesc *ssl_sock, int tid)
00685 {
00686     int           countRead = 0;
00687     PRInt32 rv;
00688     char    *buf;
00689 
00690     buf = PR_Malloc(RD_BUF_SIZE);
00691     if (!buf)
00692        return SECFailure;
00693 
00694     /* compose the http request here. */
00695 
00696     rv = PR_Send(ssl_sock, request, strlen(request), 0, maxInterval);
00697     if (rv <= 0) {
00698        errWarn("PR_Send");
00699        PR_Free(buf);
00700        buf = 0;
00701         failed_already = 1;
00702        return SECFailure;
00703     }
00704     printSecurityInfo(ssl_sock);
00705 
00706     /* read until EOF */
00707     while (1) {
00708        rv = PR_Recv(ssl_sock, buf, RD_BUF_SIZE, 0, maxInterval);
00709        if (rv == 0) {
00710            break;    /* EOF */
00711        }
00712        if (rv < 0) {
00713            errWarn("PR_Recv");
00714            failed_already = 1;
00715            break;
00716        }
00717 
00718        countRead += rv;
00719        FPRINTF(stderr,
00720                 "strsclnt: connection on thread %d read %d bytes (%d total).\n",
00721               tid, rv, countRead );
00722     }
00723     PR_Free(buf);
00724     buf = 0;
00725 
00726     /* Caller closes the socket. */
00727 
00728     FPRINTF(stderr, 
00729     "strsclnt: connection on thread %d read %d bytes total. ---------\n", 
00730            tid, countRead);
00731 
00732     return SECSuccess;      /* success */
00733 }
00734 
00735 #define USE_SOCK_PEER_ID 1
00736 
00737 #ifdef USE_SOCK_PEER_ID
00738 
00739 PRInt32 lastFullHandshakePeerID;
00740 
00741 SECStatus 
00742 myHandshakeCallback(PRFileDesc *socket, void *arg) 
00743 {
00744     PR_AtomicSet(&lastFullHandshakePeerID, (PRInt32) arg);
00745     return SECSuccess;
00746 }
00747 
00748 #endif
00749 
00750 /* one copy of this function is launched in a separate thread for each
00751 ** connection to be made.
00752 */
00753 int
00754 do_connects(
00755     void *    a,
00756     void *    b,
00757     int         tid)
00758 {
00759     PRNetAddr  *        addr              = (PRNetAddr *)  a;
00760     PRFileDesc *        model_sock = (PRFileDesc *) b;
00761     PRFileDesc *        ssl_sock   = 0;
00762     PRFileDesc *        tcp_sock   = 0;
00763     PRStatus          prStatus;
00764     PRUint32            sleepInterval     = 50; /* milliseconds */
00765     SECStatus        result;
00766     int                 rv         = SECSuccess;
00767     PRSocketOptionData  opt;
00768 
00769 retry:
00770 
00771     tcp_sock = PR_OpenTCPSocket(addr->raw.family);
00772     if (tcp_sock == NULL) {
00773        errExit("PR_OpenTCPSocket");
00774     }
00775 
00776     opt.option             = PR_SockOpt_Nonblocking;
00777     opt.value.non_blocking = PR_FALSE;
00778     prStatus = PR_SetSocketOption(tcp_sock, &opt);
00779     if (prStatus != PR_SUCCESS) {
00780        errWarn("PR_SetSocketOption(PR_SockOpt_Nonblocking, PR_FALSE)");
00781        PR_Close(tcp_sock);
00782        return SECSuccess;
00783     } 
00784 
00785     if (NoDelay) {
00786        opt.option         = PR_SockOpt_NoDelay;
00787        opt.value.no_delay = PR_TRUE;
00788        prStatus = PR_SetSocketOption(tcp_sock, &opt);
00789        if (prStatus != PR_SUCCESS) {
00790            errWarn("PR_SetSocketOption(PR_SockOpt_NoDelay, PR_TRUE)");
00791            PR_Close(tcp_sock);
00792            return SECSuccess;
00793        } 
00794     }
00795 
00796     prStatus = PR_Connect(tcp_sock, addr, PR_INTERVAL_NO_TIMEOUT);
00797     if (prStatus != PR_SUCCESS) {
00798         PRErrorCode err = PR_GetError(); /* save error code */
00799         if (ThrottleUp) {
00800             PRTime now = PR_Now();
00801             PR_Lock(threadLock);
00802             lastConnectFailure = PR_MAX(now, lastConnectFailure);
00803             PR_Unlock(threadLock);
00804         }
00805         if ((err == PR_CONNECT_REFUSED_ERROR) || 
00806            (err == PR_CONNECT_RESET_ERROR)      ) {
00807            int connections = numConnected;
00808 
00809            PR_Close(tcp_sock);
00810             PR_Lock(threadLock);
00811             if (connections > 2 && active_threads >= connections) {
00812                 active_threads = connections - 1;
00813                 fprintf(stderr,"active_threads set down to %d\n",
00814                         active_threads);
00815             }
00816             PR_Unlock(threadLock);
00817 
00818             if (QuitOnTimeout && sleepInterval > 40000) {
00819                 fprintf(stderr,
00820                    "strsclnt: Client timed out waiting for connection to server.\n");
00821                 exit(1);
00822             }
00823            PR_Sleep(PR_MillisecondsToInterval(sleepInterval));
00824            sleepInterval <<= 1;
00825            goto retry;
00826        }
00827        errWarn("PR_Connect");
00828        rv = SECFailure;
00829        goto done;
00830     } else {
00831         if (ThrottleUp) {
00832             PRTime now = PR_Now();
00833             PR_Lock(threadLock);
00834             lastConnectSuccess = PR_MAX(now, lastConnectSuccess);
00835             PR_Unlock(threadLock);
00836         }
00837     }
00838 
00839     ssl_sock = SSL_ImportFD(model_sock, tcp_sock);
00840     /* XXX if this import fails, close tcp_sock and return. */
00841     if (!ssl_sock) {
00842        PR_Close(tcp_sock);
00843        return SECSuccess;
00844     }
00845     if (fullhs != NO_FULLHS_PERCENTAGE) {
00846 #ifdef USE_SOCK_PEER_ID
00847         char sockPeerIDString[512];
00848         static PRInt32 sockPeerID = 0; /* atomically incremented */
00849         PRInt32 thisPeerID;
00850 #endif
00851         PRInt32 savid = PR_AtomicIncrement(&globalconid);
00852         PRInt32 conid = 1 + (savid - 1) % 100;
00853         /* don't change peer ID on the very first handshake, which is always
00854            a full, so the session gets stored into the client cache */
00855         if ( (savid != 1) &&
00856             ( ( (savid <= total_connections_rounded_down_to_hundreds) &&
00857                 (conid <= fullhs) ) ||
00858               (conid*100 <= total_connections_modulo_100*fullhs ) ) ) {
00859 #ifdef USE_SOCK_PEER_ID
00860             /* force a full handshake by changing the socket peer ID */
00861             thisPeerID = PR_AtomicIncrement(&sockPeerID);
00862         } else {
00863             /* reuse previous sockPeerID for restart handhsake */
00864             thisPeerID = lastFullHandshakePeerID;
00865         }
00866         PR_snprintf(sockPeerIDString, sizeof(sockPeerIDString), "ID%d",
00867                     thisPeerID);
00868         SSL_SetSockPeerID(ssl_sock, sockPeerIDString);
00869         SSL_HandshakeCallback(ssl_sock, myHandshakeCallback, (void*)thisPeerID);
00870 #else
00871             /* force a full handshake by setting the no cache option */
00872             SSL_OptionSet(ssl_sock, SSL_NO_CACHE, 1);
00873         }
00874 #endif
00875     }
00876     rv = SSL_ResetHandshake(ssl_sock, /* asServer */ 0);
00877     if (rv != SECSuccess) {
00878        errWarn("SSL_ResetHandshake");
00879        goto done;
00880     }
00881 
00882     PR_AtomicIncrement(&numConnected);
00883 
00884     if (bigBuf.data != NULL) {
00885        result = handle_fdx_connection( ssl_sock, tid);
00886     } else {
00887        result = handle_connection( ssl_sock, tid);
00888     }
00889 
00890     PR_AtomicDecrement(&numConnected);
00891 
00892 done:
00893     if (ssl_sock) {
00894        PR_Close(ssl_sock);
00895     } else if (tcp_sock) {
00896        PR_Close(tcp_sock);
00897     }
00898     return SECSuccess;
00899 }
00900 
00901 
00902 typedef struct {
00903     PRLock* lock;
00904     char* nickname;
00905     CERTCertificate* cert;
00906     SECKEYPrivateKey* key;
00907     char* password;
00908 } cert_and_key;
00909 
00910 PRBool FindCertAndKey(cert_and_key* Cert_And_Key)
00911 {
00912     if ( (NULL == Cert_And_Key->nickname) || (0 == strcmp(Cert_And_Key->nickname,"none"))) {
00913         return PR_TRUE;
00914     }
00915     Cert_And_Key->cert = CERT_FindUserCertByUsage(CERT_GetDefaultCertDB(),
00916                             Cert_And_Key->nickname, certUsageSSLClient,
00917                             PR_FALSE, Cert_And_Key->password);
00918     if (Cert_And_Key->cert) {
00919         Cert_And_Key->key = PK11_FindKeyByAnyCert(Cert_And_Key->cert, Cert_And_Key->password);
00920     }
00921     if (Cert_And_Key->cert && Cert_And_Key->key) {
00922         return PR_TRUE;
00923     } else {
00924         return PR_FALSE;
00925     }
00926 }
00927 
00928 PRBool LoggedIn(CERTCertificate* cert, SECKEYPrivateKey* key)
00929 {
00930     if ( (cert->slot) && (key->pkcs11Slot) &&
00931          (PR_TRUE == PK11_IsLoggedIn(cert->slot, NULL)) &&
00932          (PR_TRUE == PK11_IsLoggedIn(key->pkcs11Slot, NULL)) ) {
00933         return PR_TRUE;
00934     }
00935  
00936     return PR_FALSE;
00937 }
00938 
00939 SECStatus 
00940 StressClient_GetClientAuthData(void * arg,
00941                       PRFileDesc * socket,
00942                     struct CERTDistNamesStr * caNames,
00943                     struct CERTCertificateStr ** pRetCert,
00944                     struct SECKEYPrivateKeyStr **pRetKey)
00945 {
00946     cert_and_key* Cert_And_Key = (cert_and_key*) arg;
00947 
00948     if (!pRetCert || !pRetKey) {
00949         /* bad pointers, can't return a cert or key */
00950         return SECFailure;
00951     }
00952 
00953     *pRetCert = NULL;
00954     *pRetKey = NULL;
00955 
00956     if (Cert_And_Key && Cert_And_Key->nickname) {
00957         while (PR_TRUE) {
00958             if (Cert_And_Key && Cert_And_Key->lock) {
00959                 int timeout = 0;
00960                 PR_Lock(Cert_And_Key->lock);
00961 
00962                 if (Cert_And_Key->cert) {
00963                     *pRetCert = CERT_DupCertificate(Cert_And_Key->cert);
00964                 }
00965 
00966                 if (Cert_And_Key->key) {
00967                     *pRetKey = SECKEY_CopyPrivateKey(Cert_And_Key->key);
00968                 }
00969                 PR_Unlock(Cert_And_Key->lock);
00970                 if (!*pRetCert || !*pRetKey) {
00971                     /* one or both of them failed to copy. Either the source was NULL, or there was
00972                     ** an out of memory condition. Free any allocated copy and fail */
00973                     if (*pRetCert) {
00974                         CERT_DestroyCertificate(*pRetCert);
00975                         *pRetCert = NULL;
00976                     }
00977                     if (*pRetKey) {
00978                         SECKEY_DestroyPrivateKey(*pRetKey);
00979                         *pRetKey = NULL;
00980                     }
00981                     break;
00982                 }
00983                 /* now check if those objects are valid */
00984                 if ( PR_FALSE == LoggedIn(*pRetCert, *pRetKey) ) {
00985                     /* token is no longer logged in, it was removed */
00986 
00987                     /* first, delete and clear our invalid local objects */
00988                     CERT_DestroyCertificate(*pRetCert);
00989                     SECKEY_DestroyPrivateKey(*pRetKey);
00990                     *pRetCert = NULL;
00991                     *pRetKey = NULL;
00992 
00993                     PR_Lock(Cert_And_Key->lock);
00994                     /* check if another thread already logged back in */
00995                     if (PR_TRUE == LoggedIn(Cert_And_Key->cert, Cert_And_Key->key)) {
00996                         /* yes : try again */
00997                         PR_Unlock(Cert_And_Key->lock);
00998                         continue;
00999                     }
01000                     /* this is the thread to retry */
01001                     CERT_DestroyCertificate(Cert_And_Key->cert);
01002                     SECKEY_DestroyPrivateKey(Cert_And_Key->key);
01003                     Cert_And_Key->cert = NULL;
01004                     Cert_And_Key->key = NULL;
01005 
01006 
01007                     /* now look up the cert and key again */
01008                     while (PR_FALSE == FindCertAndKey(Cert_And_Key) ) {
01009                         PR_Sleep(PR_SecondsToInterval(1));
01010                         timeout++;
01011                         if (timeout>=60) {
01012                             printf("\nToken pulled and not reinserted early enough : aborting.\n");
01013                             exit(1);
01014                         }
01015                     }
01016                     PR_Unlock(Cert_And_Key->lock);
01017                     continue;
01018                     /* try again to reduce code size */
01019                 }
01020                 return SECSuccess;
01021             }
01022         }
01023         *pRetCert = NULL;
01024         *pRetKey = NULL;
01025         return SECFailure;
01026     } else {
01027         /* no cert configured, automatically find the right cert. */
01028         CERTCertificate *  cert = NULL;
01029         SECKEYPrivateKey * privkey = NULL;
01030         CERTCertNicknames * names;
01031         int                 i;
01032         void *             proto_win = NULL;
01033         SECStatus          rv         = SECFailure;
01034 
01035         if (Cert_And_Key) {
01036             proto_win = Cert_And_Key->password;
01037         }
01038 
01039         names = CERT_GetCertNicknames(CERT_GetDefaultCertDB(),
01040                                       SEC_CERT_NICKNAMES_USER, proto_win);
01041         if (names != NULL) {
01042             for (i = 0; i < names->numnicknames; i++) {
01043                 cert = CERT_FindUserCertByUsage(CERT_GetDefaultCertDB(),
01044                             names->nicknames[i], certUsageSSLClient,
01045                             PR_FALSE, proto_win);       
01046                 if ( !cert )
01047                     continue;
01048                 /* Only check unexpired certs */
01049                 if (CERT_CheckCertValidTimes(cert, PR_Now(), PR_TRUE) != 
01050                                              secCertTimeValid ) {
01051                     CERT_DestroyCertificate(cert);
01052                     continue;
01053                 }
01054                 rv = NSS_CmpCertChainWCANames(cert, caNames);
01055                 if ( rv == SECSuccess ) {
01056                     privkey = PK11_FindKeyByAnyCert(cert, proto_win);
01057                     if ( privkey )
01058                         break;
01059                 }
01060                 rv = SECFailure;
01061                 CERT_DestroyCertificate(cert);
01062             }
01063             CERT_FreeNicknames(names);
01064         }
01065         if (rv == SECSuccess) {
01066             *pRetCert = cert;
01067             *pRetKey  = privkey;
01068         }
01069         return rv;
01070     }
01071 }
01072 
01073 int 
01074 hexchar_to_int(int c) 
01075 {
01076     if (((c) >= '0') && ((c) <= '9'))
01077        return (c) - '0'; 
01078     if (((c) >= 'a') && ((c) <= 'f'))
01079        return (c) - 'a' + 10;
01080     if (((c) >= 'A') && ((c) <= 'F'))
01081        return (c) - 'A' + 10; 
01082     failed_already = 1;
01083     return -1;
01084 }
01085 
01086 void
01087 client_main(
01088     unsigned short      port, 
01089     int                 connections,
01090     cert_and_key* Cert_And_Key,
01091     const char *     hostName)
01092 {
01093     PRFileDesc *model_sock  = NULL;
01094     int         i;
01095     int         rv;
01096     PRStatus    status;
01097     PRNetAddr   addr;
01098 
01099     status = PR_StringToNetAddr(hostName, &addr);
01100     if (status == PR_SUCCESS) {
01101        addr.inet.port = PR_htons(port);
01102     } else {
01103        /* Lookup host */
01104        PRAddrInfo *addrInfo;
01105        void       *enumPtr   = NULL;
01106 
01107        addrInfo = PR_GetAddrInfoByName(hostName, PR_AF_UNSPEC, 
01108                                        PR_AI_ADDRCONFIG | PR_AI_NOCANONNAME);
01109        if (!addrInfo) {
01110            SECU_PrintError(progName, "error looking up host");
01111            return;
01112        }
01113        do {
01114            enumPtr = PR_EnumerateAddrInfo(enumPtr, addrInfo, port, &addr);
01115        } while (enumPtr != NULL &&
01116                addr.raw.family != PR_AF_INET &&
01117                addr.raw.family != PR_AF_INET6);
01118        PR_FreeAddrInfo(addrInfo);
01119        if (enumPtr == NULL) {
01120            SECU_PrintError(progName, "error looking up host address");
01121            return;
01122        }
01123     }
01124 
01125     /* all suites except RSA_NULL_MD5 are enabled by Domestic Policy */
01126     NSS_SetDomesticPolicy();
01127 
01128     /* all the SSL2 and SSL3 cipher suites are enabled by default. */
01129     if (cipherString) {
01130         int ndx;
01131 
01132         /* disable all the ciphers, then enable the ones we want. */
01133         disableAllSSLCiphers();
01134 
01135         while (0 != (ndx = *cipherString)) {
01136            const char * startCipher = cipherString++;
01137             int  cipher = 0;
01138            SECStatus rv;
01139 
01140            if (ndx == ':') {
01141               cipher  = hexchar_to_int(*cipherString++);
01142               cipher <<= 4;
01143               cipher |= hexchar_to_int(*cipherString++);
01144               cipher <<= 4;
01145               cipher |= hexchar_to_int(*cipherString++);
01146               cipher <<= 4;
01147               cipher |= hexchar_to_int(*cipherString++);
01148               if (cipher <= 0) {
01149                   fprintf(stderr, "strsclnt: Invalid cipher value: %-5.5s\n",
01150                                   startCipher);
01151                   failed_already = 1;
01152                   return;
01153               }
01154            } else {
01155               if (isalpha(ndx)) {
01156                   const int *cptr;
01157 
01158                   cptr = islower(ndx) ? ssl3CipherSuites : ssl2CipherSuites;
01159                   for (ndx &= 0x1f; (cipher = *cptr++) != 0 && --ndx > 0; ) 
01160                      /* do nothing */;
01161               }
01162               if (cipher <= 0) {
01163                   fprintf(stderr, "strsclnt: Invalid cipher letter: %c\n", 
01164                                   *startCipher);
01165                   failed_already = 1;
01166                   return;
01167               }
01168            }
01169            rv = SSL_CipherPrefSetDefault(cipher, PR_TRUE);
01170            if (rv != SECSuccess) {
01171               fprintf(stderr, 
01172                      "strsclnt: SSL_CipherPrefSetDefault(0x%04x) failed\n",
01173                      cipher);
01174               failed_already = 1;
01175               return;
01176            }
01177         }
01178     }
01179 
01180     /* configure model SSL socket. */
01181 
01182     model_sock = PR_OpenTCPSocket(addr.raw.family);
01183     if (model_sock == NULL) {
01184        errExit("PR_OpenTCPSocket for 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 *               tmp         = NULL;
01329     char *            passwd      = NULL;
01330     int                  connections = 1;
01331     int                  exitVal;
01332     int                  tmpInt;
01333     unsigned short       port        = 443;
01334     SECStatus            rv;
01335     PLOptState *         optstate;
01336     PLOptStatus          status;
01337     cert_and_key Cert_And_Key;
01338 
01339     /* Call the NSPR initialization routines */
01340     PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
01341 
01342     tmp      = strrchr(argv[0], '/');
01343     tmp      = tmp ? tmp + 1 : argv[0];
01344     progName = strrchr(tmp, '\\');
01345     progName = progName ? progName + 1 : tmp;
01346  
01347 
01348     optstate = PL_CreateOptState(argc, argv, "23BC:DNP:TUc:d:f:in:op:qst:vw:");
01349     while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
01350        switch(optstate->option) {
01351 
01352        case '2': disableSSL2 = PR_TRUE; break;
01353 
01354        case '3': disableSSL3 = PR_TRUE; break;
01355 
01356        case 'B': bypassPKCS11 = PR_TRUE; break;
01357 
01358        case 'C': cipherString = optstate->value; break;
01359 
01360        case 'D': NoDelay = PR_TRUE; break;
01361 
01362        case 'N': NoReuse = 1; break;
01363         
01364        case 'P': fullhs = PORT_Atoi(optstate->value); break;
01365 
01366        case 'T': disableTLS = PR_TRUE; break;
01367             
01368        case 'U': ThrottleUp = PR_TRUE; break;
01369 
01370        case 'c': connections = PORT_Atoi(optstate->value); break;
01371 
01372        case 'd': dir = optstate->value; break;
01373 
01374        case 'f': fileName = optstate->value; break;
01375 
01376        case 'i': ignoreErrors = PR_TRUE; break;
01377 
01378         case 'n': nickName = PL_strdup(optstate->value); break;
01379 
01380        case 'o': MakeCertOK++; break;
01381 
01382        case 'p': port = PORT_Atoi(optstate->value); break;
01383 
01384        case 'q': QuitOnTimeout = PR_TRUE; break;
01385 
01386        case 's': disableLocking = PR_TRUE; break;
01387 
01388        case 't':
01389            tmpInt = PORT_Atoi(optstate->value);
01390            if (tmpInt > 0 && tmpInt < MAX_THREADS) 
01391                max_threads = active_threads = tmpInt;
01392            break;
01393 
01394         case 'v': verbose++; break;
01395 
01396        case 'w': passwd = PL_strdup(optstate->value); break;
01397 
01398        case 0:   /* positional parameter */
01399            if (hostName) {
01400               Usage(progName);
01401            }
01402            hostName = PL_strdup(optstate->value);
01403            break;
01404 
01405        default:
01406        case '?':
01407            Usage(progName);
01408            break;
01409 
01410        }
01411     }
01412     PL_DestroyOptState(optstate);
01413 
01414     if (!hostName || status == PL_OPT_BAD)
01415        Usage(progName);
01416 
01417     if (fullhs!= NO_FULLHS_PERCENTAGE && (fullhs < 0 || fullhs>100 || NoReuse) )
01418         Usage(progName);
01419 
01420     if (port == 0)
01421        Usage(progName);
01422 
01423     if (fileName)
01424        readBigFile(fileName);
01425 
01426     /* set our password function */
01427     if ( passwd ) {
01428        PK11_SetPasswordFunc(ownPasswd);
01429     } else {
01430        PK11_SetPasswordFunc(SECU_GetModulePassword);
01431     }
01432 
01433     tmp = PR_GetEnv("NSS_DEBUG_TIMEOUT");
01434     if (tmp && tmp[0]) {
01435         int sec = PORT_Atoi(tmp);
01436        if (sec > 0) {
01437            maxInterval = PR_SecondsToInterval(sec);
01438        }
01439     }
01440 
01441     /* Call the libsec initialization routines */
01442     rv = NSS_Initialize(dir, "", "", SECMOD_DB, NSS_INIT_READONLY);
01443     if (rv != SECSuccess) {
01444        fputs("NSS_Init failed.\n", stderr);
01445        exit(1);
01446     }
01447     ssl3stats = SSL_GetStatistics();
01448     Cert_And_Key.lock = PR_NewLock();
01449     Cert_And_Key.nickname = nickName;
01450     Cert_And_Key.password = passwd;
01451     Cert_And_Key.cert = NULL;
01452     Cert_And_Key.key = NULL;
01453 
01454     if (PR_FALSE == FindCertAndKey(&Cert_And_Key)) {
01455 
01456        if (Cert_And_Key.cert == NULL) {
01457            fprintf(stderr, "strsclnt: Can't find certificate %s\n", Cert_And_Key.nickname);
01458            exit(1);
01459        }
01460 
01461        if (Cert_And_Key.key == NULL) {
01462            fprintf(stderr, "strsclnt: Can't find Private Key for cert %s\n", 
01463                   Cert_And_Key.nickname);
01464            exit(1);
01465        }
01466 
01467     }
01468 
01469     client_main(port, connections, &Cert_And_Key, hostName);
01470 
01471     /* clean up */
01472     if (Cert_And_Key.cert) {
01473        CERT_DestroyCertificate(Cert_And_Key.cert);
01474     }
01475     if (Cert_And_Key.key) {
01476        SECKEY_DestroyPrivateKey(Cert_And_Key.key);
01477     }
01478 
01479     PR_DestroyLock(Cert_And_Key.lock);
01480 
01481     if (Cert_And_Key.password) {
01482         PL_strfree(Cert_And_Key.password);
01483     }
01484     if (Cert_And_Key.nickname) {
01485         PL_strfree(Cert_And_Key.nickname);
01486     }
01487 
01488     PL_strfree(hostName);
01489 
01490     /* some final stats. */
01491     if (ssl3stats->hsh_sid_cache_hits + ssl3stats->hsh_sid_cache_misses +
01492         ssl3stats->hsh_sid_cache_not_ok == 0) {
01493        /* presumably we were testing SSL2. */
01494        printf("strsclnt: SSL2 - %d server certificates tested.\n",
01495                certsTested);
01496     } else {
01497        printf(
01498        "strsclnt: %ld cache hits; %ld cache misses, %ld cache not reusable\n",
01499            ssl3stats->hsh_sid_cache_hits, 
01500            ssl3stats->hsh_sid_cache_misses,
01501            ssl3stats->hsh_sid_cache_not_ok);
01502     }
01503 
01504     if (!NoReuse)
01505        exitVal = (ssl3stats->hsh_sid_cache_misses > 1) ||
01506                 (ssl3stats->hsh_sid_cache_not_ok != 0) ||
01507                 (certsTested > 1);
01508     else {
01509        printf("strsclnt: NoReuse - %d server certificates tested.\n",
01510                certsTested);
01511         if (ssl3stats->hsh_sid_cache_hits + ssl3stats->hsh_sid_cache_misses +
01512             ssl3stats->hsh_sid_cache_not_ok > 0) {
01513             exitVal = (ssl3stats->hsh_sid_cache_misses != connections) ||
01514                 (certsTested != connections);
01515         } else {                /* ssl2 connections */
01516             exitVal = (certsTested != connections);
01517         }
01518     }
01519 
01520     exitVal = ( exitVal || failed_already );
01521     SSL_ClearSessionCache();
01522     if (NSS_Shutdown() != SECSuccess) {
01523         printf("strsclnt: NSS_Shutdown() failed.\n");
01524         exit(1);
01525     }
01526 
01527     PR_Cleanup();
01528     return exitVal;
01529 }
01530