s_time.c revision 331638
1/* apps/s_time.c */
2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3 * All rights reserved.
4 *
5 * This package is an SSL implementation written
6 * by Eric Young (eay@cryptsoft.com).
7 * The implementation was written so as to conform with Netscapes SSL.
8 *
9 * This library is free for commercial and non-commercial use as long as
10 * the following conditions are aheared to.  The following conditions
11 * apply to all code found in this distribution, be it the RC4, RSA,
12 * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
13 * included with this distribution is covered by the same copyright terms
14 * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15 *
16 * Copyright remains Eric Young's, and as such any Copyright notices in
17 * the code are not to be removed.
18 * If this package is used in a product, Eric Young should be given attribution
19 * as the author of the parts of the library used.
20 * This can be in the form of a textual message at program startup or
21 * in documentation (online or textual) provided with the package.
22 *
23 * Redistribution and use in source and binary forms, with or without
24 * modification, are permitted provided that the following conditions
25 * are met:
26 * 1. Redistributions of source code must retain the copyright
27 *    notice, this list of conditions and the following disclaimer.
28 * 2. Redistributions in binary form must reproduce the above copyright
29 *    notice, this list of conditions and the following disclaimer in the
30 *    documentation and/or other materials provided with the distribution.
31 * 3. All advertising materials mentioning features or use of this software
32 *    must display the following acknowledgement:
33 *    "This product includes cryptographic software written by
34 *     Eric Young (eay@cryptsoft.com)"
35 *    The word 'cryptographic' can be left out if the rouines from the library
36 *    being used are not cryptographic related :-).
37 * 4. If you include any Windows specific code (or a derivative thereof) from
38 *    the apps directory (application code) you must include an acknowledgement:
39 *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40 *
41 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
45 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51 * SUCH DAMAGE.
52 *
53 * The licence and distribution terms for any publically available version or
54 * derivative of this code cannot be changed.  i.e. this code cannot simply be
55 * copied and put under another distribution licence
56 * [including the GNU Public Licence.]
57 */
58
59#define NO_SHUTDOWN
60
61/* ----------------------------------------
62   s_time - SSL client connection timer program
63   Written and donated by Larry Streepy <streepy@healthcare.com>
64  -----------------------------------------*/
65
66#include <stdio.h>
67#include <stdlib.h>
68#include <string.h>
69
70#define USE_SOCKETS
71#include "apps.h"
72#ifdef OPENSSL_NO_STDIO
73# define APPS_WIN16
74#endif
75#include <openssl/x509.h>
76#include <openssl/ssl.h>
77#include <openssl/pem.h>
78#include "s_apps.h"
79#include <openssl/err.h>
80#ifdef WIN32_STUFF
81# include "winmain.h"
82# include "wintext.h"
83#endif
84#if !defined(OPENSSL_SYS_MSDOS)
85# include OPENSSL_UNISTD
86#endif
87
88#undef PROG
89#define PROG s_time_main
90
91#undef ioctl
92#define ioctl ioctlsocket
93
94#define SSL_CONNECT_NAME        "localhost:4433"
95
96/* no default cert. */
97/*
98 * #define TEST_CERT "client.pem"
99 */
100
101#undef BUFSIZZ
102#define BUFSIZZ 1024*10
103
104#define MYBUFSIZ 1024*8
105
106#undef min
107#undef max
108#define min(a,b) (((a) < (b)) ? (a) : (b))
109#define max(a,b) (((a) > (b)) ? (a) : (b))
110
111#undef SECONDS
112#define SECONDS 30
113extern int verify_depth;
114extern int verify_error;
115
116static void s_time_usage(void);
117static int parseArgs(int argc, char **argv);
118static SSL *doConnection(SSL *scon);
119static void s_time_init(void);
120
121/***********************************************************************
122 * Static data declarations
123 */
124
125/* static char *port=PORT_STR;*/
126static char *host = SSL_CONNECT_NAME;
127static char *t_cert_file = NULL;
128static char *t_key_file = NULL;
129static char *CApath = NULL;
130static char *CAfile = NULL;
131static char *tm_cipher = NULL;
132static int tm_verify = SSL_VERIFY_NONE;
133static int maxTime = SECONDS;
134static SSL_CTX *tm_ctx = NULL;
135static const SSL_METHOD *s_time_meth = NULL;
136static char *s_www_path = NULL;
137static long bytes_read = 0;
138static int st_bugs = 0;
139static int perform = 0;
140#ifdef FIONBIO
141static int t_nbio = 0;
142#endif
143#ifdef OPENSSL_SYS_WIN32
144static int exitNow = 0;         /* Set when it's time to exit main */
145#endif
146
147static void s_time_init(void)
148{
149    host = SSL_CONNECT_NAME;
150    t_cert_file = NULL;
151    t_key_file = NULL;
152    CApath = NULL;
153    CAfile = NULL;
154    tm_cipher = NULL;
155    tm_verify = SSL_VERIFY_NONE;
156    maxTime = SECONDS;
157    tm_ctx = NULL;
158    s_time_meth = NULL;
159    s_www_path = NULL;
160    bytes_read = 0;
161    st_bugs = 0;
162    perform = 0;
163
164#ifdef FIONBIO
165    t_nbio = 0;
166#endif
167#ifdef OPENSSL_SYS_WIN32
168    exitNow = 0;                /* Set when it's time to exit main */
169#endif
170}
171
172/***********************************************************************
173 * usage - display usage message
174 */
175static void s_time_usage(void)
176{
177    static char umsg[] = "\
178-time arg     - max number of seconds to collect data, default %d\n\
179-verify arg   - turn on peer certificate verification, arg == depth\n\
180-cert arg     - certificate file to use, PEM format assumed\n\
181-key arg      - RSA file to use, PEM format assumed, key is in cert file\n\
182                file if not specified by this option\n\
183-CApath arg   - PEM format directory of CA's\n\
184-CAfile arg   - PEM format file of CA's\n\
185-cipher       - preferred cipher to use, play with 'openssl ciphers'\n\n";
186
187    printf("usage: s_time <args>\n\n");
188
189    printf("-connect host:port - host:port to connect to (default is %s)\n",
190           SSL_CONNECT_NAME);
191#ifdef FIONBIO
192    printf("-nbio         - Run with non-blocking IO\n");
193    printf("-ssl2         - Just use SSLv2\n");
194    printf("-ssl3         - Just use SSLv3\n");
195    printf("-bugs         - Turn on SSL bug compatibility\n");
196    printf("-new          - Just time new connections\n");
197    printf("-reuse        - Just time connection reuse\n");
198    printf("-www page     - Retrieve 'page' from the site\n");
199#endif
200    printf(umsg, SECONDS);
201}
202
203/***********************************************************************
204 * parseArgs - Parse command line arguments and initialize data
205 *
206 * Returns 0 if ok, -1 on bad args
207 */
208static int parseArgs(int argc, char **argv)
209{
210    int badop = 0;
211
212    verify_depth = 0;
213    verify_error = X509_V_OK;
214
215    argc--;
216    argv++;
217
218    while (argc >= 1) {
219        if (strcmp(*argv, "-connect") == 0) {
220            if (--argc < 1)
221                goto bad;
222            host = *(++argv);
223        }
224#if 0
225        else if (strcmp(*argv, "-host") == 0) {
226            if (--argc < 1)
227                goto bad;
228            host = *(++argv);
229        } else if (strcmp(*argv, "-port") == 0) {
230            if (--argc < 1)
231                goto bad;
232            port = *(++argv);
233        }
234#endif
235        else if (strcmp(*argv, "-reuse") == 0)
236            perform = 2;
237        else if (strcmp(*argv, "-new") == 0)
238            perform = 1;
239        else if (strcmp(*argv, "-verify") == 0) {
240
241            tm_verify = SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE;
242            if (--argc < 1)
243                goto bad;
244            verify_depth = atoi(*(++argv));
245            BIO_printf(bio_err, "verify depth is %d\n", verify_depth);
246
247        } else if (strcmp(*argv, "-cert") == 0) {
248
249            if (--argc < 1)
250                goto bad;
251            t_cert_file = *(++argv);
252
253        } else if (strcmp(*argv, "-key") == 0) {
254
255            if (--argc < 1)
256                goto bad;
257            t_key_file = *(++argv);
258
259        } else if (strcmp(*argv, "-CApath") == 0) {
260
261            if (--argc < 1)
262                goto bad;
263            CApath = *(++argv);
264
265        } else if (strcmp(*argv, "-CAfile") == 0) {
266
267            if (--argc < 1)
268                goto bad;
269            CAfile = *(++argv);
270
271        } else if (strcmp(*argv, "-cipher") == 0) {
272
273            if (--argc < 1)
274                goto bad;
275            tm_cipher = *(++argv);
276        }
277#ifdef FIONBIO
278        else if (strcmp(*argv, "-nbio") == 0) {
279            t_nbio = 1;
280        }
281#endif
282        else if (strcmp(*argv, "-www") == 0) {
283            if (--argc < 1)
284                goto bad;
285            s_www_path = *(++argv);
286            if (strlen(s_www_path) > MYBUFSIZ - 100) {
287                BIO_printf(bio_err, "-www option too long\n");
288                badop = 1;
289            }
290        } else if (strcmp(*argv, "-bugs") == 0)
291            st_bugs = 1;
292#ifndef OPENSSL_NO_SSL2
293        else if (strcmp(*argv, "-ssl2") == 0)
294            s_time_meth = SSLv2_client_method();
295#endif
296#ifndef OPENSSL_NO_SSL3
297        else if (strcmp(*argv, "-ssl3") == 0)
298            s_time_meth = SSLv3_client_method();
299#endif
300        else if (strcmp(*argv, "-time") == 0) {
301
302            if (--argc < 1)
303                goto bad;
304            maxTime = atoi(*(++argv));
305            if (maxTime <= 0) {
306                BIO_printf(bio_err, "time must be > 0\n");
307                badop = 1;
308            }
309        } else {
310            BIO_printf(bio_err, "unknown option %s\n", *argv);
311            badop = 1;
312            break;
313        }
314
315        argc--;
316        argv++;
317    }
318
319    if (perform == 0)
320        perform = 3;
321
322    if (badop) {
323 bad:
324        s_time_usage();
325        return -1;
326    }
327
328    return 0;                   /* Valid args */
329}
330
331/***********************************************************************
332 * TIME - time functions
333 */
334#define START   0
335#define STOP    1
336
337static double tm_Time_F(int s)
338{
339    return app_tminterval(s, 1);
340}
341
342/***********************************************************************
343 * MAIN - main processing area for client
344 *                      real name depends on MONOLITH
345 */
346int MAIN(int, char **);
347
348int MAIN(int argc, char **argv)
349{
350    double totalTime = 0.0;
351    int nConn = 0;
352    SSL *scon = NULL;
353    long finishtime = 0;
354    int ret = 1, i;
355    MS_STATIC char buf[1024 * 8];
356    int ver;
357
358    apps_startup();
359    s_time_init();
360
361    if (bio_err == NULL)
362        bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
363
364    s_time_meth = SSLv23_client_method();
365
366    /* parse the command line arguments */
367    if (parseArgs(argc, argv) < 0)
368        goto end;
369
370    OpenSSL_add_ssl_algorithms();
371    if ((tm_ctx = SSL_CTX_new(s_time_meth)) == NULL)
372        return (1);
373
374    SSL_CTX_set_quiet_shutdown(tm_ctx, 1);
375
376    if (st_bugs)
377        SSL_CTX_set_options(tm_ctx, SSL_OP_ALL);
378    SSL_CTX_set_cipher_list(tm_ctx, tm_cipher);
379    if (!set_cert_stuff(tm_ctx, t_cert_file, t_key_file))
380        goto end;
381
382    SSL_load_error_strings();
383
384    if ((!SSL_CTX_load_verify_locations(tm_ctx, CAfile, CApath)) ||
385        (!SSL_CTX_set_default_verify_paths(tm_ctx))) {
386        /*
387         * BIO_printf(bio_err,"error setting default verify locations\n");
388         */
389        ERR_print_errors(bio_err);
390        /* goto end; */
391    }
392
393    if (tm_cipher == NULL)
394        tm_cipher = getenv("SSL_CIPHER");
395
396    if (tm_cipher == NULL) {
397        fprintf(stderr, "No CIPHER specified\n");
398    }
399
400    if (!(perform & 1))
401        goto next;
402    printf("Collecting connection statistics for %d seconds\n", maxTime);
403
404    /* Loop and time how long it takes to make connections */
405
406    bytes_read = 0;
407    finishtime = (long)time(NULL) + maxTime;
408    tm_Time_F(START);
409    for (;;) {
410        if (finishtime < (long)time(NULL))
411            break;
412#ifdef WIN32_STUFF
413
414        if (flushWinMsgs(0) == -1)
415            goto end;
416
417        if (waitingToDie || exitNow) /* we're dead */
418            goto end;
419#endif
420
421        if ((scon = doConnection(NULL)) == NULL)
422            goto end;
423
424        if (s_www_path != NULL) {
425            BIO_snprintf(buf, sizeof(buf), "GET %s HTTP/1.0\r\n\r\n",
426                         s_www_path);
427            SSL_write(scon, buf, strlen(buf));
428            while ((i = SSL_read(scon, buf, sizeof(buf))) > 0)
429                bytes_read += i;
430        }
431#ifdef NO_SHUTDOWN
432        SSL_set_shutdown(scon, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN);
433#else
434        SSL_shutdown(scon);
435#endif
436        SHUTDOWN2(SSL_get_fd(scon));
437
438        nConn += 1;
439        if (SSL_session_reused(scon))
440            ver = 'r';
441        else {
442            ver = SSL_version(scon);
443            if (ver == TLS1_VERSION)
444                ver = 't';
445            else if (ver == SSL3_VERSION)
446                ver = '3';
447            else if (ver == SSL2_VERSION)
448                ver = '2';
449            else
450                ver = '*';
451        }
452        fputc(ver, stdout);
453        fflush(stdout);
454
455        SSL_free(scon);
456        scon = NULL;
457    }
458    totalTime += tm_Time_F(STOP); /* Add the time for this iteration */
459
460    i = (int)((long)time(NULL) - finishtime + maxTime);
461    printf
462        ("\n\n%d connections in %.2fs; %.2f connections/user sec, bytes read %ld\n",
463         nConn, totalTime, ((double)nConn / totalTime), bytes_read);
464    printf
465        ("%d connections in %ld real seconds, %ld bytes read per connection\n",
466         nConn, (long)time(NULL) - finishtime + maxTime, bytes_read / nConn);
467
468    /*
469     * Now loop and time connections using the same session id over and over
470     */
471
472 next:
473    if (!(perform & 2))
474        goto end;
475    printf("\n\nNow timing with session id reuse.\n");
476
477    /* Get an SSL object so we can reuse the session id */
478    if ((scon = doConnection(NULL)) == NULL) {
479        fprintf(stderr, "Unable to get connection\n");
480        goto end;
481    }
482
483    if (s_www_path != NULL) {
484        BIO_snprintf(buf, sizeof(buf), "GET %s HTTP/1.0\r\n\r\n", s_www_path);
485        SSL_write(scon, buf, strlen(buf));
486        while (SSL_read(scon, buf, sizeof(buf)) > 0) ;
487    }
488#ifdef NO_SHUTDOWN
489    SSL_set_shutdown(scon, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN);
490#else
491    SSL_shutdown(scon);
492#endif
493    SHUTDOWN2(SSL_get_fd(scon));
494
495    nConn = 0;
496    totalTime = 0.0;
497
498    finishtime = (long)time(NULL) + maxTime;
499
500    printf("starting\n");
501    bytes_read = 0;
502    tm_Time_F(START);
503
504    for (;;) {
505        if (finishtime < (long)time(NULL))
506            break;
507
508#ifdef WIN32_STUFF
509        if (flushWinMsgs(0) == -1)
510            goto end;
511
512        if (waitingToDie || exitNow) /* we're dead */
513            goto end;
514#endif
515
516        if ((doConnection(scon)) == NULL)
517            goto end;
518
519        if (s_www_path) {
520            BIO_snprintf(buf, sizeof(buf), "GET %s HTTP/1.0\r\n\r\n",
521                         s_www_path);
522            SSL_write(scon, buf, strlen(buf));
523            while ((i = SSL_read(scon, buf, sizeof(buf))) > 0)
524                bytes_read += i;
525        }
526#ifdef NO_SHUTDOWN
527        SSL_set_shutdown(scon, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN);
528#else
529        SSL_shutdown(scon);
530#endif
531        SHUTDOWN2(SSL_get_fd(scon));
532
533        nConn += 1;
534        if (SSL_session_reused(scon))
535            ver = 'r';
536        else {
537            ver = SSL_version(scon);
538            if (ver == TLS1_VERSION)
539                ver = 't';
540            else if (ver == SSL3_VERSION)
541                ver = '3';
542            else if (ver == SSL2_VERSION)
543                ver = '2';
544            else
545                ver = '*';
546        }
547        fputc(ver, stdout);
548        fflush(stdout);
549    }
550    totalTime += tm_Time_F(STOP); /* Add the time for this iteration */
551
552    printf
553        ("\n\n%d connections in %.2fs; %.2f connections/user sec, bytes read %ld\n",
554         nConn, totalTime, ((double)nConn / totalTime), bytes_read);
555    printf
556        ("%d connections in %ld real seconds, %ld bytes read per connection\n",
557         nConn, (long)time(NULL) - finishtime + maxTime,
558         bytes_read / (nConn?nConn:1));
559
560    ret = 0;
561 end:
562    if (scon != NULL)
563        SSL_free(scon);
564
565    if (tm_ctx != NULL) {
566        SSL_CTX_free(tm_ctx);
567        tm_ctx = NULL;
568    }
569    apps_shutdown();
570    OPENSSL_EXIT(ret);
571}
572
573/*-
574 * doConnection - make a connection
575 * Args:
576 *              scon    = earlier ssl connection for session id, or NULL
577 * Returns:
578 *              SSL *   = the connection pointer.
579 */
580static SSL *doConnection(SSL *scon)
581{
582    BIO *conn;
583    SSL *serverCon;
584    int width, i;
585    fd_set readfds;
586
587    if ((conn = BIO_new(BIO_s_connect())) == NULL)
588        return (NULL);
589
590/*      BIO_set_conn_port(conn,port);*/
591    BIO_set_conn_hostname(conn, host);
592
593    if (scon == NULL)
594        serverCon = SSL_new(tm_ctx);
595    else {
596        serverCon = scon;
597        SSL_set_connect_state(serverCon);
598    }
599
600    SSL_set_bio(serverCon, conn, conn);
601
602#if 0
603    if (scon != NULL)
604        SSL_set_session(serverCon, SSL_get_session(scon));
605#endif
606
607    /* ok, lets connect */
608    for (;;) {
609        i = SSL_connect(serverCon);
610        if (BIO_sock_should_retry(i)) {
611            BIO_printf(bio_err, "DELAY\n");
612
613            i = SSL_get_fd(serverCon);
614            width = i + 1;
615            FD_ZERO(&readfds);
616            openssl_fdset(i, &readfds);
617            /*
618             * Note: under VMS with SOCKETSHR the 2nd parameter is currently
619             * of type (int *) whereas under other systems it is (void *) if
620             * you don't have a cast it will choke the compiler: if you do
621             * have a cast then you can either go for (int *) or (void *).
622             */
623            select(width, (void *)&readfds, NULL, NULL, NULL);
624            continue;
625        }
626        break;
627    }
628    if (i <= 0) {
629        BIO_printf(bio_err, "ERROR\n");
630        if (verify_error != X509_V_OK)
631            BIO_printf(bio_err, "verify error:%s\n",
632                       X509_verify_cert_error_string(verify_error));
633        else
634            ERR_print_errors(bio_err);
635        if (scon == NULL)
636            SSL_free(serverCon);
637        return NULL;
638    }
639
640    return serverCon;
641}
642