diff options
Diffstat (limited to 'source3/namebrowse.c')
-rw-r--r-- | source3/namebrowse.c | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/source3/namebrowse.c b/source3/namebrowse.c new file mode 100644 index 0000000000..31ee9347ec --- /dev/null +++ b/source3/namebrowse.c @@ -0,0 +1,215 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + NBT netbios routines and daemon - version 2 + Copyright (C) Andrew Tridgell 1994-1995 + + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + Revision History: + + 14 jan 96: lkcl@pires.co.uk + added multiple workgroup domain master support + +*/ + +#include "includes.h" +#include "smb.h" + +extern int ClientNMB; + +extern int DEBUGLEVEL; + +/* this is our browse master/backup cache database */ +static struct browse_cache_record *browserlist = NULL; + + +/*************************************************************************** + add a browser into the list + **************************************************************************/ +static void add_browse_cache(struct browse_cache_record *b) +{ + struct browse_cache_record *b2; + + if (!browserlist) + { + browserlist = b; + b->prev = NULL; + b->next = NULL; + return; + } + + for (b2 = browserlist; b2->next; b2 = b2->next) ; + + b2->next = b; + b->next = NULL; + b->prev = b2; +} + + +/******************************************************************* + remove old browse entries + ******************************************************************/ +void expire_browse_cache(time_t t) +{ + struct browse_cache_record *b; + struct browse_cache_record *nextb; + + /* expire old entries in the serverlist */ + for (b = browserlist; b; b = nextb) + { + if (b->synced && b->sync_time < t) + { + DEBUG(3,("Removing dead cached browser %s\n",b->name)); + nextb = b->next; + + if (b->prev) b->prev->next = b->next; + if (b->next) b->next->prev = b->prev; + + if (browserlist == b) browserlist = b->next; + + free(b); + } + else + { + nextb = b->next; + } + } +} + + +/**************************************************************************** + add a browser entry + ****************************************************************************/ +struct browse_cache_record *add_browser_entry(char *name, int type, char *wg, + time_t ttl, struct in_addr ip) +{ + BOOL newentry=False; + + struct browse_cache_record *b; + + /* search for the entry: if it's already in the cache, update that entry */ + for (b = browserlist; b; b = b->next) + { + if (ip_equal(ip,b->ip) && strequal(b->group, wg)) break; + } + + if (b && b->synced) + { + /* entries get left in the cache for a while. this stops sync'ing too + often if the network is large */ + DEBUG(4, ("browser %s %s %s already sync'd at time %d\n", + b->name, b->group, inet_ntoa(b->ip), b->sync_time)); + return NULL; + } + + if (!b) + { + newentry = True; + b = (struct browse_cache_record *)malloc(sizeof(*b)); + + if (!b) return(NULL); + + bzero((char *)b,sizeof(*b)); + } + + /* update the entry */ + ttl = time(NULL)+ttl; + + StrnCpy(b->name ,name,sizeof(b->name )-1); + StrnCpy(b->group,wg ,sizeof(b->group)-1); + strupper(b->name); + strupper(b->group); + + b->ip = ip; + b->type = type; + + if (newentry || ttl < b->sync_time) + b->sync_time = ttl; + + if (newentry) + { + b->synced = False; + add_browse_cache(b); + + DEBUG(3,("Added cache entry %s %s(%2x) %s ttl %d\n", + wg, name, type, inet_ntoa(ip),ttl)); + } + else + { + DEBUG(3,("Updated cache entry %s %s(%2x) %s ttl %d\n", + wg, name, type, inet_ntoa(ip),ttl)); + } + + return(b); +} + + +/**************************************************************************** +find a server responsible for a workgroup, and sync browse lists +**************************************************************************/ +static void start_sync_browse_entry(struct browse_cache_record *b) +{ + struct subnet_record *d; + struct work_record *work; + + if (!(d = find_subnet(b->ip))) return; + + /* only sync if we are the master */ + if (AM_MASTER(work)) { + + /* first check whether the group we intend to sync with exists. if it + doesn't, the server must have died. o dear. */ + + /* see response_netbios_packet() or expire_netbios_response_entries() */ + queue_netbios_packet(d,ClientNMB,NMB_QUERY,NAME_QUERY_SYNC, + b->group,0x20,0,0, + False,False,b->ip); + } + + b->synced = True; +} + + +/**************************************************************************** + search through browser list for an entry to sync with + **************************************************************************/ +void do_browser_lists(void) +{ + struct browse_cache_record *b; + static time_t last = 0; + time_t t = time(NULL); + + if (t-last < 20) return; /* don't do too many of these at once! */ + /* XXXX equally this period should not be too long + the server may die in the intervening gap */ + + last = t; + + /* pick any entry in the list, preferably one whose time is up */ + for (b = browserlist; b && b->next; b = b->next) + { + if (b->sync_time < t && b->synced == False) break; + } + + if (b && !b->synced) + { + /* sync with the selected entry then remove some dead entries */ + start_sync_browse_entry(b); + expire_browse_cache(t - 60); + } + +} + |