--- httpd-2.4.25/docs/man/ab.1.ab_source_address.droplet 2015-05-07 19:25:55.000000000 +0300 +++ httpd-2.4.25/docs/man/ab.1 2016-12-24 15:52:56.742805956 +0200 @@ -113,40 +113,43 @@ Content-type header to use for POST/PUT data, eg\&. application/x-www-form-urlencoded\&. Default is text/plain\&. .TP -u \fIPUT-file\fR File containing data to PUT\&. Remember to also set -T\&. .TP -v \fIverbosity\fR Set verbosity level - 4 and above prints information on headers, 3 and above prints response codes (404, 200, etc\&.), 2 and above prints warnings and info\&. .TP -V Display version number and exit\&. .TP -w Print out results in HTML tables\&. Default table is two columns wide, with a white background\&. .TP -x \fI<table>-attributes\fR String to use as attributes for <table>\&. Attributes are inserted <table \fIhere\fR >\&. .TP -X \fIproxy\fR[:\fIport\fR] Use a proxy server for the requests\&. .TP +-o \fIsrc_address\fR +Set the local source address\&. +.TP -y \fI<tr>-attributes\fR String to use as attributes for <tr>\&. .TP -z \fI<td>-attributes\fR String to use as attributes for <td>\&. .TP -Z \fIciphersuite\fR Specify SSL/TLS cipher suite (See openssl ciphers) .SH "OUTPUT" .PP The following list describes the values returned by ab: .TP Server Software The value, if any, returned in the \fIserver\fR HTTP header of the first successful response\&. This includes all characters in the header from beginning to the point a character with decimal value of 32 (most notably: a space or CR/LF) is detected\&. .TP Server Hostname --- httpd-2.4.25/support/ab.c.ab_source_address.droplet 2016-08-25 15:53:03.000000000 +0300 +++ httpd-2.4.25/support/ab.c 2016-12-24 15:54:25.055836668 +0200 @@ -288,40 +288,41 @@ int confidence = 1; /* Show confidence estimator and warnings */ int tlimit = 0; /* time limit in secs */ int keepalive = 0; /* try and do keepalive connections */ int windowsize = 0; /* we use the OS default window size */ char servername[1024]; /* name that server reports */ char *hostname; /* host name from URL */ const char *host_field; /* value of "Host:" header field */ const char *path; /* path name */ char *postdata; /* *buffer containing data from postfile */ apr_size_t postlen = 0; /* length of data to be POSTed */ char *content_type = NULL; /* content type to put in POST header */ const char *cookie, /* optional cookie line */ *auth, /* optional (basic/uuencoded) auhentication */ *hdrs; /* optional arbitrary headers */ apr_port_t port; /* port number */ char *proxyhost = NULL; /* proxy host name */ int proxyport = 0; /* proxy port */ const char *connecthost; const char *myhost; apr_port_t connectport; +char *src_address; const char *gnuplot; /* GNUplot file */ const char *csvperc; /* CSV Percentile file */ const char *fullurl; const char *colonhost; int isproxy = 0; apr_interval_time_t aprtimeout = apr_time_from_sec(30); /* timeout value */ /* overrides for ab-generated common headers */ const char *opt_host; /* which optional "Host:" header specified, if any */ int opt_useragent = 0; /* was an optional "User-Agent:" header specified? */ int opt_accept = 0; /* was an optional "Accept:" header specified? */ /* * 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; @@ -1258,40 +1259,41 @@ "<td %s>%5" APR_TIME_T_FMT "</td></tr>\n", trstring, tdstring, tdstring, mintot - mincon, tdstring, (total / done) - (totalcon / done), tdstring, maxtot - maxcon); printf("<tr %s><th %s>Total:</th>" "<td %s>%5" APR_TIME_T_FMT "</td>" "<td %s>%5" APR_TIME_T_FMT "</td>" "<td %s>%5" APR_TIME_T_FMT "</td></tr>\n", trstring, tdstring, tdstring, mintot, tdstring, total / done, tdstring, maxtot); } printf("</table>\n"); } } /* --------------------------------------------------------- */ /* start asnchronous non-blocking connection */ static void start_connect(struct connection * c) { apr_status_t rv; + apr_sockaddr_t *from; if (!(started < requests)) return; c->read = 0; c->bread = 0; c->keepalive = 0; c->cbx = 0; c->gotheader = 0; c->rwrite = 0; if (c->ctx) apr_pool_clear(c->ctx); else apr_pool_create(&c->ctx, cntxt); if ((rv = apr_socket_create(&c->aprsock, destsa->family, SOCK_STREAM, 0, c->ctx)) != APR_SUCCESS) { apr_err("socket", rv); } @@ -1307,40 +1309,48 @@ c->pollfd.client_data = c; if ((rv = apr_socket_opt_set(c->aprsock, APR_SO_NONBLOCK, 1)) != APR_SUCCESS) { apr_err("socket nonblock", rv); } if (windowsize != 0) { rv = apr_socket_opt_set(c->aprsock, APR_SO_SNDBUF, windowsize); if (rv != APR_SUCCESS && rv != APR_ENOTIMPL) { apr_err("socket send buffer", rv); } rv = apr_socket_opt_set(c->aprsock, APR_SO_RCVBUF, windowsize); if (rv != APR_SUCCESS && rv != APR_ENOTIMPL) { apr_err("socket receive buffer", rv); } } + if (src_address) { + if ((rv = apr_sockaddr_info_get(&from, src_address, destsa->family, + 0, 0, c->ctx)) != APR_SUCCESS) + apr_err("src_address get", rv); + if ((rv = apr_socket_bind(c->aprsock, from)) != APR_SUCCESS) + apr_err("src_address bind", rv); + } + c->start = lasttime = apr_time_now(); #ifdef USE_SSL if (is_ssl) { BIO *bio; apr_os_sock_t fd; if ((c->ssl = SSL_new(ssl_ctx)) == NULL) { BIO_printf(bio_err, "SSL_new failed.\n"); ERR_print_errors(bio_err); exit(1); } ssl_rand_seed(); apr_os_sock_get(&fd, c->aprsock); bio = BIO_new_socket(fd, BIO_NOCLOSE); SSL_set_bio(c->ssl, bio, bio); SSL_set_connect_state(c->ssl); if (verbosity >= 4) { BIO_set_callback(bio, ssl_print_cb); BIO_set_callback_arg(bio, (void *)bio_err); } @@ -1990,40 +2000,41 @@ fprintf(stderr, " -B address Address to bind to when making outgoing connections\n"); fprintf(stderr, " -p postfile File containing data to POST. Remember also to set -T\n"); fprintf(stderr, " -u putfile File containing data to PUT. Remember also to set -T\n"); fprintf(stderr, " -T content-type Content-type header to use for POST/PUT data, eg.\n"); fprintf(stderr, " 'application/x-www-form-urlencoded'\n"); fprintf(stderr, " Default is 'text/plain'\n"); fprintf(stderr, " -v verbosity How much troubleshooting info to print\n"); fprintf(stderr, " -w Print out results in HTML tables\n"); fprintf(stderr, " -i Use HEAD instead of GET\n"); fprintf(stderr, " -x attributes String to insert as table attributes\n"); fprintf(stderr, " -y attributes String to insert as tr attributes\n"); fprintf(stderr, " -z attributes String to insert as td or th attributes\n"); fprintf(stderr, " -C attribute Add cookie, eg. 'Apache=1234'. (repeatable)\n"); fprintf(stderr, " -H attribute Add Arbitrary header line, eg. 'Accept-Encoding: gzip'\n"); fprintf(stderr, " Inserted after all normal header lines. (repeatable)\n"); fprintf(stderr, " -A attribute Add Basic WWW Authentication, the attributes\n"); fprintf(stderr, " are a colon separated username and password.\n"); fprintf(stderr, " -P attribute Add Basic Proxy Authentication, the attributes\n"); fprintf(stderr, " are a colon separated username and password.\n"); fprintf(stderr, " -X proxy:port Proxyserver and port number to use\n"); + fprintf(stderr, " -o src_address Set the local source address\n"); fprintf(stderr, " -V Print version number and exit\n"); fprintf(stderr, " -k Use HTTP KeepAlive feature\n"); fprintf(stderr, " -d Do not show percentiles served table.\n"); fprintf(stderr, " -S Do not show confidence estimators and warnings.\n"); fprintf(stderr, " -q Do not show progress when doing more than 150 requests\n"); fprintf(stderr, " -l Accept variable document length (use this for dynamic pages)\n"); fprintf(stderr, " -g filename Output collected data to gnuplot format file.\n"); fprintf(stderr, " -e filename Output CSV file with percentages served\n"); fprintf(stderr, " -r Don't exit on socket receive errors.\n"); fprintf(stderr, " -m method Method name\n"); fprintf(stderr, " -h Display usage information (this message)\n"); #ifdef USE_SSL #ifndef OPENSSL_NO_SSL2 #define SSL2_HELP_MSG "SSL2, " #else #define SSL2_HELP_MSG "" #endif #ifndef OPENSSL_NO_SSL3 @@ -2187,55 +2198,58 @@ status = apr_xlate_open(&to_ascii, "ISO-8859-1", APR_DEFAULT_CHARSET, cntxt); if (status) { fprintf(stderr, "apr_xlate_open(to ASCII)->%d\n", status); exit(1); } status = apr_xlate_open(&from_ascii, APR_DEFAULT_CHARSET, "ISO-8859-1", cntxt); if (status) { fprintf(stderr, "apr_xlate_open(from ASCII)->%d\n", status); exit(1); } status = apr_base64init_ebcdic(to_ascii, from_ascii); if (status) { fprintf(stderr, "apr_base64init_ebcdic()->%d\n", status); exit(1); } #endif myhost = NULL; /* 0.0.0.0 or :: */ apr_getopt_init(&opt, cntxt, argc, argv); - while ((status = apr_getopt(opt, "n:c:t:s:b:T:p:u:v:lrkVhwiIx:y:z:C:H:P:A:g:X:de:SqB:m:" + while ((status = apr_getopt(opt, "o:n:c:t:s:b:T:p:u:v:lrkVhwiIx:y:z:C:H:P:A:g:X:de:SqB:m:" #ifdef USE_SSL "Z:f:" #endif ,&c, &opt_arg)) == APR_SUCCESS) { switch (c) { case 'n': requests = atoi(opt_arg); if (requests <= 0) { err("Invalid number of requests\n"); } break; case 'k': keepalive = 1; break; + case 'o': + src_address = strdup(optarg); + break; case 'q': heartbeatres = 0; break; case 'c': concurrency = atoi(opt_arg); break; case 'b': windowsize = atoi(opt_arg); break; case 'i': if (method != NO_METH) err("Cannot mix HEAD with other methods\n"); method = HEAD; break; case 'g': gnuplot = xstrdup(opt_arg); break; case 'd': percentile = 0; break;