1
0
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:
Stefan Fritsch
2011-09-15 19:53:59 +00:00
parent 7f59e98923
commit 2d4e23d88b
8 changed files with 120 additions and 70 deletions

View File

@@ -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.

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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;
} }

View File

@@ -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 *);

View File

@@ -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,

View File

@@ -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 */