xref: /netbsd-src/external/ibm-public/postfix/dist/src/postscreen/postscreen_dict.c (revision ff6d749d9964a9b179f9760ce6992137cffbaefe)
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