1/*++ 2/* NAME 3/* postscreen_dict 3 4/* SUMMARY 5/* postscreen table access wrappers 6/* SYNOPSIS 7/* #include <postscreen.h> 8/* 9/* int psc_addr_match_list_match(match_list, client_addr) 10/* ADDR_MATCH_LIST *match_list; 11/* const char *client_addr; 12/* 13/* const char *psc_cache_lookup(DICT_CACHE *cache, const char *key) 14/* DICT_CACHE *cache; 15/* const char *key; 16/* 17/* void psc_cache_update(cache, key, value) 18/* DICT_CACHE *cache; 19/* const char *key; 20/* const char *value; 21/* 22/* void psc_dict_get(dict, key) 23/* DICT *dict; 24/* const char *key; 25/* 26/* void psc_maps_find(maps, key, flags) 27/* MAPS *maps; 28/* const char *key; 29/* int flags; 30/* DESCRIPTION 31/* This module implements wrappers around time-critical table 32/* access functions. The functions log a warning when table 33/* access takes a non-trivial amount of time. 34/* 35/* psc_addr_match_list_match() is a wrapper around 36/* addr_match_list_match(). 37/* 38/* psc_cache_lookup() and psc_cache_update() are wrappers around 39/* the corresponding dict_cache() methods. 40/* 41/* psc_dict_get() and psc_maps_find() are wrappers around 42/* dict_get() and maps_find(), respectively. 43/* LICENSE 44/* .ad 45/* .fi 46/* The Secure Mailer license must be distributed with this software. 47/* AUTHOR(S) 48/* Wietse Venema 49/* IBM T.J. Watson Research 50/* P.O. Box 704 51/* Yorktown Heights, NY 10598, USA 52/*--*/ 53 54/* System library. */ 55 56#include <sys_defs.h> 57 58/* Utility library. */ 59 60#include <msg.h> 61#include <dict.h> 62 63/* Global library. */ 64 65#include <maps.h> 66 67/* Application-specific. */ 68 69#include <postscreen.h> 70 71 /* 72 * Monitor time-critical operations. 73 * 74 * XXX Averaging support was added during a stable release candidate, so it 75 * provides only the absolute minimum necessary. A complete implementation 76 * should maintain separate statistics for each table, and it should not 77 * complain when the access latency is less than the time between accesses. 78 */ 79#define PSC_GET_TIME_BEFORE_LOOKUP { \ 80 struct timeval _before, _after; \ 81 DELTA_TIME _delta; \ 82 double _new_delta_ms; \ 83 GETTIMEOFDAY(&_before); 84 85#define PSC_DELTA_MS(d) ((d).dt_sec * 1000.0 + (d).dt_usec / 1000.0) 86 87#define PSC_AVERAGE(new, old) (0.1 * (new) + 0.9 * (old)) 88 89#ifndef PSC_THRESHOLD_MS 90#define PSC_THRESHOLD_MS 100 /* nag if latency > 100ms */ 91#endif 92 93#ifndef PSC_WARN_LOCKOUT_S 94#define PSC_WARN_LOCKOUT_S 60 /* don't nag for 60s */ 95#endif 96 97 /* 98 * Shared warning lock, so that we don't spam the logfile when the system 99 * becomes slow. 100 */ 101static time_t psc_last_warn = 0; 102 103#define PSC_CHECK_TIME_AFTER_LOOKUP(table, action, average) \ 104 GETTIMEOFDAY(&_after); \ 105 PSC_CALC_DELTA(_delta, _after, _before); \ 106 _new_delta_ms = PSC_DELTA_MS(_delta); \ 107 if ((average = PSC_AVERAGE(_new_delta_ms, average)) > PSC_THRESHOLD_MS \ 108 && psc_last_warn < _after.tv_sec - PSC_WARN_LOCKOUT_S) { \ 109 msg_warn("%s: %s %s average delay is %.0f ms", \ 110 myname, (table), (action), average); \ 111 psc_last_warn = _after.tv_sec; \ 112 } \ 113} 114 115/* psc_addr_match_list_match - time-critical address list lookup */ 116 117int psc_addr_match_list_match(ADDR_MATCH_LIST *addr_list, 118 const char *addr_str) 119{ 120 const char *myname = "psc_addr_match_list_match"; 121 int result; 122 static double latency_ms; 123 124 PSC_GET_TIME_BEFORE_LOOKUP; 125 result = addr_match_list_match(addr_list, addr_str); 126 PSC_CHECK_TIME_AFTER_LOOKUP("address list", "lookup", latency_ms); 127 return (result); 128} 129 130/* psc_cache_lookup - time-critical cache lookup */ 131 132const char *psc_cache_lookup(DICT_CACHE *cache, const char *key) 133{ 134 const char *myname = "psc_cache_lookup"; 135 const char *result; 136 static double latency_ms; 137 138 PSC_GET_TIME_BEFORE_LOOKUP; 139 result = dict_cache_lookup(cache, key); 140 PSC_CHECK_TIME_AFTER_LOOKUP(dict_cache_name(cache), "lookup", latency_ms); 141 return (result); 142} 143 144/* psc_cache_update - time-critical cache update */ 145 146void psc_cache_update(DICT_CACHE *cache, const char *key, const char *value) 147{ 148 const char *myname = "psc_cache_update"; 149 static double latency_ms; 150 151 PSC_GET_TIME_BEFORE_LOOKUP; 152 dict_cache_update(cache, key, value); 153 PSC_CHECK_TIME_AFTER_LOOKUP(dict_cache_name(cache), "update", latency_ms); 154} 155 156/* psc_dict_get - time-critical table lookup */ 157 158const char *psc_dict_get(DICT *dict, const char *key) 159{ 160 const char *myname = "psc_dict_get"; 161 const char *result; 162 static double latency_ms; 163 164 PSC_GET_TIME_BEFORE_LOOKUP; 165 result = dict_get(dict, key); 166 PSC_CHECK_TIME_AFTER_LOOKUP(dict->name, "lookup", latency_ms); 167 return (result); 168} 169 170/* psc_maps_find - time-critical table lookup */ 171 172const char *psc_maps_find(MAPS *maps, const char *key, int flags) 173{ 174 const char *myname = "psc_maps_find"; 175 const char *result; 176 static double latency_ms; 177 178 PSC_GET_TIME_BEFORE_LOOKUP; 179 result = maps_find(maps, key, flags); 180 PSC_CHECK_TIME_AFTER_LOOKUP(maps->title, "lookup", latency_ms); 181 return (result); 182} 183