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
psc_addr_match_list_match(ADDR_MATCH_LIST * addr_list,const char * addr_str)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
psc_cache_lookup(DICT_CACHE * cache,const char * key)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
psc_cache_update(DICT_CACHE * cache,const char * key,const char * value)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
psc_dict_get(DICT * dict,const char * key)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
psc_maps_find(MAPS * maps,const char * key,int flags)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