/*-
 * 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_thresholds.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_thresholds = 0;	/* 1, if -q ... -t ... */

#ifdef WITH_THRESHOLDS

int		dynamic_thresholds = -1;/* dynamic_thresholds parameter. */

ipa_mzone	*threshold_mzone;	/* Mzone for struct threshold{}. */

struct threshold *
alloc_threshold(void)
{
	struct threshold *threshold;

	if ( (threshold = mzone_alloc(threshold_mzone)) == NULL) {
		xlogmsgx(IPA_LOG_ERR, "alloc_threshold: mzone_alloc failed");
		return NULL;
	}

	threshold->threshold_info = NULL;

	threshold->st_list = NULL;

	threshold->inited = 0;

	return threshold;
}

/*
 * Return pointer to threshold with the give name.
 */
struct threshold *
threshold_by_name(const struct rule *rule, const char *name)
{
	struct threshold *threshold;

	STAILQ_FOREACH(threshold, &rule->thresholds, link)
		if (strcmp(name, threshold->threshold_name) == 0)
			return threshold;
	return NULL;
}

static void
get_min_max_no(	const struct opt_thresholds *opt_thresholds, u_int *minno,
    u_int *maxno)
{
	const struct threshold *threshold;
	const struct opt_threshold *opt_threshold;

	*minno = *maxno = STAILQ_FIRST(opt_thresholds)->threshold->thresholdno;
	STAILQ_FOREACH(opt_threshold, opt_thresholds, link) {
		threshold = opt_threshold->threshold;
		if (*minno > threshold->thresholdno)
			*minno = threshold->thresholdno;
		if (*maxno < threshold->thresholdno)
			*maxno = threshold->thresholdno;
	}
}

/*
 * Init all thresholds from one rule in modules.
 */
int
init_thresholds(const struct opt_rule *opt_rule)
{
	u_int	minno, maxno, no;
	struct threshold *threshold;
	const struct rule *rule;
	const struct opt_threshold *opt_threshold;
	const struct opt_thresholds *opt_thresholds;

	rule = opt_rule->rule;
	opt_thresholds = &opt_rule->opt_thresholds;

	get_min_max_no(opt_thresholds, &minno, &maxno);

	for (no = minno; no <= maxno; ++no)
		STAILQ_FOREACH(opt_threshold, opt_thresholds, link) {
			threshold = opt_threshold->threshold;
			if (threshold->thresholdno == no) {
				if (!threshold->inited) {
					threshold->inited = 1;

					/* Init in modules. */
					if (st_init_threshold(rule, threshold) < 0) {
						logmsgx(IPA_LOG_ERR, "rule %s, threshold %s: init_thresholds: st_init_threshold failed",
						    rule->rule_name, threshold->threshold_name);
						return -1;
					}
				}
				break;
			}
		}

	return 0;
}

int
deinit_thresholds(const struct opt_rule *opt_rule)
{
	int	error = 0;
	u_int	minno, maxno, no;
	struct threshold *threshold;
	const struct rule *rule;
	const struct opt_threshold *opt_threshold;
	const struct opt_thresholds *opt_thresholds;

	rule = opt_rule->rule;
	opt_thresholds = &opt_rule->opt_thresholds;

	get_min_max_no(opt_thresholds, &minno, &maxno);

	for (no = minno; no <= maxno; ++no)
		STAILQ_FOREACH(opt_threshold, &opt_rule->opt_thresholds, link) {
			threshold = opt_threshold->threshold;
			if (threshold->thresholdno == no) {
				if (threshold->inited) {
					threshold->inited = 0;

					/* Deinit in modules. */
					if (st_deinit_threshold(rule, threshold) < 0) {
						logmsgx(IPA_LOG_ERR, "rule %s, threshold %s: deinit_thresholds: st_deinit_threshold failed",
						    rule->rule_name, threshold->threshold_name);
						error = -1;
					}
				}
				break;
			}
		}

	return error;
}

/*
 * Copy all thresholds from list_src to rule.
 */
int
copy_thresholds(struct rule *rule, const struct thresholds_list *list_src)
{
	struct threshold *threshold_dst;
	const struct threshold *threshold_src;

	STAILQ_FOREACH(threshold_src, list_src, link) {
		if ( (threshold_dst = mzone_alloc(threshold_mzone)) == NULL) {
			xlogmsgx(IPA_LOG_ERR, "copy_thresholds: mzone_alloc failed");
			return -1;
		}

		/* Copy settings from source threshold. */
		*threshold_dst = *threshold_src;

		threshold_dst->free_mask = 0;

		/* Link just allocated threshold to rule. */
		STAILQ_INSERT_TAIL(&rule->thresholds, threshold_dst, link);
	}

	return 0;
}

#include <stdio.h>

/*
 * Release memory used by a list of thresholds.
 */
void
free_thresholds(struct thresholds_list *thresholds)
{
	struct threshold *threshold, *threshold_next;

	for (threshold = STAILQ_FIRST(thresholds); threshold != NULL; threshold = threshold_next) {
		threshold_next = STAILQ_NEXT(threshold, link);
		if (threshold->free_mask & THRESHOLD_FREE_NAME)
			mem_free(threshold->threshold_name, m_anon);
		mem_free(threshold->threshold_info, m_result);
		mzone_free(threshold_mzone, threshold);
	}
}

/*
 * Add one optional threshold given in the -q -r option.
 */
int
add_opt_threshold(const char *threshold_name)
{
	struct opt_threshold *opt_threshold;

	if ( (opt_threshold = mem_malloc(sizeof *opt_threshold, m_anon)) == NULL) {
		logmsgx(IPA_LOG_ERR, "add_opt_threshold: mem_malloc failed");
		return -1;
	}

	opt_threshold->threshold_name = threshold_name;

	opt_threshold->opt_st = cur_opt_st;

	cur_opt_rule->type = OPT_RULE_THRESHOLD;

	STAILQ_INSERT_TAIL(&cur_opt_rule->opt_thresholds, opt_threshold, link);

	has_opt_thresholds = 1;

	return 0;
}

int
parse_opt_thresholds(const struct opt_rule *opt_rule)
{
	u_int	thresholdno;
	struct rule *rule;
	struct threshold *threshold;
	struct opt_threshold *opt_threshold;

	if (!STAILQ_EMPTY(&opt_rule->opt_thresholds)) {
		rule = opt_rule->rule;

		if (STAILQ_EMPTY(&rule->thresholds))
			thresholdno = 0;
		else {
			threshold = STAILQ_LAST(&rule->thresholds, threshold, link);
			thresholdno = threshold->thresholdno + 1;
		}

		STAILQ_FOREACH(opt_threshold, &opt_rule->opt_thresholds, link) {
			if ( (threshold = threshold_by_name(rule, opt_threshold->threshold_name)) == NULL) {
				/* This threshold is not given in the configuration file. */
				if (!dynamic_thresholds) {
					logmsgx(IPA_LOG_ERR, "parse_opt_thresholds: unknown rule %s, threshold %s",
					    rule->rule_name, opt_threshold->threshold_name);
					return -1;
				}
				if ( (threshold = alloc_threshold()) == NULL) {
					logmsgx(IPA_LOG_ERR, "parse_opt_thresholds: alloc_threshold failed");
					return -1;
				}
				STAILQ_INSERT_TAIL(&rule->thresholds, threshold, link);
				threshold->thresholdno = thresholdno++;
				threshold->threshold_name = (char *)opt_threshold->threshold_name;
				threshold->free_mask = 0;
			}
			opt_threshold->threshold = threshold;
			if (opt_threshold->opt_st != NULL)
				threshold->st_list = opt_threshold->opt_st->st_list;
			if (threshold->st_list == NULL)
				threshold->st_list = rule->st_list;
		}
	}

	return 0;
}

void
free_opt_thresholds(const struct opt_thresholds *opt_thresholds)
{
	struct opt_threshold *opt_threshold, *opt_threshold_next;

	for (opt_threshold = STAILQ_FIRST(opt_thresholds); opt_threshold != NULL; opt_threshold = opt_threshold_next) {
		opt_threshold_next = STAILQ_NEXT(opt_threshold, link);
		mem_free(opt_threshold, m_anon);
	}
}
#endif /* WITH_THRESHOLDS */


syntax highlighted by Code2HTML, v. 0.9.1