📄 ab.c
字号:
/* Copyright 1999-2005 The Apache Software Foundation or its licensors, as * applicable. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *//* ** This program is based on ZeusBench V1.0 written by Adam Twiss ** which is Copyright (c) 1996 by Zeus Technology Ltd. http://www.zeustech.net/ ** ** This software is provided "as is" and any express or implied waranties, ** including but not limited to, the implied warranties of merchantability and ** fitness for a particular purpose are disclaimed. In no event shall ** Zeus Technology Ltd. be liable for any direct, indirect, incidental, special, ** exemplary, or consequential damaged (including, but not limited to, ** procurement of substitute good or services; loss of use, data, or profits; ** or business interruption) however caused and on theory of liability. Whether ** in contract, strict liability or tort (including negligence or otherwise) ** arising in any way out of the use of this software, even if advised of the ** possibility of such damage. ** *//* ** HISTORY: ** - Originally written by Adam Twiss <adam@zeus.co.uk>, March 1996 ** with input from Mike Belshe <mbelshe@netscape.com> and ** Michael Campanella <campanella@stevms.enet.dec.com> ** - Enhanced by Dean Gaudet <dgaudet@apache.org>, November 1997 ** - Cleaned up by Ralf S. Engelschall <rse@apache.org>, March 1998 ** - POST and verbosity by Kurt Sussman <kls@merlot.com>, August 1998 ** - HTML table output added by David N. Welton <davidw@prosa.it>, January 1999 ** - Added Cookie, Arbitrary header and auth support. <dirkx@webweaving.org>, April 1999 ** Version 1.3d ** - Increased version number - as some of the socket/error handling has ** fundamentally changed - and will give fundamentally different results ** in situations where a server is dropping requests. Therefore you can ** no longer compare results of AB as easily. Hence the inc of the version. ** They should be closer to the truth though. Sander & <dirkx@covalent.net>, End 2000. ** - Fixed proxy functionality, added median/mean statistics, added gnuplot ** output option, added _experimental/rudimentary_ SSL support. Added ** confidence guestimators and warnings. Sander & <dirkx@covalent.net>, End 2000 ** - Fixed serious int overflow issues which would cause realistic (longer ** than a few minutes) run's to have wrong (but believable) results. Added ** trapping of connection errors which influenced measurements. ** Contributed by Sander Temme, Early 2001 ** Version 1.3e ** - Changed timeout behavour during write to work whilst the sockets ** are filling up and apr_write() does writes a few - but not all. ** This will potentially change results. <dirkx@webweaving.org>, April 2001 ** Version 2.0.36-dev ** Improvements to concurrent processing: ** - Enabled non-blocking connect()s. ** - Prevent blocking calls to apr_recv() (thereby allowing AB to ** manage its entire set of socket descriptors). ** - Any error returned from apr_recv() that is not EAGAIN or EOF ** is now treated as fatal. ** Contributed by Aaron Bannert, April 24, 2002 ** ** Version 2.0.36-2 ** Internalized the version string - this string is part ** of the Agent: header and the result output. ** ** Version 2.0.37-dev ** Adopted SSL code by Madhu Mathihalli <madhusudan_mathihalli@hp.com> ** [PATCH] ab with SSL support Posted Wed, 15 Aug 2001 20:55:06 GMT ** Introduces four 'if (int == value)' tests per non-ssl request. ** ** Version 2.0.40-dev ** Switched to the new abstract pollset API, allowing ab to ** take advantage of future apr_pollset_t scalability improvements. ** Contributed by Brian Pane, August 31, 2002 **//* Note: this version string should start with \d+[\d\.]* and be a valid * string for an HTTP Agent: header when prefixed with 'ApacheBench/'. * It should reflect the version of AB - and not that of the apache server * it happens to accompany. And it should be updated or changed whenever * the results are no longer fundamentally comparable to the results of * a previous version of ab. Either due to a change in the logic of * ab - or to due to a change in the distribution it is compiled with * (such as an APR change in for example blocking). */#define AP_AB_BASEREVISION "2.0.41-dev" /* * BUGS: * * - uses strcpy/etc. * - has various other poor buffer attacks related to the lazy parsing of * response headers from the server * - doesn't implement much of HTTP/1.x, only accepts certain forms of * responses * - (performance problem) heavy use of strstr shows up top in profile * only an issue for loopback usage *//* -------------------------------------------------------------------- */#if 'A' != 0x41/* Hmmm... This source code isn't being compiled in ASCII. * In order for data that flows over the network to make * sense, we need to translate to/from ASCII. */#define NOT_ASCII#endif/* affects include files on Solaris */#define BSD_COMP#include "apr.h"#include "apr_signal.h"#include "apr_strings.h"#include "apr_network_io.h"#include "apr_file_io.h"#include "apr_time.h"#include "apr_getopt.h"#include "apr_general.h"#include "apr_lib.h"#include "apr_portable.h"#include "ap_release.h"#include "apr_poll.h"#define APR_WANT_STRFUNC#include "apr_want.h"#include "apr_base64.h"#ifdef NOT_ASCII#include "apr_xlate.h"#endif#if APR_HAVE_STDIO_H#include <stdio.h>#endif#if APR_HAVE_STDLIB_H#include <stdlib.h>#ifdef USE_SSL#if ((!(RSAREF)) && (!(SYSSSL)))/* Libraries on most systems.. */#include <openssl/rsa.h>#include <openssl/crypto.h>#include <openssl/x509.h>#include <openssl/pem.h>#include <openssl/err.h>#include <openssl/ssl.h>#include <openssl/rand.h>#else/* Libraries for RSAref and SYSSSL */#include <rsa.h>#include <crypto.h>#include <x509.h>#include <pem.h>#include <err.h>#include <ssl.h>#include <rand.h>#endif#endif#include <math.h>#endif#if APR_HAVE_CTYPE_H#include <ctype.h>#endif/* ------------------- DEFINITIONS -------------------------- */#ifndef LLONG_MAX#define AB_MAX APR_INT64_C(0x7fffffffffffffff)#else#define AB_MAX LLONG_MAX#endif/* maximum number of requests on a time limited test */#define MAX_REQUESTS 50000/* good old state hostname */#define STATE_UNCONNECTED 0#define STATE_CONNECTING 1 /* TCP connect initiated, but we don't * know if it worked yet */#define STATE_CONNECTED 2 /* we know TCP connect completed */#define STATE_READ 3#define CBUFFSIZE (2048)struct connection { apr_pool_t *ctx; apr_socket_t *aprsock; int state; apr_size_t read; /* amount of bytes read */ apr_size_t bread; /* amount of body read */ apr_size_t rwrite, rwrote; /* keep pointers in what we write - across * EAGAINs */ apr_size_t length; /* Content-Length value used for keep-alive */ char cbuff[CBUFFSIZE]; /* a buffer to store server response header */ int cbx; /* offset in cbuffer */ int keepalive; /* non-zero if a keep-alive request */ int gotheader; /* non-zero if we have the entire header in * cbuff */ apr_time_t start, /* Start of connection */ connect, /* Connected, start writing */ endwrite, /* Request written */ beginread, /* First byte of input */ done; /* Connection closed */ int socknum;#ifdef USE_SSL SSL *ssl;#endif};struct data {#ifdef USE_SSL /* XXXX insert SSL timings */#endif int read; /* number of bytes read */ apr_time_t starttime; /* start time of connection in seconds since * Jan. 1, 1970 */ apr_interval_time_t waittime; /* Between writing request and reading * response */ apr_interval_time_t ctime; /* time in ms to connect */ apr_interval_time_t time; /* time in ms for connection */};#define ap_min(a,b) ((a)<(b))?(a):(b)#define ap_max(a,b) ((a)>(b))?(a):(b)#define MAX_CONCURRENCY 20000/* --------------------- GLOBALS ---------------------------- */int verbosity = 0; /* no verbosity by default */int posting = 0; /* GET by default */int requests = 1; /* Number of requests to make */int heartbeatres = 100; /* How often do we say we're alive */int concurrency = 1; /* Number of multiple requests to make */int percentile = 1; /* Show percentile served */int confidence = 1; /* Show confidence estimator and warnings */int tlimit = 0; /* time limit in secs */int keepalive = 0; /* try and do keepalive connections */char servername[1024]; /* name that server reports */char *hostname; /* host name from URL */char *host_field; /* value of "Host:" header field */char *path; /* path name */char postfile[1024]; /* name of file containing post data */char *postdata; /* *buffer containing data from postfile */apr_size_t postlen = 0; /* length of data to be POSTed */char content_type[1024]; /* content type to put in POST header */char *cookie, /* optional cookie line */ *auth, /* optional (basic/uuencoded) auhentication */ *hdrs; /* optional arbitrary headers */apr_port_t port; /* port number */char proxyhost[1024]; /* proxy host name */int proxyport = 0; /* proxy port */char *connecthost;apr_port_t connectport;char *gnuplot; /* GNUplot file */char *csvperc; /* CSV Percentile file */char url[1024];char * fullurl, * colonhost;int isproxy = 0;apr_interval_time_t aprtimeout = apr_time_from_sec(30); /* timeout value */ /* * XXX - this is now a per read/write transact type of value */int use_html = 0; /* use html in the report */const char *tablestring;const char *trstring;const char *tdstring;apr_size_t doclen = 0; /* the length the document should be */long started = 0; /* number of requests started, so no excess */long totalread = 0; /* total number of bytes read */long totalbread = 0; /* totoal amount of entity body read */long totalposted = 0; /* total number of bytes posted, inc. headers */long done = 0; /* number of requests we have done */long doneka = 0; /* number of keep alive connections done */long good = 0, bad = 0; /* number of good and bad requests */long epipe = 0; /* number of broken pipe writes */#ifdef USE_SSLint ssl = 0;SSL_CTX *ctx;BIO *bio_out,*bio_err;static void write_request(struct connection * c);#endif/* store error cases */int err_length = 0, err_conn = 0, err_except = 0;int err_response = 0;apr_time_t start, endtime;/* global request (and its length) */char _request[512];char *request = _request;apr_size_t reqlen;/* one global throw-away buffer to read stuff into */char buffer[8192];/* interesting percentiles */int percs[] = {50, 66, 75, 80, 90, 95, 98, 99, 100};struct connection *con; /* connection array */struct data *stats; /* date for each request */apr_pool_t *cntxt;apr_pollset_t *readbits;apr_sockaddr_t *destsa;#ifdef NOT_ASCIIapr_xlate_t *from_ascii, *to_ascii;#endifstatic void close_connection(struct connection * c);/* --------------------------------------------------------- *//* simple little function to write an error string and exit */static void err(char *s){ fprintf(stderr, "%s\n", s); if (done) printf("Total of %ld requests completed\n" , done); exit(1);}/* simple little function to write an APR error string and exit */static void apr_err(char *s, apr_status_t rv){ char buf[120]; fprintf(stderr, "%s: %s (%d)\n", s, apr_strerror(rv, buf, sizeof buf), rv); if (done) printf("Total of %ld requests completed\n" , done); exit(rv);}#if defined(USE_SSL) && USE_THREADS/* * To ensure thread-safetyness in OpenSSL - work in progress */static apr_thread_mutex_t **lock_cs;static int lock_num_locks;static void ssl_util_thr_lock(int mode, int type, const char *file, int line){ if (type < lock_num_locks) { if (mode & CRYPTO_LOCK) { apr_thread_mutex_lock(lock_cs[type]); } else { apr_thread_mutex_unlock(lock_cs[type]); } }}static unsigned long ssl_util_thr_id(void){ /* OpenSSL needs this to return an unsigned long. On OS/390, the pthread * id is a structure twice that big. Use the TCB pointer instead as a * unique unsigned long. */#ifdef __MVS__ struct PSA { char unmapped[540]; unsigned long PSATOLD; } *psaptr = 0; return psaptr->PSATOLD;#else return (unsigned long) apr_os_thread_current();#endif}static apr_status_t ssl_util_thread_cleanup(void *data){ CRYPTO_set_locking_callback(NULL); /* Let the registered mutex cleanups do their own thing */ return APR_SUCCESS;}void ssl_util_thread_setup(apr_pool_t *p){ int i; lock_num_locks = CRYPTO_num_locks(); lock_cs = apr_palloc(p, lock_num_locks * sizeof(*lock_cs)); for (i = 0; i < lock_num_locks; i++) { apr_thread_mutex_create(&(lock_cs[i]), APR_THREAD_MUTEX_DEFAULT, p); } CRYPTO_set_id_callback(ssl_util_thr_id); CRYPTO_set_locking_callback(ssl_util_thr_lock); apr_pool_cleanup_register(p, NULL, ssl_util_thread_cleanup, apr_pool_cleanup_null);}#endif/* --------------------------------------------------------- *//* write out request to a connection - assumes we can write * (small) request out in one go into our new socket buffer * */#ifdef USE_SSLlong ssl_print_cb(BIO *bio,int cmd,const char *argp,int argi,long argl,long ret){ BIO *out; out=(BIO *)BIO_get_callback_arg(bio); if (out == NULL) return(ret); if (cmd == (BIO_CB_READ|BIO_CB_RETURN)) { BIO_printf(out,"read from %08X [%08lX] (%d bytes => %ld (0x%X))\n", bio,argp,argi,ret,ret);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -