/*-
* Copyright (c) 2005 Andrey Simonenko
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY 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.
*/
#include "config.h"
#ifndef lint
static const char rcsid[] ATTR_UNUSED =
"@(#)$Id: ipastat_limits.c,v 1.1.4.2 2007/05/11 16:29:59 simon Exp $";
#endif /* !lint */
#include <stdlib.h>
#include <string.h>
#include <sys/queue.h>
#include <sys/types.h>
#include "ipa_mod.h"
#include "dlapi.h"
#include "confcommon.h"
#include "memfunc.h"
#include "ipastat_log.h"
#include "ipastat_main.h"
#include "ipastat_rules.h"
#include "ipastat_st.h"
int has_opt_limits = 0; /* 1, if -q ... -l ... */
#ifdef WITH_LIMITS
int dynamic_limits = -1; /* dynamic_limits parameter. */
ipa_mzone *limit_mzone; /* Mzone for struct limit{}. */
struct limit *
alloc_limit(void)
{
struct limit *limit;
if ( (limit = mzone_alloc(limit_mzone)) == NULL) {
xlogmsgx(IPA_LOG_ERR, "alloc_limit: mzone_alloc failed");
return NULL;
}
limit->limit_info = NULL;
limit->st_list = NULL;
limit->inited = 0;
return limit;
}
/*
* Return pointer to limit with the given name.
*/
struct limit *
limit_by_name(const struct rule *rule, const char *name)
{
struct limit *limit;
STAILQ_FOREACH(limit, &rule->limits, link)
if (strcmp(name, limit->limit_name) == 0)
return limit;
return NULL;
}
static void
get_min_max_no( const struct opt_limits *opt_limits, u_int *minno,
u_int *maxno)
{
const struct limit *limit;
const struct opt_limit *opt_limit;
*minno = *maxno = STAILQ_FIRST(opt_limits)->limit->limitno;
STAILQ_FOREACH(opt_limit, opt_limits, link) {
limit = opt_limit->limit;
if (*minno > limit->limitno)
*minno = limit->limitno;
if (*maxno < limit->limitno)
*maxno = limit->limitno;
}
}
/*
* Init all limits from one rule in modules.
*/
int
init_limits(const struct opt_rule *opt_rule)
{
u_int minno, maxno, no;
struct limit *limit;
const struct rule *rule;
const struct opt_limit *opt_limit;
const struct opt_limits *opt_limits;
rule = opt_rule->rule;
opt_limits = &opt_rule->opt_limits;
get_min_max_no(opt_limits, &minno, &maxno);
for (no = minno; no <= maxno; ++no)
STAILQ_FOREACH(opt_limit, &opt_rule->opt_limits, link) {
limit = opt_limit->limit;
if (limit->limitno == no) {
if (!limit->inited) {
limit->inited = 1;
/* Init in modules. */
if (st_init_limit(rule, limit) < 0) {
logmsgx(IPA_LOG_ERR, "rule %s, limit %s: init_limits: st_init_limit failed",
rule->rule_name, limit->limit_name);
return -1;
}
}
break;
}
}
return 0;
}
int
deinit_limits(const struct opt_rule *opt_rule)
{
int error = 0;
u_int minno, maxno, no;
struct limit *limit;
const struct rule *rule;
const struct opt_limit *opt_limit;
const struct opt_limits *opt_limits;
rule = opt_rule->rule;
opt_limits = &opt_rule->opt_limits;
get_min_max_no(opt_limits, &minno, &maxno);
for (no = minno; no <= maxno; ++no)
STAILQ_FOREACH(opt_limit, &opt_rule->opt_limits, link) {
limit = opt_limit->limit;
if (limit->limitno == no) {
if (limit->inited) {
limit->inited = 0;
/* Deinit in modules. */
if (st_deinit_limit(rule, limit) < 0) {
logmsgx(IPA_LOG_ERR, "rule %s, limit %s: deinit_limits: st_deinit_limit failed",
rule->rule_name, limit->limit_name);
error = -1;
}
}
break;
}
}
return error;
}
/*
* Copy all limits from list_src to rule.
*/
int
copy_limits(struct rule *rule, const struct limits_list *list_src)
{
struct limit *limit_dst;
const struct limit *limit_src;
STAILQ_FOREACH(limit_src, list_src, link) {
if ( (limit_dst = mzone_alloc(limit_mzone)) == NULL) {
xlogmsgx(IPA_LOG_ERR, "copy_limits: mzone_alloc failed");
return -1;
}
/* Copy settings from source limit. */
*limit_dst = *limit_src;
limit_dst->free_mask = 0;
/* Link just allocated limit to rule. */
STAILQ_INSERT_TAIL(&rule->limits, limit_dst, link);
}
return 0;
}
/*
* Release memory used by a list of limits.
*/
void
free_limits(struct limits_list *limits)
{
struct limit *limit, *limit_next;
for (limit = STAILQ_FIRST(limits); limit != NULL; limit = limit_next) {
limit_next = STAILQ_NEXT(limit, link);
if (limit->free_mask & LIMIT_FREE_NAME)
mem_free(limit->limit_name, m_anon);
mem_free(limit->limit_info, m_result);
mzone_free(limit_mzone, limit);
}
}
/*
* Add one optional limit given in the -q -r option.
*/
int
add_opt_limit(const char *limit_name)
{
struct opt_limit *opt_limit;
if ( (opt_limit = mem_malloc(sizeof *opt_limit, m_anon)) == NULL) {
logmsgx(IPA_LOG_ERR, "add_opt_limit: mem_malloc failed");
return -1;
}
opt_limit->limit_name = limit_name;
opt_limit->opt_st = cur_opt_st;
opt_limit->data = NULL;
cur_opt_rule->type = OPT_RULE_LIMIT;
STAILQ_INSERT_TAIL(&cur_opt_rule->opt_limits, opt_limit, link);
has_opt_limits = 1;
return 0;
}
int
parse_opt_limits(const struct opt_rule *opt_rule)
{
u_int limitno;
struct rule *rule;
struct limit *limit;
struct opt_limit *opt_limit;
if (!STAILQ_EMPTY(&opt_rule->opt_limits)) {
rule = opt_rule->rule;
if (STAILQ_EMPTY(&rule->limits))
limitno = 0;
else {
limit = STAILQ_LAST(&rule->limits, limit, link);
limitno = limit->limitno + 1;
}
STAILQ_FOREACH(opt_limit, &opt_rule->opt_limits, link) {
if ( (limit = limit_by_name(rule, opt_limit->limit_name)) == NULL) {
/* This limit is not given in the configuration file. */
if (!dynamic_limits) {
logmsgx(IPA_LOG_ERR, "parse_opt_limits: unknown rule %s, limit %s",
rule->rule_name, opt_limit->limit_name);
return -1;
}
if ( (limit = alloc_limit()) == NULL) {
logmsgx(IPA_LOG_ERR, "parse_opt_limits: alloc_limit failed");
return -1;
}
STAILQ_INSERT_TAIL(&rule->limits, limit, link);
limit->limitno = limitno++;
limit->limit_name = (char *)opt_limit->limit_name;
limit->free_mask = 0;
}
opt_limit->limit = limit;
if (opt_limit->opt_st != NULL)
limit->st_list = opt_limit->opt_st->st_list;
if (limit->st_list == NULL)
limit->st_list = rule->st_list;
}
}
return 0;
}
void
free_opt_limits(const struct opt_limits *opt_limits)
{
struct opt_limit *opt_limit, *opt_limit_next;
for (opt_limit = STAILQ_FIRST(opt_limits); opt_limit != NULL; opt_limit = opt_limit_next) {
opt_limit_next = STAILQ_NEXT(opt_limit, link);
mem_free(opt_limit, m_anon);
}
}
#endif /* WITH_LIMITS */
syntax highlighted by Code2HTML, v. 0.9.1