1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-23 17:34:34 +03:00

Merge from HEAD - mimir's new gencache based namecache code.

Andrew Bartlett
(This used to be commit f79324f730)
This commit is contained in:
Andrew Bartlett 2003-01-04 08:48:15 +00:00
parent e3ed8eaa2f
commit 863e9ca2c6
5 changed files with 365 additions and 213 deletions

View File

@ -91,8 +91,8 @@ BOOL gencache_shutdown(void)
/**
* Add one entry to the cache file.
* (it part of tridge's proposed API)
* Set an entry in the cache file. If there's no such
* one, then add it.
*
* @param key string that represents a key of this entry
* @param value text representation value being cached
@ -102,7 +102,7 @@ BOOL gencache_shutdown(void)
* false on the attempt's failure
**/
BOOL gencache_add(const char *keystr, const char *value, time_t timeout)
BOOL gencache_set(const char *keystr, const char *value, time_t timeout)
{
int ret;
TDB_DATA keybuf, databuf;
@ -122,7 +122,7 @@ BOOL gencache_add(const char *keystr, const char *value, time_t timeout)
= %s (%d seconds %s)\n", keybuf.dptr, value, ctime(&timeout),
(int)(timeout - time(NULL)), timeout > time(NULL) ? "ahead" : "in the past"));
ret = tdb_store(cache, keybuf, databuf, TDB_INSERT);
ret = tdb_store(cache, keybuf, databuf, 0);
SAFE_FREE(valstr);
SAFE_FREE(keybuf.dptr);
SAFE_FREE(databuf.dptr);
@ -133,7 +133,6 @@ BOOL gencache_add(const char *keystr, const char *value, time_t timeout)
/**
* Set existing entry to the cache file.
* (it part of tridge's proposed API)
*
* @param key string that represents a key of this entry
* @param value text representation value being cached
@ -143,7 +142,7 @@ BOOL gencache_add(const char *keystr, const char *value, time_t timeout)
* false on the attempt's failure
**/
BOOL gencache_set(const char *keystr, const char *valstr, time_t timeout)
BOOL gencache_set_only(const char *keystr, const char *valstr, time_t timeout)
{
int ret = -1;
TDB_DATA keybuf, databuf;
@ -189,7 +188,6 @@ BOOL gencache_set(const char *keystr, const char *valstr, time_t timeout)
/**
* Delete one entry from the cache file.
* (it part of tridge's proposed API)
*
* @param key string that represents a key of this entry
*
@ -219,11 +217,10 @@ BOOL gencache_del(const char *keystr)
/**
* Get existing entry from the cache file.
* (it part of tridge's proposed API)
*
* @param key string that represents a key of this entry
* @param value buffer that is allocated and filled with the entry value
* buffer's disposing is done outside
* buffer's disposing must be done outside
* @param timeout pointer to a time_t that is filled with entry's
* timeout
*
@ -272,12 +269,14 @@ BOOL gencache_get(const char *keystr, char **valstr, time_t *timeout)
*
* @param fn pointer to the function that will be supplied with each single
* matching cache entry (key, value and timeout) as an arguments
* @param data void pointer to an arbitrary data that is passed directly to the fn
* function on each call
* @param keystr_pattern pattern the existing entries' keys are matched to
*
**/
void gencache_iterate(void (*fn)(const char* key, const char *value, time_t timeout),
const char* keystr_pattern)
void gencache_iterate(void (*fn)(const char* key, const char *value, time_t timeout, void* dptr),
void* data, const char* keystr_pattern)
{
TDB_LIST_NODE *node, *first_node;
TDB_DATA databuf;
@ -289,7 +288,7 @@ void gencache_iterate(void (*fn)(const char* key, const char *value, time_t time
if (!gencache_init()) return;
DEBUG(5, ("Searching cache keys with pattern %s", keystr_pattern));
DEBUG(5, ("Searching cache keys with pattern %s\n", keystr_pattern));
node = tdb_search_keys(cache, keystr_pattern);
first_node = node;
@ -314,7 +313,7 @@ void gencache_iterate(void (*fn)(const char* key, const char *value, time_t time
DEBUG(10, ("Calling function with arguments (key = %s, value = %s, timeout = %s)\n",
keystr, valstr, ctime(&timeout)));
fn(keystr, valstr, timeout);
fn(keystr, valstr, timeout, data);
SAFE_FREE(valstr);
SAFE_FREE(entry);

View File

@ -1367,6 +1367,158 @@ BOOL str_list_substitute(char **list, const char *pattern, const char *insert)
return True;
}
#define IPSTR_LIST_SEP ","
/**
* Add ip string representation to ipstr list. Used also
* as part of @function ipstr_list_make
*
* @param ipstr_list pointer to string containing ip list;
* MUST BE already allocated and IS reallocated if necessary
* @param ipstr_size pointer to current size of ipstr_list (might be changed
* as a result of reallocation)
* @param ip IP address which is to be added to list
* @return pointer to string appended with new ip and possibly
* reallocated to new length
**/
char* ipstr_list_add(char** ipstr_list, const struct in_addr *ip)
{
char* new_ipstr = NULL;
/* arguments checking */
if (!ipstr_list || !ip) return NULL;
/* attempt to convert ip to a string and append colon separator to it */
if (*ipstr_list) {
asprintf(&new_ipstr, "%s%s%s", *ipstr_list, IPSTR_LIST_SEP,inet_ntoa(*ip));
SAFE_FREE(*ipstr_list);
} else {
asprintf(&new_ipstr, "%s", inet_ntoa(*ip));
}
*ipstr_list = new_ipstr;
return *ipstr_list;
}
/**
* Allocate and initialise an ipstr list using ip adresses
* passed as arguments.
*
* @param ipstr_list pointer to string meant to be allocated and set
* @param ip_list array of ip addresses to place in the list
* @param ip_count number of addresses stored in ip_list
* @return pointer to allocated ip string
**/
char* ipstr_list_make(char** ipstr_list, const struct in_addr* ip_list, int ip_count)
{
int i;
/* arguments checking */
if (!ip_list && !ipstr_list) return 0;
*ipstr_list = NULL;
/* process ip addresses given as arguments */
for (i = 0; i < ip_count; i++)
*ipstr_list = ipstr_list_add(ipstr_list, &ip_list[i]);
return (*ipstr_list);
}
/**
* Parse given ip string list into array of ip addresses
* (as in_addr structures)
*
* @param ipstr ip string list to be parsed
* @param ip_list pointer to array of ip addresses which is
* allocated by this function and must be freed by caller
* @return number of succesfully parsed addresses
**/
int ipstr_list_parse(const char* ipstr_list, struct in_addr** ip_list)
{
fstring token_str;
int count;
if (!ipstr_list || !ip_list) return 0;
for (*ip_list = NULL, count = 0;
next_token(&ipstr_list, token_str, IPSTR_LIST_SEP, FSTRING_LEN);
count++) {
struct in_addr addr;
/* convert single token to ip address */
if ( (addr.s_addr = inet_addr(token_str)) == INADDR_NONE )
break;
/* prepare place for another in_addr structure */
*ip_list = Realloc(*ip_list, (count + 1) * sizeof(struct in_addr));
if (!*ip_list) return -1;
(*ip_list)[count] = addr;
}
return count;
}
/**
* Safely free ip string list
*
* @param ipstr_list ip string list to be freed
**/
void ipstr_list_free(char* ipstr_list)
{
SAFE_FREE(ipstr_list);
}
/***********************************************************
Unescape a URL encoded string, in place.
***********************************************************/
void rfc1738_unescape(char *buf)
{
char *p=buf;
while ((p=strchr_m(p,'+')))
*p = ' ';
p = buf;
while (p && *p && (p=strchr_m(p,'%'))) {
int c1 = p[1];
int c2 = p[2];
if (c1 >= '0' && c1 <= '9')
c1 = c1 - '0';
else if (c1 >= 'A' && c1 <= 'F')
c1 = 10 + c1 - 'A';
else if (c1 >= 'a' && c1 <= 'f')
c1 = 10 + c1 - 'a';
else {p++; continue;}
if (c2 >= '0' && c2 <= '9')
c2 = c2 - '0';
else if (c2 >= 'A' && c2 <= 'F')
c2 = 10 + c2 - 'A';
else if (c2 >= 'a' && c2 <= 'f')
c2 = 10 + c2 - 'a';
else {p++; continue;}
*p = (c1<<4) | c2;
memmove(p+1, p+3, strlen(p+3)+1);
p++;
}
}
#ifdef VALGRIND
size_t valgrind_strlen(const char *s)
{

View File

@ -1,9 +1,10 @@
/*
Unix SMB/CIFS implementation.
NetBIOS name cache module.
Copyright (C) Tim Potter, 2002
NetBIOS name cache module on top of gencache mechanism.
Copyright (C) Tim Potter 2002
Copyright (C) Rafal Szczesniak 2002
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -22,242 +23,224 @@
#include "includes.h"
static BOOL done_namecache_init;
static BOOL enable_namecache;
static TDB_CONTEXT *namecache_tdb;
#define NBTKEY_FMT "NBT/%s#%02X"
struct nc_value {
time_t expiry; /* When entry expires */
int count; /* Number of addresses */
struct in_addr ip_list[1]; /* Address list */
};
/* Initialise namecache system */
/**
* Initialise namecache system. Function calls gencache
* initialisation function to perform necessary actions
*
* @return true upon successful initialisation of the cache or
* false on failure
**/
BOOL namecache_enable(void)
{
/* Check if we have been here before, or name caching disabled
by setting the name cache timeout to zero. */
if (done_namecache_init)
return False;
done_namecache_init = True;
/*
* Check if name caching disabled by setting the name cache
* timeout to zero.
*/
if (lp_name_cache_timeout() == 0) {
DEBUG(5, ("namecache_init: disabling netbios name cache\n"));
DEBUG(5, ("namecache_enable: disabling netbios name cache\n"));
return False;
}
/* Open namecache tdb in read/write or readonly mode */
/* Init namecache by calling gencache initialisation */
namecache_tdb = tdb_open_log(
lock_path("namecache.tdb"), 0,
TDB_DEFAULT, O_RDWR | O_CREAT, 0644);
if (!namecache_tdb) {
DEBUG(5, ("namecache_init: could not open %s\n",
lock_path("namecache.tdb")));
if (!gencache_init()) {
DEBUG(2, ("namecache_enable: Couldn't initialise namecache on top of gencache.\n"));
return False;
}
DEBUG(5, ("namecache_init: enabling netbios namecache, timeout %d "
/* I leave it for now, though I don't think we really need this (mimir, 27.09.2002) */
DEBUG(5, ("namecache_enable: enabling netbios namecache, timeout %d "
"seconds\n", lp_name_cache_timeout()));
enable_namecache = True;
return True;
}
/* Return a key for a name and name type. The caller must free
retval.dptr when finished. */
static TDB_DATA namecache_key(const char *name, int name_type)
/**
* Shutdown namecache. Routine calls gencache close function
* to safely close gencache file.
*
* @return true upon successful shutdown of the cache or
* false on failure
**/
BOOL namecache_shutdown(void)
{
if (!gencache_shutdown()) {
DEBUG(2, ("namecache_shutdown: Couldn't close namecache on top of gencache.\n"));
return False;
}
DEBUG(5, ("namecache_shutdown: netbios namecache closed successfully.\n"));
return True;
}
/**
* Generates a key for netbios name lookups on basis of
* netbios name and type.
* The caller must free returned key string when finished.
*
* @param name netbios name string (case insensitive)
* @param name_type netbios type of the name being looked up
*
* @return string consisted of uppercased name and appended
* type number
*/
static char* namecache_key(const char *name, int name_type)
{
TDB_DATA retval;
char *keystr;
asprintf(&keystr, NBTKEY_FMT, strupper_static(name), name_type);
asprintf(&keystr, "%s#%02X", strupper_static(name), name_type);
retval.dsize = strlen(keystr) + 1;
retval.dptr = keystr;
return retval;
return keystr;
}
/* Return a data value for an IP list. The caller must free
retval.dptr when finished. */
static TDB_DATA namecache_value(struct in_addr *ip_list, int num_names,
time_t expiry)
/**
* Store a name(s) in the name cache
*
* @param name netbios names array
* @param name_type integer netbios name type
* @param num_names number of names being stored
* @param ip_list array of in_addr structures containing
* ip addresses being stored
**/
BOOL namecache_store(const char *name, int name_type,
int num_names, struct in_addr *ip_list)
{
TDB_DATA retval;
struct nc_value *value;
int size = sizeof(struct nc_value);
if (num_names > 0)
size += sizeof(struct in_addr) * (num_names-1);
value = (struct nc_value *)malloc(size);
memset(value, 0, size);
value->expiry = expiry;
value->count = num_names;
if (ip_list)
memcpy(value->ip_list, ip_list, sizeof(struct in_addr) * num_names);
retval.dptr = (char *)value;
retval.dsize = size;
return retval;
}
/* Store a name in the name cache */
void namecache_store(const char *name, int name_type,
int num_names, struct in_addr *ip_list)
{
TDB_DATA key, value;
time_t expiry;
char *key, *value_string;
int i;
if (!enable_namecache)
return;
/*
* we use gecache call to avoid annoying debug messages about
* initialised namecache again and again...
*/
if (!gencache_init()) return False;
DEBUG(5, ("namecache_store: storing %d address%s for %s#%02x: ",
num_names, num_names == 1 ? "": "es", name, name_type));
num_names, num_names == 1 ? "": "es", name, name_type));
for (i = 0; i < num_names; i++)
DEBUGADD(5, ("%s%s", inet_ntoa(ip_list[i]),
i == (num_names - 1) ? "" : ", "));
i == (num_names - 1) ? "" : ", "));
DEBUGADD(5, ("\n"));
key = namecache_key(name, name_type);
/* Cache pdc location or dc lists for only a little while
otherwise if we lock on to a bad DC we can potentially be
out of action for the entire cache timeout time! */
/*
* Cache pdc location or dc lists for only a little while
* otherwise if we lock on to a bad DC we can potentially be
* out of action for the entire cache timeout time!
*/
if (name_type != 0x1b || name_type != 0x1c)
if (name_type == 0x1b || name_type == 0x1c)
expiry = time(NULL) + 10;
else
expiry = time(NULL) + lp_name_cache_timeout();
value = namecache_value(ip_list, num_names, expiry);
tdb_store(namecache_tdb, key, value, TDB_REPLACE);
free(key.dptr);
free(value.dptr);
/*
* Generate string representation of ip addresses list
* First, store the number of ip addresses and then
* place each single ip
*/
ipstr_list_make(&value_string, ip_list, num_names);
/* set the entry */
return (gencache_set(key, value_string, expiry));
}
/* Look up a name in the name cache. Return a mallocated list of IP
addresses if the name is contained in the cache. */
/**
* Look up a name in the cache.
*
* @param name netbios name to look up for
* @param name_type netbios name type of @param name
* @param ip_list mallocated list of IP addresses if found in the cache,
* NULL otherwise
* @param num_names number of entries found
*
* @return true upon successful fetch or
* false if name isn't found in the cache or has expired
**/
BOOL namecache_fetch(const char *name, int name_type, struct in_addr **ip_list,
int *num_names)
int *num_names)
{
TDB_DATA key, value;
struct nc_value *data = NULL;
time_t now;
int i;
char *key, *value;
time_t timeout;
*ip_list = NULL;
*num_names = 0;
if (!enable_namecache)
/* exit now if null pointers were passed as they're required further */
if (!ip_list || !num_names) return False;
if (!gencache_init())
return False;
/* Read value */
/*
* Use gencache interface - lookup the key
*/
key = namecache_key(name, name_type);
value = tdb_fetch(namecache_tdb, key);
if (!gencache_get(key, &value, &timeout)) {
DEBUG(5, ("no entry for %s#%02X found.\n", name, name_type));
SAFE_FREE(key);
return False;
} else {
DEBUG(5, ("name %s#%02X found.\n", name, name_type));
}
if (!value.dptr) {
DEBUG(5, ("namecache_fetch: %s#%02x not found\n",
name, name_type));
goto done;
}
data = (struct nc_value *)value.dptr;
/* Check expiry time */
now = time(NULL);
if (now > data->expiry) {
DEBUG(5, ("namecache_fetch: entry for %s#%02x expired\n",
name, name_type));
tdb_delete(namecache_tdb, key);
value = tdb_null;
goto done;
}
if ((data->expiry - now) > lp_name_cache_timeout()) {
/* Someone may have changed the system time on us */
DEBUG(5, ("namecache_fetch: entry for %s#%02x has bad expiry\n",
name, name_type));
tdb_delete(namecache_tdb, key);
value = tdb_null;
goto done;
}
/* Extract and return namelist */
DEBUG(5, ("namecache_fetch: returning %d address%s for %s#%02x: ",
data->count, data->count == 1 ? "" : "es", name, name_type));
if (data->count) {
*ip_list = (struct in_addr *)malloc(
sizeof(struct in_addr) * data->count);
memcpy(*ip_list, data->ip_list, sizeof(struct in_addr) * data->count);
*num_names = data->count;
for (i = 0; i < *num_names; i++)
DEBUGADD(5, ("%s%s", inet_ntoa((*ip_list)[i]),
i == (*num_names - 1) ? "" : ", "));
}
DEBUGADD(5, ("\n"));
done:
SAFE_FREE(key.dptr);
SAFE_FREE(data);
return value.dsize > 0;
/*
* Split up the stored value into the list of IP adresses
*/
*num_names = ipstr_list_parse(value, ip_list);
SAFE_FREE(key);
SAFE_FREE(value);
return *num_names > 0; /* true only if some ip has been fetched */
}
/* Flush all names from the name cache */
/**
* Delete single namecache entry. Look at the
* gencache_iterate definition.
*
**/
static void flush_netbios_name(const char* key, const char *value, time_t timeout, void* dptr)
{
gencache_del(key);
DEBUG(5, ("Deleting entry %s\n", key));
}
/**
* Flush all names from the name cache.
* It's done by gencache_iterate()
*
* @return True upon successful deletion or
* False in case of an error
**/
void namecache_flush(void)
{
int result;
if (!namecache_tdb)
if (!gencache_init())
return;
result = tdb_traverse(namecache_tdb, tdb_traverse_delete_fn, NULL);
if (result == -1)
DEBUG(5, ("namecache_flush: error deleting cache entries\n"));
else
DEBUG(5, ("namecache_flush: deleted %d cache entr%s\n",
result, result == 1 ? "y" : "ies"));
/*
* iterate through each NBT cache's entry and flush it
* by flush_netbios_name function
*/
gencache_iterate(flush_netbios_name, NULL, "NBT/*");
DEBUG(5, ("Namecache flushed\n"));
}

View File

@ -837,11 +837,6 @@ static BOOL internal_resolve_name(const char *name, int name_type,
if (resolve_hosts(name, return_iplist, return_count)) {
result = True;
goto done;
} else {
/* Store negative lookup result */
namecache_store(name, name_type, 0, NULL);
}
}
} else if(strequal( tok, "lmhosts")) {
@ -916,7 +911,10 @@ static BOOL internal_resolve_name(const char *name, int name_type,
}
/* Save in name cache */
for (i = 0; i < *return_count && DEBUGLEVEL == 100; i++)
DEBUG(100, ("Storing name %s of type %d (ip: %s)\n", name,
name_type, inet_ntoa((*return_iplist)[i])));
namecache_store(name, name_type, *return_count, *return_iplist);
/* Display some debugging info */

View File

@ -34,15 +34,34 @@
* (print_cache_entry) and to flush it (delete_cache_entry).
* Both of them are defined by first arg of gencache_iterate() routine.
*/
static void print_cache_entry(const char* keystr, const char* datastr, const time_t timeout)
static void print_cache_entry(const char* keystr, const char* datastr,
const time_t timeout, void* dptr)
{
char* timeout_str = ctime(&timeout);
timeout_str[strlen(timeout_str) - 1] = '\0';
d_printf("Key: %s\t\t Value: %s\t\t Timeout: %s %s\n", keystr, datastr,
timeout_str, timeout > time(NULL) ? "": "(expired)");
char* timeout_str;
time_t now_t = time(NULL);
struct tm timeout_tm, *now_tm;
/* localtime returns statically allocated pointer, so timeout_tm
has to be copied somewhere else */
memcpy(&timeout_tm, localtime(&timeout), sizeof(struct tm));
now_tm = localtime(&now_t);
/* form up timeout string depending whether it's today's date or not */
if (timeout_tm.tm_year != now_tm->tm_year ||
timeout_tm.tm_mon != now_tm->tm_mon ||
timeout_tm.tm_mday != now_tm->tm_mday) {
timeout_str = asctime(&timeout_tm);
timeout_str[strlen(timeout_str) - 1] = '\0'; /* remove tailing CR */
} else
asprintf(&timeout_str, "%.2d:%.2d:%.2d", timeout_tm.tm_hour,
timeout_tm.tm_min, timeout_tm.tm_sec);
d_printf("Key: %s\t Timeout: %s\t Value: %s %s\n", keystr,
timeout_str, datastr, timeout > now_t ? "": "(expired)");
}
static void delete_cache_entry(const char* keystr, const char* datastr, const time_t timeout)
static void delete_cache_entry(const char* keystr, const char* datastr,
const time_t timeout, void* dptr)
{
if (!gencache_del(keystr))
d_printf("Couldn't delete entry! key = %s", keystr);
@ -106,7 +125,7 @@ static time_t parse_timeout(const char* timeout_str)
/**
* Add an entry to the cache
* Add an entry to the cache. If it does exist, then set it.
*
* @param argv key, value and timeout are passed in command line
* @return 0 on success, otherwise failure
@ -132,12 +151,12 @@ static int net_cache_add(int argc, const char **argv)
return -1;
}
if (gencache_add(keystr, datastr, timeout)) {
if (gencache_set(keystr, datastr, timeout)) {
d_printf("New cache entry stored successfully.\n");
gencache_shutdown();
return 0;
}
}
d_printf("Entry couldn't be added. Perhaps there's already such a key.\n");
gencache_shutdown();
return -1;
@ -145,7 +164,8 @@ static int net_cache_add(int argc, const char **argv)
/**
* Set new value of an existing entry in the cache
* Set new value of an existing entry in the cache. Fail If the entry doesn't
* exist.
*
* @param argv key being searched and new value and timeout to set in the entry
* @return 0 on success, otherwise failure
@ -171,7 +191,7 @@ static int net_cache_set(int argc, const char **argv)
return -1;
}
if (gencache_set(keystr, datastr, timeout)) {
if (gencache_set_only(keystr, datastr, timeout)) {
d_printf("Cache entry set successfully.\n");
gencache_shutdown();
return 0;
@ -201,7 +221,7 @@ static int net_cache_del(int argc, const char **argv)
if(gencache_del(keystr)) {
d_printf("Entry deleted.\n");
return 0;
}
}
d_printf("Couldn't delete specified entry\n");
return -1;
@ -226,9 +246,9 @@ static int net_cache_get(int argc, const char **argv)
}
if (gencache_get(keystr, &valuestr, &timeout)) {
print_cache_entry(keystr, valuestr, timeout);
print_cache_entry(keystr, valuestr, timeout, NULL);
return 0;
}
}
d_printf("Failed to find entry\n");
return -1;
@ -251,7 +271,7 @@ static int net_cache_search(int argc, const char **argv)
}
pattern = argv[0];
gencache_iterate(print_cache_entry, pattern);
gencache_iterate(print_cache_entry, NULL, pattern);
return 0;
}
@ -265,7 +285,7 @@ static int net_cache_search(int argc, const char **argv)
static int net_cache_list(int argc, const char **argv)
{
const char* pattern = "*";
gencache_iterate(print_cache_entry, pattern);
gencache_iterate(print_cache_entry, NULL, pattern);
gencache_shutdown();
return 0;
}
@ -280,7 +300,7 @@ static int net_cache_list(int argc, const char **argv)
static int net_cache_flush(int argc, const char **argv)
{
const char* pattern = "*";
gencache_iterate(delete_cache_entry, pattern);
gencache_iterate(delete_cache_entry, NULL, pattern);
gencache_shutdown();
return 0;
}