/*
 * Copyright (c) 2005 Sendmail, Inc. and its suppliers.
 *	All rights reserved.
 *
 * By using this file, you agree to the terms and conditions set
 * forth in the LICENSE file which can be found at the top level of
 * the sendmail distribution.
 */

#include "sm/generic.h"
SM_RCSID("@(#)$Id: t-greyctl-1.c,v 1.4 2006/12/01 16:54:53 ca Exp $")

#include "sm/assert.h"
#include "sm/error.h"
#include "sm/types.h"
#include "sm/net.h"
#include "sm/greyctl.h"
#include "sm/io.h"
#include "sm/test.h"
#include "greyctl.h"

static int Verbose = 0;

static sm_ret_T
grey_display1(DB *db, DB *sdb, sm_file_T *fp)
{
	sm_ret_T ret;
	DBC *dbcp;
	DBT db_data, db_key;
	greyentry_T ge;
	bool first;

	ret = db->cursor(sdb, NULL, &dbcp, 0);
	if (ret != 0)
		return ret;
	first = true;
	do
	{
		sm_memzero(&db_key, sizeof(db_key));
		sm_memzero(&db_data, sizeof(db_data));
		db_data.flags = DB_DBT_USERMEM;
		db_data.data = ≥
		db_data.ulen = sizeof(ge);

		ret = dbcp->c_get(dbcp, &db_key, &db_data,
			first ? DB_FIRST : DB_NEXT);
		if (ret == 0)
		{
			sm_io_fprintf(fp,
				"addr=%16A, time=%7ld, expire=%7ld, type=%s\n",
				(ipv4_T) ge.ge_key,
				(long) ge.ge_time,
				(long) ge.ge_expire,
				ge.ge_type == GREY_TYPE_GREY ? "grey" :
				ge.ge_type == GREY_TYPE_WHITE ? "white"
				: "oops");
		}
		first = false;
	} while (ret == 0);
	ret = dbcp->c_close(dbcp);
	return ret;
}

static sm_ret_T
grey_display(greyctx_P greyctx, sm_file_T *fp)
{
	sm_ret_T ret;

	ret = grey_display1(greyctx->greyc_grey_db, greyctx->greyc_grey_sdb,
			fp);
	sm_io_putc(fp, '\n');
	sm_io_flush(fp);
	return ret;
}

static void
testg(uint entries, uint ips, bool display)
{
	sm_ret_T ret;
	uint ht_size, ht_limit, ge_limit, u;
	ipv4_T addr;
	ipv4_T *addrs;
	time_t t;
	greyctx_P greyctx;
	time_t  start, elapsed;
	uint greyr[2];

#define T_GREY_MIN_WAIT	60
#define T_GREY_MAX_WAIT	600
#define T_WHITE_EXP	6000
#define T_WHITE_TMO	12000

	ht_size = 40000;
	ht_limit = 40000;
	ge_limit = 20000;
	addrs = (ipv4_T *) sm_malloc(ips * sizeof(*addrs));
	if (addrs == NULL)
		return;

	ret = sm_greyctl_crt(&greyctx);
	SM_TEST(ret == SM_SUCCESS);
	if (ret != SM_SUCCESS)
		return;

	greyctx->greyc_cnf.greycnf_limit = ht_limit;
	greyctx->greyc_cnf.greycnf_min_grey_wait = T_GREY_MIN_WAIT;
	greyctx->greyc_cnf.greycnf_max_grey_wait = T_GREY_MAX_WAIT;
	greyctx->greyc_cnf.greycnf_white_expire = T_WHITE_EXP;
	greyctx->greyc_cnf.greycnf_white_reconfirm = T_WHITE_TMO;

	ret = sm_greyctl_open(greyctx, NULL);
	SM_TEST(ret == SM_SUCCESS);
	if (ret != SM_SUCCESS)
		return;


	srand(1);
	for (u = 0; u < ips; u++)
		addrs[u] = rand();

	greyr[0] = 0;
	greyr[1] = 0;
	start = time((time_t *) 0);
	t = 1;
	for (u = 0; u < entries; u++)
	{
		addr = addrs[u % ips];
		ret = sm_greyctl(greyctx, (uchar *)&addr, sizeof(addr), t + u);
		switch (ret)
		{
		  case SM_GREY_AGAIN:
		  case SM_GREY_FIRST:
		  case SM_GREY_WAIT:
			++greyr[1];
			break;
		  case SM_GREY_OK:
			++greyr[0];
			break;
		  default:
			goto done;
		}
	}
	elapsed = time((time_t *) 0) - start;
	sm_io_fprintf(smioout, "elapsed time: %ld\n", (long) elapsed);
	if (elapsed > 0)
		sm_io_fprintf(smioout, "updates/s: %ld\n", (long) entries / elapsed);
	sm_io_fprintf(smioout, "wait=%u\nok=  %u\n", greyr[1], greyr[0]);
	if (display)
		grey_display(greyctx, smioout);
	sm_io_flush(smioout);

  done:
	ret = sm_greyctl_free(greyctx);
	SM_TEST(ret == SM_SUCCESS);
}

int
main(int argc, char *argv[])
{
	int c;
	bool rm, display;
	uint entries, ips;

	entries = 1000;
	ips = 100;
	rm = true;
	display = false;
	while ((c = getopt(argc, argv, "de:i:k:V")) != -1)
	{
		switch (c)
		{
		  case 'd':
			display = true;
			break;
		  case 'e':
			entries = strtoul(optarg, NULL, 0);
			break;
		  case 'i':
			ips = strtoul(optarg, NULL, 0);
			break;
		  case 'k':
			rm = false;
			break;
		  case 'V':
			++Verbose;
			break;
		  default:
			return(1);
		}
	}
	if (rm)
	{
		(void) unlink("grey_grey_m.db");
		(void) unlink("grey_grey_s.db");
	}
	sm_test_begin(argc, argv, "test greylist");
	testg(entries, ips, display);
	return sm_test_end();
}


syntax highlighted by Code2HTML, v. 0.9.1