Merge in atomic counter updates and some cleanup from trunk.

This commit is contained in:
b1v1r
2009-03-06 04:53:40 +00:00
parent 0acef426d5
commit a78d2613c3
9 changed files with 296 additions and 42 deletions

View File

@@ -91,7 +91,7 @@ static apr_table_t *collection_unpack(modsec_rec *msr, const unsigned char *blob
/**
*
*/
apr_table_t *collection_retrieve(modsec_rec *msr, const char *col_name,
static apr_table_t *collection_retrieve_ex(apr_sdbm_t *existing_dbm, modsec_rec *msr, const char *col_name,
const char *col_key, int col_key_len)
{
char *dbm_filename = NULL;
@@ -117,17 +117,19 @@ apr_table_t *collection_retrieve(modsec_rec *msr, const char *col_name,
key.dptr = (char *)col_key;
key.dsize = col_key_len + 1;
rc = apr_sdbm_open(&dbm, dbm_filename, APR_READ | APR_SHARELOCK,
CREATEMODE, msr->mp);
if (rc != APR_SUCCESS) {
return NULL;
if (existing_dbm == NULL) {
rc = apr_sdbm_open(&dbm, dbm_filename, APR_READ | APR_SHARELOCK,
CREATEMODE, msr->mp);
if (rc != APR_SUCCESS) {
return NULL;
}
}
else {
dbm = existing_dbm;
}
value = (apr_sdbm_datum_t *)apr_pcalloc(msr->mp, sizeof(apr_sdbm_datum_t));
rc = apr_sdbm_fetch(dbm, value, key);
apr_sdbm_close(dbm);
if (rc != APR_SUCCESS) {
msr_log(msr, 1, "Failed to read from DBM file \"%s\": %s", log_escape(msr->mp,
dbm_filename), get_apr_error(msr->mp, rc));
@@ -139,7 +141,7 @@ apr_table_t *collection_retrieve(modsec_rec *msr, const char *col_name,
}
/* ENH Need expiration (and perhaps other metadata) accessible in blob
* form so we can determine if we need to convert to a table. This will
* form to determine if converting to a table is needed. This will
* save some cycles.
*/
@@ -147,6 +149,11 @@ apr_table_t *collection_retrieve(modsec_rec *msr, const char *col_name,
col = collection_unpack(msr, (const unsigned char *)value->dptr, value->dsize, 1);
if (col == NULL) return NULL;
/* Close after "value" used from fetch or memory may be overwritten. */
if (existing_dbm == NULL) {
apr_sdbm_close(dbm);
}
/* Remove expired variables. */
do {
arr = apr_table_elts(col);
@@ -181,22 +188,24 @@ apr_table_t *collection_retrieve(modsec_rec *msr, const char *col_name,
/* Delete the collection if the variable "KEY" does not exist.
*
* ENH It would probably be more efficient to hold the DBM
* open until we determine if it needs deleted than to open a second
* open until determined if it needs deleted than to open a second
* time.
*/
if (apr_table_get(col, "KEY") == NULL) {
rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK,
CREATEMODE, msr->mp);
if (rc != APR_SUCCESS) {
msr_log(msr, 1, "Failed to access DBM file \"%s\": %s",
log_escape(msr->mp, dbm_filename), get_apr_error(msr->mp, rc));
return NULL;
if (existing_dbm == NULL) {
rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK,
CREATEMODE, msr->mp);
if (rc != APR_SUCCESS) {
msr_log(msr, 1, "Failed to access DBM file \"%s\": %s",
log_escape(msr->mp, dbm_filename), get_apr_error(msr->mp, rc));
return NULL;
}
}
else {
dbm = existing_dbm;
}
rc = apr_sdbm_delete(dbm, key);
apr_sdbm_close(dbm);
if (rc != APR_SUCCESS) {
msr_log(msr, 1, "Failed deleting collection (name \"%s\", "
"key \"%s\"): %s", log_escape(msr->mp, col_name),
@@ -204,6 +213,11 @@ apr_table_t *collection_retrieve(modsec_rec *msr, const char *col_name,
return NULL;
}
if (existing_dbm == NULL) {
apr_sdbm_close(dbm);
}
if (expired && (msr->txcfg->debuglog_level >= 9)) {
msr_log(msr, 9, "Collection expired (name \"%s\", key \"%s\").", col_name, log_escape_ex(msr->mp, col_key, col_key_len));
}
@@ -231,7 +245,7 @@ apr_table_t *collection_retrieve(modsec_rec *msr, const char *col_name,
apr_time_t td;
counter = atoi(var->value);
/* UPDATE_RATE is removed on store, so we add it back here */
/* UPDATE_RATE is removed on store, so add it back here */
var = (msc_string *)apr_pcalloc(msr->mp, sizeof(msc_string));
var->name = "UPDATE_RATE";
var->name_len = strlen(var->name);
@@ -259,6 +273,15 @@ apr_table_t *collection_retrieve(modsec_rec *msr, const char *col_name,
return col;
}
/**
*
*/
apr_table_t *collection_retrieve(modsec_rec *msr, const char *col_name,
const char *col_key, int col_key_len) {
return collection_retrieve_ex(NULL, msr, col_name, col_key, col_key_len);
}
/**
*
*/
@@ -274,6 +297,8 @@ int collection_store(modsec_rec *msr, apr_table_t *col) {
const apr_array_header_t *arr;
apr_table_entry_t *te;
int i;
const apr_table_t *stored_col = NULL;
const apr_table_t *orig_col = NULL;
var_name = (msc_string *)apr_table_get(col, "__name");
if (var_name == NULL) {
@@ -347,7 +372,35 @@ int collection_store(modsec_rec *msr, apr_table_t *col) {
* convert back to table form
*/
/* Calculate the size first. */
rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK,
CREATEMODE, msr->mp);
if (rc != APR_SUCCESS) {
msr_log(msr, 1, "Failed to access DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename),
get_apr_error(msr->mp, rc));
return -1;
}
/* Only need to lock to pull in the stored data again. */
rc = apr_sdbm_lock(dbm, APR_FLOCK_EXCLUSIVE);
if (rc != APR_SUCCESS) {
msr_log(msr, 1, "Failed to exclusivly lock DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename),
get_apr_error(msr->mp, rc));
apr_sdbm_close(dbm);
return -1;
}
/* If there is an original value, then create a delta and
* apply the delta to the current value */
orig_col = (const apr_table_t *)apr_table_get(msr->collections_original, var_name->value);
if (orig_col != NULL) {
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "Re-retrieving collection prior to store: %s", apr_psprintf(msr->mp, "%.*s", var_name->value_len, var_name->value));
}
stored_col = (const apr_table_t *)collection_retrieve_ex(dbm, msr, var_name->value, var_key->value, var_key->value_len);
}
/* Merge deltas and calculate the size first. */
blob_size = 3 + 2;
arr = apr_table_elts(col);
te = (apr_table_entry_t *)arr->elts;
@@ -355,6 +408,33 @@ int collection_store(modsec_rec *msr, apr_table_t *col) {
msc_string *var = (msc_string *)te[i].val;
int len;
/* If there is an original value, then apply the delta
* to the latest stored value */
if (stored_col != NULL) {
const msc_string *orig_var = (const msc_string *)apr_table_get(orig_col, var->name);
if (orig_var != NULL) {
const msc_string *stored_var = (const msc_string *)apr_table_get(stored_col, var->name);
if (stored_var != NULL) {
int origval = atoi(orig_var->value);
int ourval = atoi(var->value);
int storedval = atoi(stored_var->value);
int delta = ourval - origval;
int value = storedval + delta;
if (value < 0) value = 0; /* Counters never go below zero. */
var->value = apr_psprintf(msr->mp, "%d", value);
var->value_len = strlen(var->value);
if (msr->txcfg->debuglog_level >= 9) {
msr_log(msr, 9, "Delta applied for %s.%s %d->%d (%d): %d + (%d) = %d [%s,%d]",
log_escape_ex(msr->mp, var_name->value, var_name->value_len),
log_escape_ex(msr->mp, var->name, var->name_len),
origval, ourval, delta, storedval, delta, value, var->value, var->value_len);
}
}
}
}
len = var->name_len + 1;
if (len >= 65536) len = 65536;
blob_size += len + 2;
@@ -418,24 +498,17 @@ int collection_store(modsec_rec *msr, apr_table_t *col) {
value.dptr = (char *)blob;
value.dsize = blob_size;
rc = apr_sdbm_open(&dbm, dbm_filename, APR_CREATE | APR_WRITE | APR_SHARELOCK,
CREATEMODE, msr->mp);
if (rc != APR_SUCCESS) {
msr_log(msr, 1, "Failed to access DBM file \"%s\": %s", log_escape(msr->mp, dbm_filename),
get_apr_error(msr->mp, rc));
return -1;
}
rc = apr_sdbm_store(dbm, key, value, APR_SDBM_REPLACE);
apr_sdbm_close(dbm);
if (rc != APR_SUCCESS) {
msr_log(msr, 1, "Failed to write to DBM file \"%s\": %s", dbm_filename,
get_apr_error(msr->mp, rc));
return -1;
}
/* ENH: Do we need to unlock()? Or will just close() suffice? */
apr_sdbm_unlock(dbm);
apr_sdbm_close(dbm);
if (msr->txcfg->debuglog_level >= 4) {
msr_log(msr, 4, "Persisted collection (name \"%s\", key \"%s\").",
log_escape_ex(msr->mp, var_name->value, var_name->value_len), log_escape_ex(msr->mp, var_key->value, var_key->value_len));
@@ -485,8 +558,8 @@ int collections_remove_stale(modsec_rec *msr, const char *col_name) {
return -1;
}
/* No one can write to the file while we're
* doing this so let's do it as fast as we can.
/* No one can write to the file while doing this so
* do it as fast as possible.
*/
rc = apr_sdbm_firstkey(dbm, &key);
while(rc == APR_SUCCESS) {