10Sstevel@tonic-gate/*	$NetBSD$	*/
20Sstevel@tonic-gate
30Sstevel@tonic-gate/*++
40Sstevel@tonic-gate/* NAME
50Sstevel@tonic-gate/*	postscreen_dict 3
60Sstevel@tonic-gate/* SUMMARY
70Sstevel@tonic-gate/*	postscreen table access wrappers
80Sstevel@tonic-gate/* SYNOPSIS
90Sstevel@tonic-gate/*	#include <postscreen.h>
100Sstevel@tonic-gate/*
110Sstevel@tonic-gate/*	int	psc_addr_match_list_match(match_list, client_addr)
120Sstevel@tonic-gate/*	ADDR_MATCH_LIST *match_list;
130Sstevel@tonic-gate/*	const char *client_addr;
140Sstevel@tonic-gate/*
150Sstevel@tonic-gate/*	const char *psc_cache_lookup(DICT_CACHE *cache, const char *key)
160Sstevel@tonic-gate/*	DICT_CACHE *cache;
170Sstevel@tonic-gate/*	const char *key;
180Sstevel@tonic-gate/*
190Sstevel@tonic-gate/*	void	psc_cache_update(cache, key, value)
200Sstevel@tonic-gate/*	DICT_CACHE *cache;
210Sstevel@tonic-gate/*	const char *key;
220Sstevel@tonic-gate/*	const char *value;
230Sstevel@tonic-gate/*
240Sstevel@tonic-gate/*	void	psc_dict_get(dict, key)
250Sstevel@tonic-gate/*	DICT	*dict;
260Sstevel@tonic-gate/*	const char *key;
270Sstevel@tonic-gate/*
280Sstevel@tonic-gate/*	void	psc_maps_find(maps, key, flags)
290Sstevel@tonic-gate/*	MAPS	*maps;
300Sstevel@tonic-gate/*	const char *key;
310Sstevel@tonic-gate/*	int	flags;
320Sstevel@tonic-gate/* DESCRIPTION
330Sstevel@tonic-gate/*	This module implements wrappers around time-critical table
340Sstevel@tonic-gate/*	access functions.  The functions log a warning when table
350Sstevel@tonic-gate/*	access takes a non-trivial amount of time.
360Sstevel@tonic-gate/*
370Sstevel@tonic-gate/*	psc_addr_match_list_match() is a wrapper around
380Sstevel@tonic-gate/*	addr_match_list_match().
390Sstevel@tonic-gate/*
400Sstevel@tonic-gate/*	psc_cache_lookup() and psc_cache_update() are wrappers around
410Sstevel@tonic-gate/*	the corresponding dict_cache() methods.
420Sstevel@tonic-gate/*
430Sstevel@tonic-gate/*	psc_dict_get() and psc_maps_find() are wrappers around
440Sstevel@tonic-gate/*	dict_get() and maps_find(), respectively.
450Sstevel@tonic-gate/* LICENSE
460Sstevel@tonic-gate/* .ad
470Sstevel@tonic-gate/* .fi
480Sstevel@tonic-gate/*	The Secure Mailer license must be distributed with this software.
490Sstevel@tonic-gate/* AUTHOR(S)
500Sstevel@tonic-gate/*	Wietse Venema
510Sstevel@tonic-gate/*	IBM T.J. Watson Research
520Sstevel@tonic-gate/*	P.O. Box 704
530Sstevel@tonic-gate/*	Yorktown Heights, NY 10598, USA
542139Sjp161948/*--*/
552139Sjp161948
562139Sjp161948/* System library. */
572139Sjp161948
582139Sjp161948#include <sys_defs.h>
590Sstevel@tonic-gate
600Sstevel@tonic-gate/* Utility library. */
610Sstevel@tonic-gate
620Sstevel@tonic-gate#include <msg.h>
630Sstevel@tonic-gate#include <dict.h>
640Sstevel@tonic-gate
650Sstevel@tonic-gate/* Global library. */
660Sstevel@tonic-gate
670Sstevel@tonic-gate#include <maps.h>
680Sstevel@tonic-gate
690Sstevel@tonic-gate/* Application-specific. */
700Sstevel@tonic-gate
710Sstevel@tonic-gate#include <postscreen.h>
720Sstevel@tonic-gate
730Sstevel@tonic-gate /*
740Sstevel@tonic-gate  * Monitor time-critical operations.
750Sstevel@tonic-gate  *
760Sstevel@tonic-gate  * XXX Averaging support was added during a stable release candidate, so it
770Sstevel@tonic-gate  * provides only the absolute minimum necessary. A complete implementation
780Sstevel@tonic-gate  * should maintain separate statistics for each table, and it should not
790Sstevel@tonic-gate  * complain when the access latency is less than the time between accesses.
800Sstevel@tonic-gate  */
810Sstevel@tonic-gate#define PSC_GET_TIME_BEFORE_LOOKUP { \
820Sstevel@tonic-gate    struct timeval _before, _after; \
830Sstevel@tonic-gate    DELTA_TIME _delta; \
840Sstevel@tonic-gate    double _new_delta_ms; \
850Sstevel@tonic-gate    GETTIMEOFDAY(&_before);
860Sstevel@tonic-gate
870Sstevel@tonic-gate#define PSC_DELTA_MS(d) ((d).dt_sec * 1000.0 + (d).dt_usec / 1000.0)
880Sstevel@tonic-gate
890Sstevel@tonic-gate#define PSC_AVERAGE(new, old)	(0.1 * (new) + 0.9 * (old))
900Sstevel@tonic-gate
910Sstevel@tonic-gate#ifndef PSC_THRESHOLD_MS
920Sstevel@tonic-gate#define PSC_THRESHOLD_MS	100	/* nag if latency > 100ms */
930Sstevel@tonic-gate#endif
940Sstevel@tonic-gate
952139Sjp161948#ifndef PSC_WARN_LOCKOUT_S
960Sstevel@tonic-gate#define PSC_WARN_LOCKOUT_S	60	/* don't nag for 60s */
970Sstevel@tonic-gate#endif
980Sstevel@tonic-gate
990Sstevel@tonic-gate /*
1000Sstevel@tonic-gate  * Shared warning lock, so that we don't spam the logfile when the system
1010Sstevel@tonic-gate  * becomes slow.
1020Sstevel@tonic-gate  */
1030Sstevel@tonic-gatestatic time_t psc_last_warn = 0;
1040Sstevel@tonic-gate
1050Sstevel@tonic-gate#define PSC_CHECK_TIME_AFTER_LOOKUP(table, action, average) \
1060Sstevel@tonic-gate    GETTIMEOFDAY(&_after); \
1070Sstevel@tonic-gate    PSC_CALC_DELTA(_delta, _after, _before); \
1080Sstevel@tonic-gate    _new_delta_ms = PSC_DELTA_MS(_delta); \
1090Sstevel@tonic-gate    if ((average = PSC_AVERAGE(_new_delta_ms, average)) > PSC_THRESHOLD_MS \
1100Sstevel@tonic-gate	&& psc_last_warn < _after.tv_sec - PSC_WARN_LOCKOUT_S) { \
1110Sstevel@tonic-gate        msg_warn("%s: %s %s average delay is %.0f ms", \
1120Sstevel@tonic-gate                 myname, (table), (action), average); \
1130Sstevel@tonic-gate	psc_last_warn = _after.tv_sec; \
1140Sstevel@tonic-gate    } \
1150Sstevel@tonic-gate}
1160Sstevel@tonic-gate
1170Sstevel@tonic-gate/* psc_addr_match_list_match - time-critical address list lookup */
1180Sstevel@tonic-gate
1190Sstevel@tonic-gateint     psc_addr_match_list_match(ADDR_MATCH_LIST *addr_list,
1200Sstevel@tonic-gate				          const char *addr_str)
1210Sstevel@tonic-gate{
1220Sstevel@tonic-gate    const char *myname = "psc_addr_match_list_match";
1230Sstevel@tonic-gate    int     result;
1240Sstevel@tonic-gate    static double latency_ms;
1250Sstevel@tonic-gate
1260Sstevel@tonic-gate    PSC_GET_TIME_BEFORE_LOOKUP;
1270Sstevel@tonic-gate    result = addr_match_list_match(addr_list, addr_str);
1280Sstevel@tonic-gate    PSC_CHECK_TIME_AFTER_LOOKUP("address list", "lookup", latency_ms);
1290Sstevel@tonic-gate    return (result);
1300Sstevel@tonic-gate}
1310Sstevel@tonic-gate
1320Sstevel@tonic-gate/* psc_cache_lookup - time-critical cache lookup */
1330Sstevel@tonic-gate
1340Sstevel@tonic-gateconst char *psc_cache_lookup(DICT_CACHE *cache, const char *key)
1350Sstevel@tonic-gate{
1362139Sjp161948    const char *myname = "psc_cache_lookup";
1370Sstevel@tonic-gate    const char *result;
1380Sstevel@tonic-gate    static double latency_ms;
1390Sstevel@tonic-gate
1400Sstevel@tonic-gate    PSC_GET_TIME_BEFORE_LOOKUP;
1410Sstevel@tonic-gate    result = dict_cache_lookup(cache, key);
1420Sstevel@tonic-gate    PSC_CHECK_TIME_AFTER_LOOKUP(dict_cache_name(cache), "lookup", latency_ms);
1430Sstevel@tonic-gate    return (result);
1440Sstevel@tonic-gate}
1450Sstevel@tonic-gate
1460Sstevel@tonic-gate/* psc_cache_update - time-critical cache update */
1470Sstevel@tonic-gate
1480Sstevel@tonic-gatevoid    psc_cache_update(DICT_CACHE *cache, const char *key, const char *value)
1490Sstevel@tonic-gate{
1500Sstevel@tonic-gate    const char *myname = "psc_cache_update";
1510Sstevel@tonic-gate    static double latency_ms;
1520Sstevel@tonic-gate
1530Sstevel@tonic-gate    PSC_GET_TIME_BEFORE_LOOKUP;
1540Sstevel@tonic-gate    dict_cache_update(cache, key, value);
1550Sstevel@tonic-gate    PSC_CHECK_TIME_AFTER_LOOKUP(dict_cache_name(cache), "update", latency_ms);
1560Sstevel@tonic-gate}
1570Sstevel@tonic-gate
1580Sstevel@tonic-gate/* psc_dict_get - time-critical table lookup */
1590Sstevel@tonic-gate
1600Sstevel@tonic-gateconst char *psc_dict_get(DICT *dict, const char *key)
1610Sstevel@tonic-gate{
1620Sstevel@tonic-gate    const char *myname = "psc_dict_get";
1630Sstevel@tonic-gate    const char *result;
1642139Sjp161948    static double latency_ms;
1652139Sjp161948
1660Sstevel@tonic-gate    PSC_GET_TIME_BEFORE_LOOKUP;
1670Sstevel@tonic-gate    result = dict_get(dict, key);
1680Sstevel@tonic-gate    PSC_CHECK_TIME_AFTER_LOOKUP(dict->name, "lookup", latency_ms);
1690Sstevel@tonic-gate    return (result);
1700Sstevel@tonic-gate}
1712139Sjp161948
1722139Sjp161948/* psc_maps_find - time-critical table lookup */
1732139Sjp161948
1742139Sjp161948const char *psc_maps_find(MAPS *maps, const char *key, int flags)
1752139Sjp161948{
1762139Sjp161948    const char *myname = "psc_maps_find";
1772139Sjp161948    const char *result;
1782139Sjp161948    static double latency_ms;
1792139Sjp161948
1802139Sjp161948    PSC_GET_TIME_BEFORE_LOOKUP;
1812139Sjp161948    result = maps_find(maps, key, flags);
1822139Sjp161948    PSC_CHECK_TIME_AFTER_LOOKUP(maps->title, "lookup", latency_ms);
1832139Sjp161948    return (result);
1842139Sjp161948}
1852139Sjp161948