mirror of
https://github.com/apache/httpd.git
synced 2025-11-09 15:21:02 +03:00
Create wrapper API for apr_random;
use in mod_lbmethod_heartbeat and mod_serf to - replace some needles use of apr_generate_random_bytes - remove code duplication git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1171247 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
2
CHANGES
2
CHANGES
@@ -12,6 +12,8 @@ Changes with Apache 2.3.15
|
|||||||
PR 51714. [Stefan Fritsch, Jim Jagielski, Ruediger Pluem, Eric Covener,
|
PR 51714. [Stefan Fritsch, Jim Jagielski, Ruediger Pluem, Eric Covener,
|
||||||
<lowprio20 gmail.com>]
|
<lowprio20 gmail.com>]
|
||||||
|
|
||||||
|
*) core: Add convenience API for apr_random. [Stefan Fritsch]
|
||||||
|
|
||||||
*) core: Add MaxRangeOverlaps and MaxRangeReversals directives to control
|
*) core: Add MaxRangeOverlaps and MaxRangeReversals directives to control
|
||||||
the number of overlapping and reversing ranges (respectively) permitted
|
the number of overlapping and reversing ranges (respectively) permitted
|
||||||
before returning the entire resource, with a default limit of 20.
|
before returning the entire resource, with a default limit of 20.
|
||||||
|
|||||||
@@ -351,6 +351,7 @@
|
|||||||
* 20110724.4 (2.3.15-dev) add max_ranges to core_dir_config
|
* 20110724.4 (2.3.15-dev) add max_ranges to core_dir_config
|
||||||
* 20110724.5 (2.3.15-dev) add ap_set_accept_ranges()
|
* 20110724.5 (2.3.15-dev) add ap_set_accept_ranges()
|
||||||
* 20110724.6 (2.3.15-dev) add max_overlaps and max_reversals to core_dir_config
|
* 20110724.6 (2.3.15-dev) add max_overlaps and max_reversals to core_dir_config
|
||||||
|
* 20110724.7 (2.3.15-dev) add ap_random_insecure_bytes(), ap_random_pick()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define MODULE_MAGIC_COOKIE 0x41503234UL /* "AP24" */
|
#define MODULE_MAGIC_COOKIE 0x41503234UL /* "AP24" */
|
||||||
@@ -358,7 +359,7 @@
|
|||||||
#ifndef MODULE_MAGIC_NUMBER_MAJOR
|
#ifndef MODULE_MAGIC_NUMBER_MAJOR
|
||||||
#define MODULE_MAGIC_NUMBER_MAJOR 20110724
|
#define MODULE_MAGIC_NUMBER_MAJOR 20110724
|
||||||
#endif
|
#endif
|
||||||
#define MODULE_MAGIC_NUMBER_MINOR 6 /* 0...n */
|
#define MODULE_MAGIC_NUMBER_MINOR 7 /* 0...n */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine if the server's current MODULE_MAGIC_NUMBER is at least a
|
* Determine if the server's current MODULE_MAGIC_NUMBER is at least a
|
||||||
|
|||||||
@@ -2067,6 +2067,26 @@ AP_DECLARE(const char *) ap_strstr_c(const char *s, const char *c);
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate pseudo random bytes.
|
||||||
|
* This is a convenience interface to apr_random. It is cheaper but less
|
||||||
|
* secure than apr_generate_random_bytes().
|
||||||
|
* @param buf where to store the bytes
|
||||||
|
* @param size number of bytes to generate
|
||||||
|
* @note ap_random_insecure_bytes() is thread-safe, it uses a mutex on
|
||||||
|
* threaded MPMs.
|
||||||
|
*/
|
||||||
|
APR_DECLARE(void) ap_random_insecure_bytes(void *buf, apr_size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a pseudo random number in a range.
|
||||||
|
* @param min low end of range
|
||||||
|
* @param max high end of range
|
||||||
|
* @return a number in the range
|
||||||
|
*/
|
||||||
|
APR_DECLARE(apr_uint32_t) ap_random_pick(apr_uint32_t min, apr_uint32_t max);
|
||||||
|
|
||||||
|
|
||||||
#define AP_NORESTART APR_OS_START_USEERR + 1
|
#define AP_NORESTART APR_OS_START_USEERR + 1
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|||||||
@@ -87,6 +87,9 @@ AP_DECLARE_NONSTD(int) ap_send_http_trace(request_rec *r);
|
|||||||
*/
|
*/
|
||||||
AP_DECLARE(int) ap_send_http_options(request_rec *r);
|
AP_DECLARE(int) ap_send_http_options(request_rec *r);
|
||||||
|
|
||||||
|
/* Used for multipart/byteranges boundary string */
|
||||||
|
extern AP_DECLARE_DATA const char *ap_multipart_boundary;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ AP_DECLARE_DATA ap_filter_rec_t *ap_chunk_filter_handle;
|
|||||||
AP_DECLARE_DATA ap_filter_rec_t *ap_http_outerror_filter_handle;
|
AP_DECLARE_DATA ap_filter_rec_t *ap_http_outerror_filter_handle;
|
||||||
AP_DECLARE_DATA ap_filter_rec_t *ap_byterange_filter_handle;
|
AP_DECLARE_DATA ap_filter_rec_t *ap_byterange_filter_handle;
|
||||||
|
|
||||||
|
AP_DECLARE_DATA const char *ap_multipart_boundary;
|
||||||
|
|
||||||
/* If we are using an MPM That Supports Async Connections,
|
/* If we are using an MPM That Supports Async Connections,
|
||||||
* use a different processing function
|
* use a different processing function
|
||||||
*/
|
*/
|
||||||
@@ -255,9 +257,13 @@ static int http_send_options(request_rec *r)
|
|||||||
|
|
||||||
static int http_post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
|
static int http_post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
|
||||||
{
|
{
|
||||||
|
apr_uint64_t val;
|
||||||
if (ap_mpm_query(AP_MPMQ_IS_ASYNC, &async_mpm) != APR_SUCCESS) {
|
if (ap_mpm_query(AP_MPMQ_IS_ASYNC, &async_mpm) != APR_SUCCESS) {
|
||||||
async_mpm = 0;
|
async_mpm = 0;
|
||||||
}
|
}
|
||||||
|
ap_random_insecure_bytes(&val, sizeof(val));
|
||||||
|
ap_multipart_boundary = apr_psprintf(p, "%0" APR_UINT64_T_HEX_FMT, val);
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -253,36 +253,6 @@ static apr_status_t read_heartbeats(const char *path, apr_hash_t *servers,
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Finding a random number in a range.
|
|
||||||
* n' = a + n(b-a+1)/(M+1)
|
|
||||||
* where:
|
|
||||||
* n' = random number in range
|
|
||||||
* a = low end of range
|
|
||||||
* b = high end of range
|
|
||||||
* n = random number of 0..M
|
|
||||||
* M = maxint
|
|
||||||
* Algorithm 'borrowed' from PHP's rand() function.
|
|
||||||
*/
|
|
||||||
#define RAND_RANGE(__n, __min, __max, __tmax) \
|
|
||||||
(__n) = (__min) + (long) ((double) ((__max) - (__min) + 1.0) * ((__n) / ((__tmax) + 1.0)))
|
|
||||||
|
|
||||||
static apr_status_t random_pick(apr_uint32_t *number,
|
|
||||||
apr_uint32_t min,
|
|
||||||
apr_uint32_t max)
|
|
||||||
{
|
|
||||||
apr_status_t rv =
|
|
||||||
apr_generate_random_bytes((void*)number, sizeof(apr_uint32_t));
|
|
||||||
|
|
||||||
if (rv) {
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
RAND_RANGE(*number, min, max, APR_UINT32_MAX);
|
|
||||||
|
|
||||||
return APR_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static proxy_worker *find_best_hb(proxy_balancer *balancer,
|
static proxy_worker *find_best_hb(proxy_balancer *balancer,
|
||||||
request_rec *r)
|
request_rec *r)
|
||||||
{
|
{
|
||||||
@@ -343,14 +313,7 @@ static proxy_worker *find_best_hb(proxy_balancer *balancer,
|
|||||||
apr_uint32_t c = 0;
|
apr_uint32_t c = 0;
|
||||||
apr_uint32_t pick = 0;
|
apr_uint32_t pick = 0;
|
||||||
|
|
||||||
rv = random_pick(&pick, 0, openslots);
|
pick = ap_random_pick(0, openslots);
|
||||||
|
|
||||||
if (rv) {
|
|
||||||
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
|
|
||||||
"lb_heartbeat: failed picking a random number. how random.");
|
|
||||||
apr_pool_destroy(tpool);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < up_servers->nelts; i++) {
|
for (i = 0; i < up_servers->nelts; i++) {
|
||||||
server = APR_ARRAY_IDX(up_servers, i, hb_server_t *);
|
server = APR_ARRAY_IDX(up_servers, i, hb_server_t *);
|
||||||
|
|||||||
@@ -399,35 +399,6 @@ static apr_status_t setup_request(serf_request_t *request,
|
|||||||
return APR_SUCCESS;
|
return APR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Finding a random number in a range.
|
|
||||||
* n' = a + n(b-a+1)/(M+1)
|
|
||||||
* where:
|
|
||||||
* n' = random number in range
|
|
||||||
* a = low end of range
|
|
||||||
* b = high end of range
|
|
||||||
* n = random number of 0..M
|
|
||||||
* M = maxint
|
|
||||||
* Algorithm 'borrowed' from PHP's rand() function. (See mod_lbmethod_heartbeat.c).
|
|
||||||
*/
|
|
||||||
#define RAND_RANGE(__n, __min, __max, __tmax) \
|
|
||||||
(__n) = (__min) + (long) ((double) ((__max) - (__min) + 1.0) * ((__n) / ((__tmax) + 1.0)))
|
|
||||||
|
|
||||||
static apr_status_t random_pick(apr_uint32_t *number,
|
|
||||||
apr_uint32_t min,
|
|
||||||
apr_uint32_t max)
|
|
||||||
{
|
|
||||||
apr_status_t rv =
|
|
||||||
apr_generate_random_bytes((void*)number, sizeof(apr_uint32_t));
|
|
||||||
|
|
||||||
if (rv) {
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
RAND_RANGE(*number, min, max, APR_UINT32_MAX);
|
|
||||||
|
|
||||||
return APR_SUCCESS;
|
|
||||||
}
|
|
||||||
/* TOOD: rewrite drive_serf to make it async */
|
/* TOOD: rewrite drive_serf to make it async */
|
||||||
static int drive_serf(request_rec *r, serf_config_t *conf)
|
static int drive_serf(request_rec *r, serf_config_t *conf)
|
||||||
{
|
{
|
||||||
@@ -499,8 +470,7 @@ static int drive_serf(request_rec *r, serf_config_t *conf)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* TOOD: restructure try all servers in the array !! */
|
/* TOOD: restructure try all servers in the array !! */
|
||||||
if (random_pick(&pick, 0, servers->nelts-1) != APR_SUCCESS)
|
pick = ap_random_pick(0, servers->nelts-1);
|
||||||
pick = 0;
|
|
||||||
choice = APR_ARRAY_IDX(servers, pick, ap_serf_server_t *);
|
choice = APR_ARRAY_IDX(servers, pick, ap_serf_server_t *);
|
||||||
|
|
||||||
rv = apr_sockaddr_info_get(&address, choice->ip,
|
rv = apr_sockaddr_info_get(&address, choice->ip,
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#include "apr_fnmatch.h"
|
#include "apr_fnmatch.h"
|
||||||
#include "apr_hash.h"
|
#include "apr_hash.h"
|
||||||
#include "apr_thread_proc.h" /* for RLIMIT stuff */
|
#include "apr_thread_proc.h" /* for RLIMIT stuff */
|
||||||
|
#include "apr_random.h"
|
||||||
|
|
||||||
#define APR_WANT_IOVEC
|
#define APR_WANT_IOVEC
|
||||||
#define APR_WANT_STRFUNC
|
#define APR_WANT_STRFUNC
|
||||||
@@ -4593,12 +4594,93 @@ AP_DECLARE(int) ap_state_query(int query)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static apr_random_t *rng = NULL;
|
||||||
|
#if APR_HAS_THREADS
|
||||||
|
static apr_thread_mutex_t *rng_mutex = NULL;
|
||||||
|
|
||||||
|
static void create_rng_mutex(apr_pool_t *pchild, server_rec *s)
|
||||||
|
{
|
||||||
|
int threaded_mpm;
|
||||||
|
if (ap_mpm_query(AP_MPMQ_IS_THREADED, &threaded_mpm) != APR_SUCCESS)
|
||||||
|
return;
|
||||||
|
if (threaded_mpm)
|
||||||
|
apr_thread_mutex_create(&rng_mutex, APR_THREAD_MUTEX_DEFAULT, pchild);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void rng_init(apr_pool_t *p)
|
||||||
|
{
|
||||||
|
unsigned char seed[8];
|
||||||
|
apr_status_t rv;
|
||||||
|
rng = apr_random_standard_new(p);
|
||||||
|
do {
|
||||||
|
rv = apr_generate_random_bytes(seed, sizeof(seed));
|
||||||
|
if (rv != APR_SUCCESS)
|
||||||
|
goto error;
|
||||||
|
apr_random_add_entropy(rng, seed, sizeof(seed));
|
||||||
|
rv = apr_random_insecure_ready(rng);
|
||||||
|
} while (rv == APR_ENOTENOUGHENTROPY);
|
||||||
|
if (rv == APR_SUCCESS)
|
||||||
|
return;
|
||||||
|
error:
|
||||||
|
ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL,
|
||||||
|
"Could not initialize random number generator");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
APR_DECLARE(void) ap_random_insecure_bytes(void *buf, apr_size_t size)
|
||||||
|
{
|
||||||
|
#if APR_HAS_THREADS
|
||||||
|
if (rng_mutex)
|
||||||
|
apr_thread_mutex_lock(rng_mutex);
|
||||||
|
#endif
|
||||||
|
/* apr_random_insecure_bytes can only fail with APR_ENOTENOUGHENTROPY,
|
||||||
|
* and we have ruled that out during initialization. Therefore we don't
|
||||||
|
* need to check the return code.
|
||||||
|
*/
|
||||||
|
apr_random_insecure_bytes(rng, buf, size);
|
||||||
|
#if APR_HAS_THREADS
|
||||||
|
if (rng_mutex)
|
||||||
|
apr_thread_mutex_unlock(rng_mutex);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Finding a random number in a range.
|
||||||
|
* n' = a + n(b-a+1)/(M+1)
|
||||||
|
* where:
|
||||||
|
* n' = random number in range
|
||||||
|
* a = low end of range
|
||||||
|
* b = high end of range
|
||||||
|
* n = random number of 0..M
|
||||||
|
* M = maxint
|
||||||
|
* Algorithm 'borrowed' from PHP's rand() function.
|
||||||
|
*/
|
||||||
|
#define RAND_RANGE(__n, __min, __max, __tmax) \
|
||||||
|
(__n) = (__min) + (long) ((double) ((__max) - (__min) + 1.0) * ((__n) / ((__tmax) + 1.0)))
|
||||||
|
APR_DECLARE(apr_uint32_t) ap_random_pick(apr_uint32_t min, apr_uint32_t max)
|
||||||
|
{
|
||||||
|
apr_uint32_t number;
|
||||||
|
if (max < 16384) {
|
||||||
|
apr_uint16_t num16;
|
||||||
|
ap_random_insecure_bytes(&num16, sizeof(num16));
|
||||||
|
RAND_RANGE(num16, min, max, APR_UINT16_MAX);
|
||||||
|
number = num16;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ap_random_insecure_bytes(&number, sizeof(number));
|
||||||
|
RAND_RANGE(number, min, max, APR_UINT32_MAX);
|
||||||
|
}
|
||||||
|
return number;
|
||||||
|
}
|
||||||
|
|
||||||
static void register_hooks(apr_pool_t *p)
|
static void register_hooks(apr_pool_t *p)
|
||||||
{
|
{
|
||||||
errorlog_hash = apr_hash_make(p);
|
errorlog_hash = apr_hash_make(p);
|
||||||
ap_register_log_hooks(p);
|
ap_register_log_hooks(p);
|
||||||
ap_register_config_hooks(p);
|
ap_register_config_hooks(p);
|
||||||
ap_expr_init(p);
|
ap_expr_init(p);
|
||||||
|
rng_init(p);
|
||||||
|
|
||||||
/* create_connection and pre_connection should always be hooked
|
/* create_connection and pre_connection should always be hooked
|
||||||
* APR_HOOK_REALLY_LAST by core to give other modules the opportunity
|
* APR_HOOK_REALLY_LAST by core to give other modules the opportunity
|
||||||
@@ -4615,6 +4697,9 @@ static void register_hooks(apr_pool_t *p)
|
|||||||
ap_hook_translate_name(ap_core_translate,NULL,NULL,APR_HOOK_REALLY_LAST);
|
ap_hook_translate_name(ap_core_translate,NULL,NULL,APR_HOOK_REALLY_LAST);
|
||||||
ap_hook_map_to_storage(core_map_to_storage,NULL,NULL,APR_HOOK_REALLY_LAST);
|
ap_hook_map_to_storage(core_map_to_storage,NULL,NULL,APR_HOOK_REALLY_LAST);
|
||||||
ap_hook_open_logs(ap_open_logs,NULL,NULL,APR_HOOK_REALLY_FIRST);
|
ap_hook_open_logs(ap_open_logs,NULL,NULL,APR_HOOK_REALLY_FIRST);
|
||||||
|
#if APR_HAS_THREADS
|
||||||
|
ap_hook_child_init(create_rng_mutex,NULL,NULL,APR_HOOK_REALLY_FIRST);
|
||||||
|
#endif
|
||||||
ap_hook_child_init(ap_logs_child_init,NULL,NULL,APR_HOOK_MIDDLE);
|
ap_hook_child_init(ap_logs_child_init,NULL,NULL,APR_HOOK_MIDDLE);
|
||||||
ap_hook_handler(default_handler,NULL,NULL,APR_HOOK_REALLY_LAST);
|
ap_hook_handler(default_handler,NULL,NULL,APR_HOOK_REALLY_LAST);
|
||||||
/* FIXME: I suspect we can eliminate the need for these do_nothings - Ben */
|
/* FIXME: I suspect we can eliminate the need for these do_nothings - Ben */
|
||||||
|
|||||||
Reference in New Issue
Block a user