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#if !defined(OPENSSL_SYS_MSDOS) && !defined(OPENSSL_SYS_VXWORKS) && (!defined(OPENSSL_SYS_VMS) || defined(__DECC)) 89#define TIMES 90#endif 91 92#ifndef _IRIX 93#include <time.h> 94#endif 95#ifdef TIMES 96#include <sys/types.h> 97#include <sys/times.h> 98#endif 99 100/* Depending on the VMS version, the tms structure is perhaps defined. 101 The __TMS macro will show if it was. If it wasn't defined, we should 102 undefine TIMES, since that tells the rest of the program how things 103 should be handled. -- Richard Levitte */ 104#if defined(OPENSSL_SYS_VMS_DECC) && !defined(__TMS) 105#undef TIMES 106#endif 107 108#if !defined(TIMES) && !defined(OPENSSL_SYS_VXWORKS) 109#include <sys/timeb.h> 110#endif 111 112#if defined(sun) || defined(__ultrix) 113#define _POSIX_SOURCE 114#include <limits.h> 115#include <sys/param.h> 116#endif 117 118/* The following if from times(3) man page. It may need to be changed 119*/ 120#ifndef HZ 121# ifdef _SC_CLK_TCK 122# define HZ ((double)sysconf(_SC_CLK_TCK)) 123# else 124# ifndef CLK_TCK 125# ifndef _BSD_CLK_TCK_ /* FreeBSD hack */ 126# define HZ 100.0 127# else /* _BSD_CLK_TCK_ */ 128# define HZ ((double)_BSD_CLK_TCK_) 129# endif 130# else /* CLK_TCK */ 131# define HZ ((double)CLK_TCK) 132# endif 133# endif 134#endif 135 136#undef PROG 137#define PROG s_time_main 138 139#undef ioctl 140#define ioctl ioctlsocket 141 142#define SSL_CONNECT_NAME "localhost:4433" 143 144/*#define TEST_CERT "client.pem" */ /* no default cert. */ 145 146#undef BUFSIZZ 147#define BUFSIZZ 1024*10 148 149#define MYBUFSIZ 1024*8 150 151#undef min 152#undef max 153#define min(a,b) (((a) < (b)) ? (a) : (b)) 154#define max(a,b) (((a) > (b)) ? (a) : (b)) 155 156#undef SECONDS 157#define SECONDS 30 158extern int verify_depth; 159extern int verify_error; 160 161static void s_time_usage(void); 162static int parseArgs( int argc, char **argv ); 163static SSL *doConnection( SSL *scon ); 164static void s_time_init(void); 165 166/*********************************************************************** 167 * Static data declarations 168 */ 169 170/* static char *port=PORT_STR;*/ 171static char *host=SSL_CONNECT_NAME; 172static char *t_cert_file=NULL; 173static char *t_key_file=NULL; 174static char *CApath=NULL; 175static char *CAfile=NULL; 176static char *tm_cipher=NULL; 177static int tm_verify = SSL_VERIFY_NONE; 178static int maxTime = SECONDS; 179static SSL_CTX *tm_ctx=NULL; 180static SSL_METHOD *s_time_meth=NULL; 181static char *s_www_path=NULL; 182static long bytes_read=0; 183static int st_bugs=0; 184static int perform=0; 185#ifdef FIONBIO 186static int t_nbio=0; 187#endif 188#ifdef OPENSSL_SYS_WIN32 189static int exitNow = 0; /* Set when it's time to exit main */ 190#endif 191 192static void s_time_init(void) 193 { 194 host=SSL_CONNECT_NAME; 195 t_cert_file=NULL; 196 t_key_file=NULL; 197 CApath=NULL; 198 CAfile=NULL; 199 tm_cipher=NULL; 200 tm_verify = SSL_VERIFY_NONE; 201 maxTime = SECONDS; 202 tm_ctx=NULL; 203 s_time_meth=NULL; 204 s_www_path=NULL; 205 bytes_read=0; 206 st_bugs=0; 207 perform=0; 208 209#ifdef FIONBIO 210 t_nbio=0; 211#endif 212#ifdef OPENSSL_SYS_WIN32 213 exitNow = 0; /* Set when it's time to exit main */ 214#endif 215 } 216 217/*********************************************************************** 218 * usage - display usage message 219 */ 220static void s_time_usage(void) 221{ 222 static char umsg[] = "\ 223-time arg - max number of seconds to collect data, default %d\n\ 224-verify arg - turn on peer certificate verification, arg == depth\n\ 225-cert arg - certificate file to use, PEM format assumed\n\ 226-key arg - RSA file to use, PEM format assumed, key is in cert file\n\ 227 file if not specified by this option\n\ 228-CApath arg - PEM format directory of CA's\n\ 229-CAfile arg - PEM format file of CA's\n\ 230-cipher - preferred cipher to use, play with 'openssl ciphers'\n\n"; 231 232 printf( "usage: s_time <args>\n\n" ); 233 234 printf("-connect host:port - host:port to connect to (default is %s)\n",SSL_CONNECT_NAME); 235#ifdef FIONBIO 236 printf("-nbio - Run with non-blocking IO\n"); 237 printf("-ssl2 - Just use SSLv2\n"); 238 printf("-ssl3 - Just use SSLv3\n"); 239 printf("-bugs - Turn on SSL bug compatibility\n"); 240 printf("-new - Just time new connections\n"); 241 printf("-reuse - Just time connection reuse\n"); 242 printf("-www page - Retrieve 'page' from the site\n"); 243#endif 244 printf( umsg,SECONDS ); 245} 246 247/*********************************************************************** 248 * parseArgs - Parse command line arguments and initialize data 249 * 250 * Returns 0 if ok, -1 on bad args 251 */ 252static int parseArgs(int argc, char **argv) 253{ 254 int badop = 0; 255 256 verify_depth=0; 257 verify_error=X509_V_OK; 258 259 argc--; 260 argv++; 261 262 while (argc >= 1) { 263 if (strcmp(*argv,"-connect") == 0) 264 { 265 if (--argc < 1) goto bad; 266 host= *(++argv); 267 } 268#if 0 269 else if( strcmp(*argv,"-host") == 0) 270 { 271 if (--argc < 1) goto bad; 272 host= *(++argv); 273 } 274 else if( strcmp(*argv,"-port") == 0) 275 { 276 if (--argc < 1) goto bad; 277 port= *(++argv); 278 } 279#endif 280 else if (strcmp(*argv,"-reuse") == 0) 281 perform=2; 282 else if (strcmp(*argv,"-new") == 0) 283 perform=1; 284 else if( strcmp(*argv,"-verify") == 0) { 285 286 tm_verify=SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE; 287 if (--argc < 1) goto bad; 288 verify_depth=atoi(*(++argv)); 289 BIO_printf(bio_err,"verify depth is %d\n",verify_depth); 290 291 } else if( strcmp(*argv,"-cert") == 0) { 292 293 if (--argc < 1) goto bad; 294 t_cert_file= *(++argv); 295 296 } else if( strcmp(*argv,"-key") == 0) { 297 298 if (--argc < 1) goto bad; 299 t_key_file= *(++argv); 300 301 } else if( strcmp(*argv,"-CApath") == 0) { 302 303 if (--argc < 1) goto bad; 304 CApath= *(++argv); 305 306 } else if( strcmp(*argv,"-CAfile") == 0) { 307 308 if (--argc < 1) goto bad; 309 CAfile= *(++argv); 310 311 } else if( strcmp(*argv,"-cipher") == 0) { 312 313 if (--argc < 1) goto bad; 314 tm_cipher= *(++argv); 315 } 316#ifdef FIONBIO 317 else if(strcmp(*argv,"-nbio") == 0) { 318 t_nbio=1; 319 } 320#endif 321 else if(strcmp(*argv,"-www") == 0) 322 { 323 if (--argc < 1) goto bad; 324 s_www_path= *(++argv); 325 if(strlen(s_www_path) > MYBUFSIZ-100) 326 { 327 BIO_printf(bio_err,"-www option too long\n"); 328 badop=1; 329 } 330 } 331 else if(strcmp(*argv,"-bugs") == 0) 332 st_bugs=1; 333#ifndef OPENSSL_NO_SSL2 334 else if(strcmp(*argv,"-ssl2") == 0) 335 s_time_meth=SSLv2_client_method(); 336#endif 337#ifndef OPENSSL_NO_SSL3 338 else if(strcmp(*argv,"-ssl3") == 0) 339 s_time_meth=SSLv3_client_method(); 340#endif 341 else if( strcmp(*argv,"-time") == 0) { 342 343 if (--argc < 1) goto bad; 344 maxTime= atoi(*(++argv)); 345 } 346 else { 347 BIO_printf(bio_err,"unknown option %s\n",*argv); 348 badop=1; 349 break; 350 } 351 352 argc--; 353 argv++; 354 } 355 356 if (perform == 0) perform=3; 357 358 if(badop) { 359bad: 360 s_time_usage(); 361 return -1; 362 } 363 364 return 0; /* Valid args */ 365} 366 367/*********************************************************************** 368 * TIME - time functions 369 */ 370#define START 0 371#define STOP 1 372 373static double tm_Time_F(int s) 374 { 375 static double ret; 376#ifdef TIMES 377 static struct tms tstart,tend; 378 379 if(s == START) { 380 times(&tstart); 381 return(0); 382 } else { 383 times(&tend); 384 ret=((double)(tend.tms_utime-tstart.tms_utime))/HZ; 385 return((ret == 0.0)?1e-6:ret); 386 } 387#elif defined(OPENSSL_SYS_VXWORKS) 388 { 389 static unsigned long tick_start, tick_end; 390 391 if( s == START ) 392 { 393 tick_start = tickGet(); 394 return 0; 395 } 396 else 397 { 398 tick_end = tickGet(); 399 ret = (double)(tick_end - tick_start) / (double)sysClkRateGet(); 400 return((ret == 0.0)?1e-6:ret); 401 } 402 } 403#else /* !times() */ 404 static struct timeb tstart,tend; 405 long i; 406 407 if(s == START) { 408 ftime(&tstart); 409 return(0); 410 } else { 411 ftime(&tend); 412 i=(long)tend.millitm-(long)tstart.millitm; 413 ret=((double)(tend.time-tstart.time))+((double)i)/1000.0; 414 return((ret == 0.0)?1e-6:ret); 415 } 416#endif 417} 418 419/*********************************************************************** 420 * MAIN - main processing area for client 421 * real name depends on MONOLITH 422 */ 423int MAIN(int, char **); 424 425int MAIN(int argc, char **argv) 426 { 427 double totalTime = 0.0; 428 int nConn = 0; 429 SSL *scon=NULL; 430 long finishtime=0; 431 int ret=1,i; 432 MS_STATIC char buf[1024*8]; 433 int ver; 434 435 apps_startup(); 436 s_time_init(); 437 438 if (bio_err == NULL) 439 bio_err=BIO_new_fp(stderr,BIO_NOCLOSE); 440 441#if !defined(OPENSSL_NO_SSL2) && !defined(OPENSSL_NO_SSL3) 442 s_time_meth=SSLv23_client_method(); 443#elif !defined(OPENSSL_NO_SSL3) 444 s_time_meth=SSLv3_client_method(); 445#elif !defined(OPENSSL_NO_SSL2) 446 s_time_meth=SSLv2_client_method(); 447#endif 448 449 /* parse the command line arguments */ 450 if( parseArgs( argc, argv ) < 0 ) 451 goto end; 452 453 OpenSSL_add_ssl_algorithms(); 454 if ((tm_ctx=SSL_CTX_new(s_time_meth)) == NULL) return(1); 455 456 SSL_CTX_set_quiet_shutdown(tm_ctx,1); 457 458 if (st_bugs) SSL_CTX_set_options(tm_ctx,SSL_OP_ALL); 459 SSL_CTX_set_cipher_list(tm_ctx,tm_cipher); 460 if(!set_cert_stuff(tm_ctx,t_cert_file,t_key_file)) 461 goto end; 462 463 SSL_load_error_strings(); 464 465 if ((!SSL_CTX_load_verify_locations(tm_ctx,CAfile,CApath)) || 466 (!SSL_CTX_set_default_verify_paths(tm_ctx))) 467 { 468 /* BIO_printf(bio_err,"error setting default verify locations\n"); */ 469 ERR_print_errors(bio_err); 470 /* goto end; */ 471 } 472 473 if (tm_cipher == NULL) 474 tm_cipher = getenv("SSL_CIPHER"); 475 476 if (tm_cipher == NULL ) { 477 fprintf( stderr, "No CIPHER specified\n" ); 478 } 479 480 if (!(perform & 1)) goto next; 481 printf( "Collecting connection statistics for %d seconds\n", maxTime ); 482 483 /* Loop and time how long it takes to make connections */ 484 485 bytes_read=0; 486 finishtime=(long)time(NULL)+maxTime; 487 tm_Time_F(START); 488 for (;;) 489 { 490 if (finishtime < (long)time(NULL)) break; 491#ifdef WIN32_STUFF 492 493 if( flushWinMsgs(0) == -1 ) 494 goto end; 495 496 if( waitingToDie || exitNow ) /* we're dead */ 497 goto end; 498#endif 499 500 if( (scon = doConnection( NULL )) == NULL ) 501 goto end; 502 503 if (s_www_path != NULL) 504 { 505 BIO_snprintf(buf,sizeof buf,"GET %s HTTP/1.0\r\n\r\n",s_www_path); 506 SSL_write(scon,buf,strlen(buf)); 507 while ((i=SSL_read(scon,buf,sizeof(buf))) > 0) 508 bytes_read+=i; 509 } 510 511#ifdef NO_SHUTDOWN 512 SSL_set_shutdown(scon,SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN); 513#else 514 SSL_shutdown(scon); 515#endif 516 SHUTDOWN2(SSL_get_fd(scon)); 517 518 nConn += 1; 519 if (SSL_session_reused(scon)) 520 ver='r'; 521 else 522 { 523 ver=SSL_version(scon); 524 if (ver == TLS1_VERSION) 525 ver='t'; 526 else if (ver == SSL3_VERSION) 527 ver='3'; 528 else if (ver == SSL2_VERSION) 529 ver='2'; 530 else 531 ver='*'; 532 } 533 fputc(ver,stdout); 534 fflush(stdout); 535 536 SSL_free( scon ); 537 scon=NULL; 538 } 539 totalTime += tm_Time_F(STOP); /* Add the time for this iteration */ 540 541 i=(int)((long)time(NULL)-finishtime+maxTime); 542 printf( "\n\n%d connections in %.2fs; %.2f connections/user sec, bytes read %ld\n", nConn, totalTime, ((double)nConn/totalTime),bytes_read); 543 printf( "%d connections in %ld real seconds, %ld bytes read per connection\n",nConn,(long)time(NULL)-finishtime+maxTime,bytes_read/nConn); 544 545 /* Now loop and time connections using the same session id over and over */ 546 547next: 548 if (!(perform & 2)) goto end; 549 printf( "\n\nNow timing with session id reuse.\n" ); 550 551 /* Get an SSL object so we can reuse the session id */ 552 if( (scon = doConnection( NULL )) == NULL ) 553 { 554 fprintf( stderr, "Unable to get connection\n" ); 555 goto end; 556 } 557 558 if (s_www_path != NULL) 559 { 560 BIO_snprintf(buf,sizeof buf,"GET %s HTTP/1.0\r\n\r\n",s_www_path); 561 SSL_write(scon,buf,strlen(buf)); 562 while (SSL_read(scon,buf,sizeof(buf)) > 0) 563 ; 564 } 565#ifdef NO_SHUTDOWN 566 SSL_set_shutdown(scon,SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN); 567#else 568 SSL_shutdown(scon); 569#endif 570 SHUTDOWN2(SSL_get_fd(scon)); 571 572 nConn = 0; 573 totalTime = 0.0; 574 575 finishtime=(long)time(NULL)+maxTime; 576 577 printf( "starting\n" ); 578 bytes_read=0; 579 tm_Time_F(START); 580 581 for (;;) 582 { 583 if (finishtime < (long)time(NULL)) break; 584 585#ifdef WIN32_STUFF 586 if( flushWinMsgs(0) == -1 ) 587 goto end; 588 589 if( waitingToDie || exitNow ) /* we're dead */ 590 goto end; 591#endif 592 593 if( (doConnection( scon )) == NULL ) 594 goto end; 595 596 if (s_www_path) 597 { 598 BIO_snprintf(buf,sizeof buf,"GET %s HTTP/1.0\r\n\r\n",s_www_path); 599 SSL_write(scon,buf,strlen(buf)); 600 while ((i=SSL_read(scon,buf,sizeof(buf))) > 0) 601 bytes_read+=i; 602 } 603 604#ifdef NO_SHUTDOWN 605 SSL_set_shutdown(scon,SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN); 606#else 607 SSL_shutdown(scon); 608#endif 609 SHUTDOWN2(SSL_get_fd(scon)); 610 611 nConn += 1; 612 if (SSL_session_reused(scon)) 613 ver='r'; 614 else 615 { 616 ver=SSL_version(scon); 617 if (ver == TLS1_VERSION) 618 ver='t'; 619 else if (ver == SSL3_VERSION) 620 ver='3'; 621 else if (ver == SSL2_VERSION) 622 ver='2'; 623 else 624 ver='*'; 625 } 626 fputc(ver,stdout); 627 fflush(stdout); 628 } 629 totalTime += tm_Time_F(STOP); /* Add the time for this iteration*/ 630 631 632 printf( "\n\n%d connections in %.2fs; %.2f connections/user sec, bytes read %ld\n", nConn, totalTime, ((double)nConn/totalTime),bytes_read); 633 printf( "%d connections in %ld real seconds, %ld bytes read per connection\n",nConn,(long)time(NULL)-finishtime+maxTime,bytes_read/nConn); 634 635 ret=0; 636end: 637 if (scon != NULL) SSL_free(scon); 638 639 if (tm_ctx != NULL) 640 { 641 SSL_CTX_free(tm_ctx); 642 tm_ctx=NULL; 643 } 644 apps_shutdown(); 645 OPENSSL_EXIT(ret); 646 } 647 648/*********************************************************************** 649 * doConnection - make a connection 650 * Args: 651 * scon = earlier ssl connection for session id, or NULL 652 * Returns: 653 * SSL * = the connection pointer. 654 */ 655static SSL *doConnection(SSL *scon) 656 { 657 BIO *conn; 658 SSL *serverCon; 659 int width, i; 660 fd_set readfds; 661 662 if ((conn=BIO_new(BIO_s_connect())) == NULL) 663 return(NULL); 664 665/* BIO_set_conn_port(conn,port);*/ 666 BIO_set_conn_hostname(conn,host); 667 668 if (scon == NULL) 669 serverCon=SSL_new(tm_ctx); 670 else 671 { 672 serverCon=scon; 673 SSL_set_connect_state(serverCon); 674 } 675 676 SSL_set_bio(serverCon,conn,conn); 677 678#if 0 679 if( scon != NULL ) 680 SSL_set_session(serverCon,SSL_get_session(scon)); 681#endif 682 683 /* ok, lets connect */ 684 for(;;) { 685 i=SSL_connect(serverCon); 686 if (BIO_sock_should_retry(i)) 687 { 688 BIO_printf(bio_err,"DELAY\n"); 689 690 i=SSL_get_fd(serverCon); 691 width=i+1; 692 FD_ZERO(&readfds); 693 FD_SET(i,&readfds); 694 /* Note: under VMS with SOCKETSHR the 2nd parameter 695 * is currently of type (int *) whereas under other 696 * systems it is (void *) if you don't have a cast it 697 * will choke the compiler: if you do have a cast then 698 * you can either go for (int *) or (void *). 699 */ 700 select(width,(void *)&readfds,NULL,NULL,NULL); 701 continue; 702 } 703 break; 704 } 705 if(i <= 0) 706 { 707 BIO_printf(bio_err,"ERROR\n"); 708 if (verify_error != X509_V_OK) 709 BIO_printf(bio_err,"verify error:%s\n", 710 X509_verify_cert_error_string(verify_error)); 711 else 712 ERR_print_errors(bio_err); 713 if (scon == NULL) 714 SSL_free(serverCon); 715 return NULL; 716 } 717 718 return serverCon; 719 } 720 721 722