updated for 2.2.6pre2
[Samba.git] / source / libsmb / namecache.c
blob2252e8e59cebd58e68207e716bd7c7d00cf8b0ba
1 /*
2 Unix SMB/CIFS implementation.
4 NetBIOS name cache module.
6 Copyright (C) Tim Potter, 2002
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include "includes.h"
25 static BOOL done_namecache_init;
26 static BOOL enable_namecache;
27 static TDB_CONTEXT *namecache_tdb;
29 struct nc_value {
30 time_t expiry; /* When entry expires */
31 int count; /* Number of addresses */
32 struct in_addr ip_list[1]; /* Address list */
35 /* Initialise namecache system */
37 BOOL namecache_enable(void)
39 /* Check if we have been here before, or name caching disabled
40 by setting the name cache timeout to zero. */
42 if (done_namecache_init)
43 return False;
45 done_namecache_init = True;
47 if (lp_name_cache_timeout() == 0) {
48 DEBUG(5, ("namecache_init: disabling netbios name cache\n"));
49 return False;
52 /* Open namecache tdb in read/write or readonly mode */
54 namecache_tdb = tdb_open_log(
55 lock_path("namecache.tdb"), 0,
56 TDB_DEFAULT, O_RDWR | O_CREAT, 0644);
58 if (!namecache_tdb) {
59 DEBUG(5, ("namecache_init: could not open %s\n",
60 lock_path("namecache.tdb")));
61 return False;
64 DEBUG(5, ("namecache_init: enabling netbios namecache, timeout %d "
65 "seconds\n", lp_name_cache_timeout()));
67 enable_namecache = True;
69 return True;
72 /* Return a key for a name and name type. The caller must free
73 retval.dptr when finished. */
75 static TDB_DATA namecache_key(const char *name, int name_type)
77 TDB_DATA retval;
78 char *keystr;
80 asprintf(&keystr, "%s#%02X", strupper_static(name), name_type);
82 retval.dsize = strlen(keystr) + 1;
83 retval.dptr = keystr;
85 return retval;
88 /* Return a data value for an IP list. The caller must free
89 retval.dptr when finished. */
91 static TDB_DATA namecache_value(struct in_addr *ip_list, int num_names,
92 time_t expiry)
94 TDB_DATA retval;
95 struct nc_value *value;
96 int size = sizeof(struct nc_value);
98 if (num_names > 0)
99 size += sizeof(struct in_addr) * (num_names-1);
101 value = (struct nc_value *)malloc(size);
103 memset(value, 0, size);
105 value->expiry = expiry;
106 value->count = num_names;
108 if (ip_list)
109 memcpy(value->ip_list, ip_list, sizeof(struct in_addr) * num_names);
111 retval.dptr = (char *)value;
112 retval.dsize = size;
114 return retval;
117 /* Store a name in the name cache */
119 void namecache_store(const char *name, int name_type,
120 int num_names, struct in_addr *ip_list)
122 TDB_DATA key, value;
123 time_t expiry;
124 int i;
126 if (!enable_namecache)
127 return;
129 DEBUG(5, ("namecache_store: storing %d address%s for %s#%02x: ",
130 num_names, num_names == 1 ? "": "es", name, name_type));
132 for (i = 0; i < num_names; i++)
133 DEBUGADD(5, ("%s%s", inet_ntoa(ip_list[i]),
134 i == (num_names - 1) ? "" : ", "));
136 DEBUGADD(5, ("\n"));
138 key = namecache_key(name, name_type);
140 /* Cache pdc location or dc lists for only a little while
141 otherwise if we lock on to a bad DC we can potentially be
142 out of action for the entire cache timeout time! */
144 if (name_type != 0x1b || name_type != 0x1c)
145 expiry = time(NULL) + 10;
146 else
147 expiry = time(NULL) + lp_name_cache_timeout();
149 value = namecache_value(ip_list, num_names, expiry);
151 tdb_store(namecache_tdb, key, value, TDB_REPLACE);
153 free(key.dptr);
154 free(value.dptr);
157 /* Look up a name in the name cache. Return a mallocated list of IP
158 addresses if the name is contained in the cache. */
160 BOOL namecache_fetch(const char *name, int name_type, struct in_addr **ip_list,
161 int *num_names)
163 TDB_DATA key, value;
164 struct nc_value *data;
165 time_t now;
166 int i;
168 *ip_list = NULL;
169 *num_names = 0;
171 if (!enable_namecache)
172 return False;
174 /* Read value */
176 key = namecache_key(name, name_type);
178 value = tdb_fetch(namecache_tdb, key);
180 if (!value.dptr) {
181 DEBUG(5, ("namecache_fetch: %s#%02x not found\n",
182 name, name_type));
183 goto done;
186 data = (struct nc_value *)value.dptr;
188 /* Check expiry time */
190 now = time(NULL);
192 if (now > data->expiry) {
194 DEBUG(5, ("namecache_fetch: entry for %s#%02x expired\n",
195 name, name_type));
197 tdb_delete(namecache_tdb, key);
199 value = tdb_null;
201 goto done;
204 if ((data->expiry - now) > lp_name_cache_timeout()) {
206 /* Someone may have changed the system time on us */
208 DEBUG(5, ("namecache_fetch: entry for %s#%02x has bad expiry\n",
209 name, name_type));
211 tdb_delete(namecache_tdb, key);
213 value = tdb_null;
215 goto done;
218 /* Extract and return namelist */
220 DEBUG(5, ("namecache_fetch: returning %d address%s for %s#%02x: ",
221 data->count, data->count == 1 ? "" : "es", name, name_type));
223 if (data->count) {
225 *ip_list = (struct in_addr *)malloc(
226 sizeof(struct in_addr) * data->count);
228 memcpy(*ip_list, data->ip_list, sizeof(struct in_addr) * data->count);
230 *num_names = data->count;
232 for (i = 0; i < *num_names; i++)
233 DEBUGADD(5, ("%s%s", inet_ntoa((*ip_list)[i]),
234 i == (*num_names - 1) ? "" : ", "));
238 DEBUGADD(5, ("\n"));
240 done:
241 SAFE_FREE(key.dptr);
242 SAFE_FREE(value.dptr);
244 return value.dsize > 0;
247 /* Flush all names from the name cache */
249 void namecache_flush(void)
251 int result;
253 if (!namecache_tdb)
254 return;
256 result = tdb_traverse(namecache_tdb, tdb_traverse_delete_fn, NULL);
258 if (result == -1)
259 DEBUG(5, ("namecache_flush: error deleting cache entries\n"));
260 else
261 DEBUG(5, ("namecache_flush: deleted %d cache entr%s\n",
262 result, result == 1 ? "y" : "ies"));