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