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