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