s_time.c 11.9 KB
Newer Older
R
Rich Salz 已提交
1 2
/*
 * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
3
 *
R
Rich Salz 已提交
4 5 6 7
 * Licensed under the OpenSSL license (the "License").  You may not use
 * this file except in compliance with the License.  You can obtain a copy
 * in the file LICENSE in the source distribution or at
 * https://www.openssl.org/source/license.html
8 9
 */

10
#define NO_SHUTDOWN
11 12 13 14 15

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

M
Matt Caswell 已提交
16 17 18 19
#include <openssl/opensslconf.h>

#ifndef OPENSSL_NO_SOCK

20 21
#define USE_SOCKETS
#include "apps.h"
22 23 24
#include <openssl/x509.h>
#include <openssl/ssl.h>
#include <openssl/pem.h>
25
#include "s_apps.h"
26
#include <openssl/err.h>
27
#if !defined(OPENSSL_SYS_MSDOS)
28
# include OPENSSL_UNISTD
29
#endif
30

U
Ulf Möller 已提交
31
#undef ioctl
32 33
#define ioctl ioctlsocket

34
#define SSL_CONNECT_NAME        "localhost:4433"
35

36
/* no default cert. */
37 38 39
/*
 * #define TEST_CERT "client.pem"
 */
40 41 42 43

#undef BUFSIZZ
#define BUFSIZZ 1024*10

44 45
#undef min
#undef max
46 47 48 49
#define min(a,b) (((a) < (b)) ? (a) : (b))
#define max(a,b) (((a) > (b)) ? (a) : (b))

#undef SECONDS
50
#define SECONDS 30
51 52
#define SECONDSSTR "30"

53 54 55
extern int verify_depth;
extern int verify_error;

56
static SSL *doConnection(SSL *scon, const char *host, SSL_CTX *ctx);
57

58 59
static const char fmt_http_get_cmd[] = "GET %s HTTP/1.0\r\n\r\n";

60 61 62
typedef enum OPTION_choice {
    OPT_ERR = -1, OPT_EOF = 0, OPT_HELP,
    OPT_CONNECT, OPT_CIPHER, OPT_CERT, OPT_KEY, OPT_CAPATH,
63 64
    OPT_CAFILE, OPT_NOCAPATH, OPT_NOCAFILE, OPT_NEW, OPT_REUSE, OPT_BUGS,
    OPT_VERIFY, OPT_TIME, OPT_SSL3,
65 66 67 68 69 70 71 72 73 74 75 76
    OPT_WWW
} OPTION_CHOICE;

OPTIONS s_time_options[] = {
    {"help", OPT_HELP, '-', "Display this summary"},
    {"connect", OPT_CONNECT, 's',
     "Where to connect as post:port (default is " SSL_CONNECT_NAME ")"},
    {"cipher", OPT_CIPHER, 's', "Cipher to use, see 'openssl ciphers'"},
    {"cert", OPT_CERT, '<', "Cert file to use, PEM format assumed"},
    {"key", OPT_KEY, '<', "File with key, PEM; default is -cert file"},
    {"CApath", OPT_CAPATH, '/', "PEM format directory of CA's"},
    {"cafile", OPT_CAFILE, '<', "PEM format file of CA's"},
77 78 79 80
    {"no-CAfile", OPT_NOCAFILE, '-',
     "Do not load the default certificates file"},
    {"no-CApath", OPT_NOCAPATH, '-',
     "Do not load certificates from the default certificates directory"},
81 82 83 84 85
    {"new", OPT_NEW, '-', "Just time new connections"},
    {"reuse", OPT_REUSE, '-', "Just time connection reuse"},
    {"bugs", OPT_BUGS, '-', "Turn on SSL bug compatibility"},
    {"verify", OPT_VERIFY, 'p',
     "Turn on peer certificate verification, set depth"},
86
    {"time", OPT_TIME, 'p', "Seconds to collect data, default " SECONDSSTR},
87 88 89
    {"www", OPT_WWW, 's', "Fetch specified page from the site"},
#ifndef OPENSSL_NO_SSL3
    {"ssl3", OPT_SSL3, '-', "Just use SSLv3"},
90
#endif
91 92
    {NULL}
};
93

94 95
#define START   0
#define STOP    1
96

97
static double tm_Time_F(int s)
98
{
99
    return app_tminterval(s, 1);
100 101
}

102
int s_time_main(int argc, char **argv)
103
{
104 105 106 107 108 109 110
    char buf[1024 * 8];
    SSL *scon = NULL;
    SSL_CTX *ctx = NULL;
    const SSL_METHOD *meth = NULL;
    char *CApath = NULL, *CAfile = NULL, *cipher = NULL, *www_path = NULL;
    char *host = SSL_CONNECT_NAME, *certfile = NULL, *keyfile = NULL, *prog;
    double totalTime = 0.0;
111
    int noCApath = 0, noCAfile = 0;
112
    int maxtime = SECONDS, nConn = 0, perform = 3, ret = 1, i, st_bugs = 0;
113 114
    long bytes_read = 0, finishtime = 0;
    OPTION_CHOICE o;
115 116
    int max_version = 0, ver, buf_len;
    size_t buf_size;
117

118
    meth = TLS_client_method();
119 120
    verify_depth = 0;
    verify_error = X509_V_OK;
121

122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
    prog = opt_init(argc, argv, s_time_options);
    while ((o = opt_next()) != OPT_EOF) {
        switch (o) {
        case OPT_EOF:
        case OPT_ERR:
 opthelp:
            BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
            goto end;
        case OPT_HELP:
            opt_help(s_time_options);
            ret = 0;
            goto end;
        case OPT_CONNECT:
            host = opt_arg();
            break;
        case OPT_REUSE:
138
            perform = 2;
139 140
            break;
        case OPT_NEW:
141
            perform = 1;
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
            break;
        case OPT_VERIFY:
            if (!opt_int(opt_arg(), &verify_depth))
                goto opthelp;
            BIO_printf(bio_err, "%s: verify depth is %d\n",
                       prog, verify_depth);
            break;
        case OPT_CERT:
            certfile = opt_arg();
            break;
        case OPT_KEY:
            keyfile = opt_arg();
            break;
        case OPT_CAPATH:
            CApath = opt_arg();
            break;
        case OPT_CAFILE:
            CAfile = opt_arg();
            break;
161 162 163 164 165 166
        case OPT_NOCAPATH:
            noCApath = 1;
            break;
        case OPT_NOCAFILE:
            noCAfile = 1;
            break;
167 168 169 170
        case OPT_CIPHER:
            cipher = opt_arg();
            break;
        case OPT_BUGS:
171
            st_bugs = 1;
172 173 174 175 176 177 178
            break;
        case OPT_TIME:
            if (!opt_int(opt_arg(), &maxtime))
                goto opthelp;
            break;
        case OPT_WWW:
            www_path = opt_arg();
179 180 181
            buf_size = strlen(www_path) + sizeof(fmt_http_get_cmd) - 2;  /* 2 is for %s */
            if (buf_size > sizeof(buf)) {
                BIO_printf(bio_err, "%s: -www option is too long\n", prog);
182
                goto end;
M
Matt Caswell 已提交
183
            }
184
            break;
185
        case OPT_SSL3:
186
            max_version = SSL3_VERSION;
187
            break;
188
        }
189
    }
190
    argc = opt_num_rest();
K
Kurt Roeckx 已提交
191 192
    if (argc != 0)
        goto opthelp;
193

194 195 196
    if (cipher == NULL)
        cipher = getenv("SSL_CIPHER");
    if (cipher == NULL) {
R
Rich Salz 已提交
197
        BIO_printf(bio_err, "No CIPHER specified\n");
198
        goto end;
199 200
    }

201
    if ((ctx = SSL_CTX_new(meth)) == NULL)
202 203
        goto end;

204
    SSL_CTX_set_quiet_shutdown(ctx, 1);
205 206
    if (SSL_CTX_set_max_proto_version(ctx, max_version) == 0)
        goto end;
207 208

    if (st_bugs)
209 210
        SSL_CTX_set_options(ctx, SSL_OP_ALL);
    if (!SSL_CTX_set_cipher_list(ctx, cipher))
M
Matt Caswell 已提交
211
        goto end;
212
    if (!set_cert_stuff(ctx, certfile, keyfile))
213 214
        goto end;

215
    if (!ctx_set_verify_locations(ctx, CAfile, CApath, noCAfile, noCApath)) {
216
        ERR_print_errors(bio_err);
217
        goto end;
218 219 220
    }
    if (!(perform & 1))
        goto next;
221
    printf("Collecting connection statistics for %d seconds\n", maxtime);
222

223
    /* Loop and time how long it takes to make connections */
224

225
    bytes_read = 0;
226
    finishtime = (long)time(NULL) + maxtime;
227 228 229 230
    tm_Time_F(START);
    for (;;) {
        if (finishtime < (long)time(NULL))
            break;
231

232
        if ((scon = doConnection(NULL, host, ctx)) == NULL)
233
            goto end;
234

235
        if (www_path != NULL) {
236 237 238
            buf_len = BIO_snprintf(buf, sizeof buf,
                                   fmt_http_get_cmd, www_path);
            if (SSL_write(scon, buf, buf_len) <= 0)
M
Matt Caswell 已提交
239
                goto end;
240 241 242
            while ((i = SSL_read(scon, buf, sizeof(buf))) > 0)
                bytes_read += i;
        }
243
#ifdef NO_SHUTDOWN
244
        SSL_set_shutdown(scon, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN);
245
#else
246
        SSL_shutdown(scon);
247
#endif
R
Rich Salz 已提交
248
        BIO_closesocket(SSL_get_fd(scon));
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269

        nConn += 1;
        if (SSL_session_reused(scon))
            ver = 'r';
        else {
            ver = SSL_version(scon);
            if (ver == TLS1_VERSION)
                ver = 't';
            else if (ver == SSL3_VERSION)
                ver = '3';
            else
                ver = '*';
        }
        fputc(ver, stdout);
        fflush(stdout);

        SSL_free(scon);
        scon = NULL;
    }
    totalTime += tm_Time_F(STOP); /* Add the time for this iteration */

270
    i = (int)((long)time(NULL) - finishtime + maxtime);
271 272 273 274 275
    printf
        ("\n\n%d connections in %.2fs; %.2f connections/user sec, bytes read %ld\n",
         nConn, totalTime, ((double)nConn / totalTime), bytes_read);
    printf
        ("%d connections in %ld real seconds, %ld bytes read per connection\n",
276
         nConn, (long)time(NULL) - finishtime + maxtime, bytes_read / nConn);
277 278 279 280 281 282 283 284 285 286 287

    /*
     * Now loop and time connections using the same session id over and over
     */

 next:
    if (!(perform & 2))
        goto end;
    printf("\n\nNow timing with session id reuse.\n");

    /* Get an SSL object so we can reuse the session id */
288
    if ((scon = doConnection(NULL, host, ctx)) == NULL) {
R
Rich Salz 已提交
289
        BIO_printf(bio_err, "Unable to get connection\n");
290 291 292
        goto end;
    }

293
    if (www_path != NULL) {
294 295 296
        buf_len = BIO_snprintf(buf, sizeof buf,
                               fmt_http_get_cmd, www_path);
        if (SSL_write(scon, buf, buf_len) <= 0)
M
Matt Caswell 已提交
297
            goto end;
298 299
        while (SSL_read(scon, buf, sizeof(buf)) > 0)
            continue;
300
    }
301
#ifdef NO_SHUTDOWN
302
    SSL_set_shutdown(scon, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN);
303
#else
304
    SSL_shutdown(scon);
305
#endif
R
Rich Salz 已提交
306
    BIO_closesocket(SSL_get_fd(scon));
307 308 309

    nConn = 0;
    totalTime = 0.0;
310

311
    finishtime = (long)time(NULL) + maxtime;
312

313 314 315
    printf("starting\n");
    bytes_read = 0;
    tm_Time_F(START);
316

317 318 319
    for (;;) {
        if (finishtime < (long)time(NULL))
            break;
320

321
        if ((doConnection(scon, host, ctx)) == NULL)
322
            goto end;
323

324
        if (www_path) {
325
            BIO_snprintf(buf, sizeof buf, "GET %s HTTP/1.0\r\n\r\n",
326
                         www_path);
V
Viktor Dukhovni 已提交
327
            if (SSL_write(scon, buf, strlen(buf)) <= 0)
M
Matt Caswell 已提交
328
                goto end;
329 330 331
            while ((i = SSL_read(scon, buf, sizeof(buf))) > 0)
                bytes_read += i;
        }
332
#ifdef NO_SHUTDOWN
333
        SSL_set_shutdown(scon, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN);
334
#else
335
        SSL_shutdown(scon);
336
#endif
R
Rich Salz 已提交
337
        BIO_closesocket(SSL_get_fd(scon));
338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360

        nConn += 1;
        if (SSL_session_reused(scon))
            ver = 'r';
        else {
            ver = SSL_version(scon);
            if (ver == TLS1_VERSION)
                ver = 't';
            else if (ver == SSL3_VERSION)
                ver = '3';
            else
                ver = '*';
        }
        fputc(ver, stdout);
        fflush(stdout);
    }
    totalTime += tm_Time_F(STOP); /* Add the time for this iteration */

    printf
        ("\n\n%d connections in %.2fs; %.2f connections/user sec, bytes read %ld\n",
         nConn, totalTime, ((double)nConn / totalTime), bytes_read);
    printf
        ("%d connections in %ld real seconds, %ld bytes read per connection\n",
361
         nConn, (long)time(NULL) - finishtime + maxtime, bytes_read / nConn);
362 363

    ret = 0;
364

365
 end:
R
Rich Salz 已提交
366
    SSL_free(scon);
367 368
    SSL_CTX_free(ctx);
    return (ret);
369
}
370

371
/*-
372 373
 * doConnection - make a connection
 */
374
static SSL *doConnection(SSL *scon, const char *host, SSL_CTX *ctx)
375 376 377 378 379 380 381 382 383 384 385 386
{
    BIO *conn;
    SSL *serverCon;
    int width, i;
    fd_set readfds;

    if ((conn = BIO_new(BIO_s_connect())) == NULL)
        return (NULL);

    BIO_set_conn_hostname(conn, host);

    if (scon == NULL)
387
        serverCon = SSL_new(ctx);
388 389 390 391
    else {
        serverCon = scon;
        SSL_set_connect_state(serverCon);
    }
392

393
    SSL_set_bio(serverCon, conn, conn);
394

395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426
    /* ok, lets connect */
    for (;;) {
        i = SSL_connect(serverCon);
        if (BIO_sock_should_retry(i)) {
            BIO_printf(bio_err, "DELAY\n");

            i = SSL_get_fd(serverCon);
            width = i + 1;
            FD_ZERO(&readfds);
            openssl_fdset(i, &readfds);
            /*
             * Note: under VMS with SOCKETSHR the 2nd parameter is currently
             * of type (int *) whereas under other systems it is (void *) if
             * you don't have a cast it will choke the compiler: if you do
             * have a cast then you can either go for (int *) or (void *).
             */
            select(width, (void *)&readfds, NULL, NULL, NULL);
            continue;
        }
        break;
    }
    if (i <= 0) {
        BIO_printf(bio_err, "ERROR\n");
        if (verify_error != X509_V_OK)
            BIO_printf(bio_err, "verify error:%s\n",
                       X509_verify_cert_error_string(verify_error));
        else
            ERR_print_errors(bio_err);
        if (scon == NULL)
            SSL_free(serverCon);
        return NULL;
    }
427

428 429
    return serverCon;
}
M
Matt Caswell 已提交
430
#endif /* OPENSSL_NO_SOCK */